Go: IM系统基于xorm实现简单的注册和登录功能

概述

  • IM系统允许用户通过网络实时发送和接收消息
  • 它通常包括用户注册、登录、消息发送、接收、存储以及用户状态管理等核心功能
  • 其中,登录功能是用户访问IM服务的第一步,它确保了系统的安全性和用户数据的准确性

基于MVC的目录设计

im-project
├── go.mod
├── main.go          主程序
├── model            模型层
│     └── user.go
├── views            模板层
│     └── user
│           ├── register.html
│           └── login.html
├── ctrl             控制器层
│     └── user.go
├── service          服务包
│     ├── init.go
│     └── user.go
├── utils            工具包
│     ├── md5.go
│     └── resp.go

主程序

在 main.go 注册模板,设置静态服务,绑定路由和控制器

package mainimport ("net/http""im-project/ctrl""log""html/template""fmt"_ "github.com/go-sql-driver/mysql"
)// 注册模板
func RegisterTemplate() {//全局扫描模板GlobTemplete := template.New("root")GlobTemplete, err := GlobTemplete.ParseGlob("view/**/*")if err!=nil {//打印错误信息//退出系统log.Fatal(err)}//分别对每一个模板进行注册for _,tpl := range  GlobTemplete.Templates(){patern := tpl.Name()http.HandleFunc(patern,func(w http.ResponseWriter,r *http.Request) {GlobTemplete.ExecuteTemplate(w,patern,nil)})// fmt.Println("register=>"+patern)}
}// 这里注册视图,仅供参考
func RegisterView(){//一次解析出全部模板tpl,err := template.ParseGlob("view/**/*")if nil!=err{log.Fatal(err)}//通过for循环做好映射for _,v := range tpl.Templates(){tplname := v.Name();http.HandleFunc(tplname, func(w http.ResponseWriter,request *http.Request) {// fmt.Println("parse     "+v.Name() + "==" + tplname)err := tpl.ExecuteTemplate(w,tplname,nil)if err!=nil {log.Fatal(err.Error())}})}
}func main() {// 1. 路由绑定请求和控制器处理函数http.HandleFunc("/user/login", ctrl.UserLogin)http.HandleFunc("/user/register", ctrl.UserRegister)// 2. 指定目录的静态文件http.Handle("/asset/",http.FileServer(http.Dir(".")))http.Handle("/mnt/",http.FileServer(http.Dir(".")))// 3. 注册模板RegisterView()// 4. 运行http.ListenAndServe(":8080",nil)
}

模型层

定义user实体

package modelimport "time"const (SEX_WOMEN = "W"SEX_MEN = "M"SEX_UNKNOW = "U"
)type User struct {//用户IDId         int64     `xorm:"pk autoincr bigint(20)" form:"id" json:"id"`Mobile   string 		`xorm:"varchar(20)" form:"mobile" json:"mobile"`Passwd       string	`xorm:"varchar(40)" form:"passwd" json:"-"`   // 什么角色Avatar	   string 		`xorm:"varchar(150)" form:"avatar" json:"avatar"`Sex        string	`xorm:"varchar(2)" form:"sex" json:"sex"`   // 什么角色Nickname    string	`xorm:"varchar(20)" form:"nickname" json:"nickname"`   // 什么角色//加盐随机字符串6Salt       string	`xorm:"varchar(10)" form:"salt" json:"-"`   // 什么角色Online     int	`xorm:"int(10)" form:"online" json:"online"`   //是否在线//前端鉴权因子,Token      string	`xorm:"varchar(40)" form:"token" json:"token"`   // 什么角色Memo      string	`xorm:"varchar(140)" form:"memo" json:"memo"`   // 什么角色Createat   time.Time	`xorm:"datetime" form:"createat" json:"createat"`   // 什么角色
}

服务包

init.go 用于初始化数据库相关操作

package serviceimport ("github.com/go-xorm/xorm""log""fmt""errors""im-project/model"
)var DbEngin *xorm.Enginefunc  init()  {drivename :="mysql"DsName := "root:root@(192.168.0.102:3306)/chat?charset=utf8"err := errors.New("")DbEngin,err = xorm.NewEngine(drivename,DsName)if nil!=err && ""!=err.Error() {log.Fatal(err.Error())}//是否显示SQL语句DbEngin.ShowSQL(false)//数据库最大打开的连接数DbEngin.SetMaxOpenConns(2)//自动UserDbEngin.Sync2(new(model.User))// DbEngin = dbenginfmt.Println("init data base ok")
}

user.go 登录时用到的封装函数

package serviceimport ("im-project/model""errors""fmt""math/rand""im-project/util""time"_ "github.com/go-sql-driver/mysql"
)type UserService struct {}//注册函数
func (s *UserService)Register(mobile,//手机plainpwd,//明文密码nickname,//昵称avatar,sex string)(user model.User,err error) {//检测手机号码是否存在,tmp := model.User{}_,err=DbEngin.Where("mobile=? ",mobile).Get(&tmp)if err!=nil{return tmp,err}//如果存在则返回提示已经注册if tmp.Id>0{return tmp,errors.New("该手机号已经注册")}//否则拼接插入数据tmp.Mobile = mobiletmp.Avatar = avatartmp.Nickname = nicknametmp.Sex = sextmp.Salt = fmt.Sprintf("%06d",rand.Int31n(10000))tmp.Passwd = util.MakePasswd(plainpwd,tmp.Salt)tmp.Createat = time.Now()//token 可以是一个随机数tmp.Token = fmt.Sprintf("%08d",rand.Int31())//passwd =//md5 加密//返回新用户信息//插入 InserOne_,err = DbEngin.InsertOne(&tmp)//前端恶意插入特殊字符//数据库连接操作失败return tmp,err
}//登录函数
func (s *UserService)Login(mobile, plainpwd string )(user model.User,err error) {//首先通过手机号查询用户tmp := model.User{}DbEngin.Where("mobile = ?",mobile).Get(&tmp)// 如果没有找到if tmp.Id==0 {return tmp,errors.New("该用户不存在")}// 查询到了比对密码if !util.ValidatePasswd(plainpwd,tmp.Salt,tmp.Passwd){return tmp,errors.New("密码不正确")}// 刷新token, 安全str := fmt.Sprintf("%d",time.Now().Unix())token := util.MD5Encode(str)tmp.Token = token//返回数据DbEngin.ID(tmp.Id).Cols("token").Update(&tmp)return tmp,nil
}//查找某个用户
func (s *UserService)Find(userId int64 )(user model.User) {//首先通过手机号查询用户tmp :=model.User{}DbEngin.ID(userId).Get(&tmp)return tmp
}

工具包

util/md5.go

package utilimport ("crypto/md5""encoding/hex""strings"
)
//小写的
func Md5Encode(data string) string{h := md5.New()h.Write([]byte(data)) // 需要加密的字符串为 123456cipherStr := h.Sum(nil)return  hex.EncodeToString(cipherStr)
}
//大写
func MD5Encode(data string) string{return strings.ToUpper(Md5Encode(data))
}func ValidatePasswd(plainpwd,salt,passwd string) bool{return Md5Encode(plainpwd+salt)==passwd
}
func MakePasswd(plainpwd,salt string) string{return Md5Encode(plainpwd+salt)
}

util/resp.go

package utilimport ("net/http""encoding/json""log"
)type H struct {Code int `json:"code"`Msg  string `json:"msg"`Data interface{} `json:"data,omitempty"`Rows interface{} `json:"rows,omitempty"`Total interface{} `json:"total,omitempty"`
}
//
func RespFail(w http.ResponseWriter,msg string){Resp(w,-1,nil,msg)
}
func RespOk(w http.ResponseWriter,data interface{},msg string){Resp(w,0,data,msg)
}
func RespOkList(w http.ResponseWriter,lists interface{},total interface{}){//分页数目,RespList(w,0,lists,total)
}
func Resp(w http.ResponseWriter,code int,data interface{},msg string)  {w.Header().Set("Content-Type","application/json")//设置200状态w.WriteHeader(http.StatusOK)//输出//定义一个结构体h := H{Code:code,Msg:msg,Data:data,}//将结构体转化成JSOn字符串ret,err := json.Marshal(h)if err!=nil{log.Println(err.Error())}//输出w.Write(ret)
}
func RespList(w http.ResponseWriter,code int,data interface{},total interface{})  {w.Header().Set("Content-Type","application/json")//设置200状态w.WriteHeader(http.StatusOK)//输出//定义一个结构体//满足某一条件的全部记录数目//测试 100//20h := H{Code:code,Rows:data,Total:total,}//将结构体转化成JSOn字符串ret,err := json.Marshal(h)if err!=nil{log.Println(err.Error())}//输出w.Write(ret)
}

控制器

ctrl/user.go 中用于处理登录时的接口响应

package ctrlimport ("net/http""fmt""math/rand""im-project/util""im-project/service""im-project/model"
)func UserLogin(writer http.ResponseWriter, request *http.Request) {// 数据库操作// 逻辑处理// restapi json/xml返回// 1.获取前端传递的参数// mobile,passwd// 解析参数// 如何获得参数// 解析参数request.ParseForm()mobile := request.PostForm.Get("mobile")passwd := request.PostForm.Get("passwd")//模拟user,err := userService.Login(mobile,passwd)if err!=nil {util.RespFail(writer,err.Error())} else {util.RespOk(writer,user,"")}
}var userService service.UserServicefunc UserRegister(writer http.ResponseWriter, request *http.Request) {request.ParseForm()mobile := request.PostForm.Get("mobile")plainpwd := request.PostForm.Get("passwd")nickname := fmt.Sprintf("user%06d",rand.Int31())avatar := ""sex := model.SEX_UNKNOWuser,err := userService.Register(mobile, plainpwd, nickname, avatar, sex)if err != nil {util.RespFail(writer,err.Error())} else {util.RespOk(writer,user,"")}
}

模板层

view/user/login.html 登录页面

{{define  "/user/login.shtml"}}
<!DOCTYPE html>
<html>
<head>
{{template "/chat/head.shtml"}}
</head>
<body><header class="mui-bar mui-bar-nav"><h1 class="mui-title">登录</h1>
</header>
<div class="mui-content" id="pageapp"><form id='login-form' class="mui-input-group"><div class="mui-input-row"><label>账号</label><input v-model="user.mobile" placeholder="请输入手机号" type="text" class="mui-input-clear mui-input" ></div><div class="mui-input-row"><label>密码</label><input v-model="user.passwd" placeholder="请输入密码"  type="password" class="mui-input-clear mui-input" ></div></form><div class="mui-content-padded"><button @click="login"  type="button"  class="mui-btn mui-btn-block mui-btn-primary">登录</button><div class="link-area"><a id='reg' href="register.shtml">注册账号</a> <span class="spliter">|</span> <a  id='forgetPassword'>忘记密码</a></div></div><div class="mui-content-padded oauth-area"></div>
</div>
</body>
</html>
<script>var app = new Vue({el:"#pageapp",data:function(){return {user:{mobile:"",passwd:""}}},methods:{login:function(){//检测手机号是否正确//检测密码是否为空//网络请求//封装了promisutil.post("user/login",this.user).then(res=>{console.log(res)if(res.code!=0) {mui.toast(res.msg)return}var url = "/chat/index.shtml?id=" + res.data.id + "&token=" + res.data.tokenuserInfo(res.data)userId(res.data.id)location.href = url})},}})
</script>
{{end}}

view/user/register.html 注册页面

{{define  "/user/register.shtml"}}
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no"><title>IM解决方案</title><link rel="stylesheet" href="/asset/plugins/mui/css/mui.css" /><link rel="stylesheet" href="/asset/css/login.css" /><script src="/asset/plugins/mui/js/mui.js" ></script><script src="/asset/js/vue.min.js" ></script><script src="/asset/js/util.js" ></script>
</head>
<body><header class="mui-bar mui-bar-nav"><h1 class="mui-title">登录</h1>
</header>
<div class="mui-content" id="pageapp"><form id='login-form' class="mui-input-group"><div class="mui-input-row"><label>账号</label><input v-model="user.mobile" placeholder="请输入手机号" type="text" class="mui-input-clear mui-input" ></div><div class="mui-input-row"><label>密码</label><input v-model="user.passwd" placeholder="请输入密码"  type="password" class="mui-input-clear mui-input" ></div></form><div class="mui-content-padded"><button @click="login"  type="button"  class="mui-btn mui-btn-block mui-btn-primary">登录</button><div class="link-area"><a id='reg' href="register.shtml">注册账号</a> <span class="spliter">|</span> <a  id='forgetPassword'>忘记密码</a></div></div><div class="mui-content-padded oauth-area"></div>
</div>
</body>
</html>
<script>var app = new Vue({el:"#pageapp",data:function(){return {user:{mobile:"",passwd:""}}},methods:{login:function(){//检测手机号是否正确console.log("login")//检测密码是否为空//网络请求//封装了promisutil.post("user/login",this.user).then(res=>{// console.log(res)if(res.code!=0){mui.toast(res.msg)return}location.replace("//127.0.0.1/index.shtml")mui.toast("登录成功,即将跳转")})},}})
</script>
{{end}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/873221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编程中的智慧之设计模式三

深入探索设计模式&#xff1a;实际应用和优化策略 在前两篇文章中&#xff0c;我们详细探讨了创建型模式、结构型模式、行为模式和架构模式的基本概念及其在Java中的实现。在本文中&#xff0c;我们将进一步探讨如何在实际项目中应用和优化这些模式&#xff0c;尤其是如何在大…

海豚调度器(DolphinScheduler)集群搭建详细笔记

海豚调度器集群搭建笔记 1.DolphinScheduler Cluster部署1.1 集群部署规划1.2 集群准备工作1.3 初始化数据库1.4 修改安装环境配置1.5 安装DolphinScheduler1.6 启停命令1.7 登录 DolphinScheduler UI 1.DolphinScheduler Cluster部署 分布式去中心化易扩展的工作流任务调度系…

CTF-Web习题:[HFCTF2021]Unsetme

题目链接&#xff1a;[HFCTF2021]Unsetme 解题思路 打开靶场发现是一段PHP源码 做一下代码审阅&#xff1a; <?php// Kickstart the framework $f3require(lib/base.php);//引入f3框架源码$f3->set(DEBUG,1);//f3对象设置DEBUG属性 if ((float)PCRE_VERSION<8.0)…

腾讯元宝上线“3D角色梦工厂”:快速生成专属3D角色!

7月16日&#xff0c;腾讯旗下大模型应用“腾讯元宝”上线“3D角色梦工厂”&#xff0c;允许用户通过上传一张五官清晰的正面头像&#xff0c;并选择不同的角色模板&#xff0c;迅速生成个人3D角色&#xff01; 技术特点 “3D角色梦工厂”将大模型生成技术与3D应用相结合&#…

JavaDS —— 二叉树

树的基本概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看 起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 树形结构中&#xff0c;子树之间不能有…

Pandas库学习之DataFrame.drop()函数

Pandas库学习之DataFrame.drop()函数 一、简介 DataFrame.drop 是 Pandas 库中一个非常实用的函数&#xff0c;用于删除 DataFrame 中的行或列。通过指定列名或行索引&#xff0c;可以灵活地从数据集中移除不需要的数据。这对于数据清洗和预处理非常有用。 二、语法和参数 D…

AWS IoT Core 优化分析:提升性能、安全性和成本效益

1. 引言 在当今快速发展的物联网(IoT)领域,AWS IoT Core已成为许多企业首选的IoT平台。然而,随着设备数量的增加和数据流量的激增,优化AWS IoT Core的性能、安全性和成本效益变得至关重要。本文将深入探讨如何通过数据分析来优化AWS IoT Core的各个方面,帮助您充分发挥这个强大…

02线性表 - 链表

这里是只讲干货不讲废话的炽念&#xff0c;这个系列的文章是为了我自己以后复习数据结构而写&#xff0c;所以可能会用一种我自己能够听懂的方式来描述&#xff0c;不会像书本上那么枯燥和无聊&#xff0c;且全系列的代码均是可运行的代码&#xff0c;关键地方会给出注释^_^ 全…

十六、【机器学习】【监督学习】- 支持向量回归 (SVR)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

Docker Ubuntu Milvus 2.4 windows 详细安装攻略

目录 背景 安装Docker Destop 下载docker 破解之法 启动 docker destop OS镜像 前置条件 dism 启动WSL服务 命令

MQTT 固定报头中的剩余长度介绍

MQTT协议中的剩余长度&#xff08;Remaining Length&#xff09;是一个重要的概念&#xff0c;它表示当前报文剩余部分的字节数&#xff0c;包括可变报头和负载的数据&#xff0c;但不包括用于编码剩余长度字段本身的字节数。以下是对MQTT剩余长度的详细说明&#xff1a; 一、…

python中excel的读取和写入

python中对于excel文件数据的读取和写入&#xff0c;主要有两种方法&#xff0c;一种是通过pandas库&#xff0c;一种是通过openpyxl库。在实际过程中&#xff0c;因为pandas库对单元格的定位和访问比较方便&#xff0c;openpyxl可以对单个单元格进行写入&#xff0c;而pandas库…

GaussDB常见调优指南

文章目录 GaussDB常见调优指南一. Analyze 统计信息解析二. Explain 分布式计划解析三. 性能调优总体策略详解四. 性能调优之坏味道 SQL 识别五. 性能调优之好味道表定义六. 性能调优之 SQL 改写七. 性能调优之路径干预八. 性能调优之 Plan hint 运用九. 性能调优之 GUC 参数调…

C学习(数据结构)-->单链表习题

目录 一、环形链表 题一&#xff1a;环形链表 思路&#xff1a; 思考一&#xff1a;为什么&#xff1f; 思考二&#xff1a;快指针一次走3步、4步、......n步&#xff0c;能否相遇 step1&#xff1a; step2&#xff1a; 代码&#xff1a; 题二&#xff1a; 环形链表 I…

SAE J1939协议入门(一)

一、SAE J1939是什么 SAE J1939&#xff08;以下简称J1939&#xff09;是由汽车工程师协会&#xff08;SAE &#xff09;定义的标准&#xff0c;专门用于提供微处理器系统之间的串行数据通信。虽然CAN存在并且被广泛用于小型车辆&#xff0c;但J1939被设计为大型车辆复杂网络的…

antd drawer extra中按钮点击事件获取子组件的数据

在Ant Design的Drawer组件中&#xff0c;需要在extra区域的按钮点击事件中获取子组件的数据&#xff0c;可以通过以下步骤实现&#xff1a; 使用useRef钩子在父组件中创建一个ref引用子组件。 在子组件中使用useImperativeHandle或forwardRef来暴露一个方法给父组件调用。 在ex…

android mm m mmm 区别

Android开发中的m, mm, mmm命令用于编译源代码&#xff0c;‌它们的主要区别在于编译的范围和目标。‌ m命令&#xff1a;‌用于从Android源码的根目录开始编译所有的模块。‌这个命令会编译整个Android源代码树&#xff0c;‌确保所有必要的模块都被编译12。‌ mm命令&#x…

如何用Java实现运营商三要素接口调用

今天给大家案例运营商三要素接口&#xff0c;该接口实用性极强&#xff01;建议大家点赞收藏&#xff0c;如果问题可随时评论区留言交流&#xff01; 一、什么是运营商三要素&#xff1f; 运营商三要素通常指的是手机号码、用户姓名和身份证号码。 二、运营商三要素应用场景…

升级TrinityCore 服务器硬件

升级服务器 原服务器&#xff1a;Ubuntu装VirtualBox装Ubuntu虚拟机 原配置&#xff1a;内存1756MB 内核4 外接硬盘 ip 192.168.0.12 升级服务器&#xff1a;FreeBSD装bhyve装Ubuntu虚拟机 新配置&#xff1a;内存3072MB 内核4 ssd硬盘 ip 192.168.1.12 除了ssh&#…

WPF之URI的使用

pack://application:, pack://application:, 是一个在 WPF (Windows Presentation Foundation) 应用程序中用于指定资源位置的 URI (统一资源标识符) 方案的特定格式。这个格式用于访问嵌入在应用程序程序集&#xff08;assemblies&#xff09;中的资源&#xff0c;如图像、XA…