12.注册模块
# 01.user表结构设计
# 1.1 创建数据库
mysql> create database gin_bbs charset utf8;
1
# 1.2 创建user表SQL
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`username` varchar(64) COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(64) COLLATE utf8mb4_general_ci NOT NULL,
`email` varchar(64) COLLATE utf8mb4_general_ci,
`gender` tinyint(4) NOT NULL DEFAULT '0',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`) USING BTREE,
UNIQUE KEY `idx_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 1.3 models/user.go
package models
type User struct {
UserID int64 `db:"user_id"`
Username string `db:"username"`
Password string `db:"password"`
Token string
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 1.4 dao/mysql/error_code.go
package mysql
import "errors"
var (
ErrorUserExist = errors.New("用户已存在")
ErrorUserNotExist = errors.New("用户不存在")
ErrorInvalidPassword = errors.New("用户名或密码错误")
ErrorInvalidID = errors.New("无效的ID")
)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 02.注册CLD
# 2.1 routes/routes.go 处理路由 C
package routes
import (
"gin_bbs/controllers"
"gin_bbs/logger"
"gin_bbs/settings"
"github.com/gin-gonic/gin"
)
func Setup(mode string) *gin.Engine {
if mode == gin.ReleaseMode {
gin.SetMode(gin.ReleaseMode)
}
r := gin.New()
r.Use(logger.GinLogger(), logger.GinRecovery(true))
r.GET("/version", func(c *gin.Context) {
//c.String(http.StatusOK, settings.Conf.Version)
// 返回响应
controller.ResponseSuccess(c, settings.Conf.Version)
})
v1 := r.Group("/api/v1")
// 注册
v1.POST("/signup", controller.SignUpHandler)
return r
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 2.2 controller/user.go 参数校验 C
package controller
import (
"errors"
"gin_bbs/dao/mysql"
"gin_bbs/logic"
"gin_bbs/models"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"go.uber.org/zap"
)
// SignUpHandler 处理注册请求的函数
func SignUpHandler(c *gin.Context) {
// 1. 获取参数和参数校验
p := new(models.ParamSignUp)
if err := c.ShouldBindJSON(p); err != nil {
// 请求参数有误,直接返回响应
zap.L().Error("SignUp with invalid param", zap.Error(err))
// 判断err是不是validator.ValidationErrors 类型
errs, ok := err.(validator.ValidationErrors)
if !ok {
ResponseError(c, CodeInvalidParam)
return
}
ResponseErrorWithMsg(c, CodeInvalidParam, removeTopStruct(errs.Translate(trans)))
return
}
// 2. 业务处理
if err := logic.SignUp(p); err != nil {
zap.L().Error("logic.SignUp failed", zap.Error(err))
if errors.Is(err, mysql.ErrorUserExist) {
ResponseError(c, CodeUserExist)
return
}
ResponseError(c, CodeServerBusy)
return
}
// 3. 返回响应
ResponseSuccess(c, nil)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 2.3 models/params.go 校验结构体 C
package models
// ParamSignUp 注册请求参数
type ParamSignUp struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
RePassword string `json:"confirm_password" binding:"required,eqfield=Password"`
//RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2.4 logic/user.go 业务逻辑 L
package logic
import (
"gin_bbs/dao/mysql"
"gin_bbs/models"
"gin_bbs/pkg/snowflake"
)
// 存放业务逻辑的代码
func SignUp(p *models.ParamSignUp) (err error) {
// 1.判断用户存不存在
if err := mysql.CheckUserExist(p.Username); err != nil {
return err
}
// 2.生成UID
userID := snowflake.GenID()
// 构造一个User实例
user := &models.User{
UserID: userID,
Username: p.Username,
Password: p.Password,
}
// 3.保存进数据库
return mysql.InsertUser(user)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 2.5 models/user.go 表模型 D
package models
type User struct {
UserID int64 `db:"user_id"`
Username string `db:"username"`
Password string `db:"password"`
Token string
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 2.6 dao/mysql/user.go 数据库 D
package mysql
import (
"crypto/md5"
"encoding/hex"
"gin_bbs/models"
)
// 把每一步数据库操作封装成函数
// 待logic层根据业务需求调用
const secret = "v5blog.cn" // 用户注册,密码加盐
// CheckUserExist 检查指定用户名的用户是否存在
func CheckUserExist(username string) (err error) {
sqlStr := `select count(user_id) from user where username = ?`
var count int64
if err := db.Get(&count, sqlStr, username); err != nil {
return err
}
if count > 0 {
return ErrorUserExist
}
return
}
// InsertUser 向数据库中插入一条新的用户记录
func InsertUser(user *models.User) (err error) {
// 对密码进行加密
user.Password = encryptPassword(user.Password)
// 执行SQL语句入库
sqlStr := `insert into user(user_id, username, password) values(?,?,?)`
_, err = db.Exec(sqlStr, user.UserID, user.Username, user.Password)
return
}
// encryptPassword 密码加密
func encryptPassword(oPassword string) string {
h := md5.New()
h.Write([]byte(secret))
return hex.EncodeToString(h.Sum([]byte(oPassword)))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 03.测试注册接口
# 3.1 注册参数不全
- http://127.0.0.1:8080/api/v1/signup
{
"username":"lisi"
}
1
2
3
2
3
# 3.2 注册成功
- http://127.0.0.1:8080/api/v1/signup
{
"username":"lisi",
"password": "123456",
"confirm_password": "123456"
}
1
2
3
4
5
2
3
4
5
上次更新: 2024/3/13 15:35:10