注册请求/响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#api/v1/user/user.go
package user

import (
"gf_study/internal/model/entity"
"github.com/gogf/gf/v2/frame/g"
)


type RegisterReq struct {
g.Meta `path:"/user/register" method:"post" summary:"注册" tags:"User" `
Username string `v:"required|length:6,16#请输入账号|账号长度为:min到:max位" dc:"用户账号" json:"username"`
Password string `v:"required|length:6,16#请输入密码|密码长度为:min到:max位" dc:"用户密码" json:"password"`
Nickname string `v:"required|length:2,10#请输入昵称|昵称长度为:min到:max位" dc:"用户昵称" json:"nickname"`
}

type RegisterRes struct {
Info *entity.GfUsers
}

注册功能实现

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#internal/controller/v1/v1_user_register.go
package v1

import (
"golang.org/x/crypto/bcrypt"
"context"
"gf_study/internal/dao"
"gf_study/internal/model/do"
"gf_study/internal/model/entity"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"gf_study/api/v1/user"
)

func (c *ControllerUser) Register(ctx context.Context, req *user.RegisterReq) (res *user.RegisterRes, err error) {

// 检查用户是否已存在
isExist, err := dao.GfUsers.Ctx(ctx).Where("username", req.Username).Exist()
if err != nil {
return nil, gerror.WrapCode(gcode.CodeDbOperationError, err, "检查用户是否存在失败")
}
if isExist {
return nil, gerror.Newf("用户名 %s 已存在", req.Username)
}

// 密码加密处理(实际项目中必须添加)
encryptedPassword, err := encryptPassword(req.Password)
if err != nil {
return nil, gerror.WrapCode(gcode.CodeOperationFailed, err, "密码加密失败")
}

// 插入新用户
result, err := dao.GfUsers.Ctx(ctx).Insert(do.GfUsers{
Username: req.Username,
Nickname: req.Nickname,
Password: encryptedPassword, // 使用加密后的密码
})
if err != nil {
return nil, gerror.WrapCode(gcode.CodeDbOperationError, err, "用户注册失败")
}

// 获取插入的用户ID
userId, err := result.LastInsertId()
if err != nil {
return nil, gerror.WrapCode(gcode.CodeDbOperationError, err, "获取用户ID失败")
}

// 查询刚创建的用户信息
userEntity := &entity.GfUsers{
Id: uint(userId),
Username: req.Username,
Nickname: req.Nickname,
RegistTime: gtime.Now(),
LastLoginTime: gtime.Now(),
}


// 构建返回结果(注意:不要返回原始密码)
return &user.RegisterRes{
Info: userEntity,
}, nil
}

func encryptPassword(password string) (string, error) {
// 使用 bcrypt 加密密码
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedPassword), nil
}


安装bcrypt

1
go get golang.org/x/crypto/bcrypt

安装mysql驱动

1
2
3
4
5
6
7
8
9
10
11
12
13
$ go get -u github.com/gogf/gf/contrib/drivers/mysql/v2
go: downloading github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.1
go: added filippo.io/edwards25519 v1.1.0
go: added github.com/go-sql-driver/mysql v1.9.3
go: added github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.1
go: added github.com/olekukonko/cat v0.0.0-20250817074551-3280053e4e00
go: added github.com/olekukonko/errors v1.1.0
go: added github.com/olekukonko/ll v0.1.0
go: upgraded github.com/olekukonko/tablewriter v0.0.5 => v1.0.9

# main.go

import _ "github.com/gogf/gf/contrib/drivers/mysql/v2"

启动服务

1
2
3
4
5
6
$ go run main.go
# github.com/gogf/gf/v2/net/ghttp
C:\Users\JT\go\pkg\mod\github.com\gogf\gf\v2@v2.9.1\net\ghttp\ghttp_server.go:300:9: table.SetHeader undefined (type *tablewriter.Table has no field or method SetHeader)
C:\Users\JT\go\pkg\mod\github.com\gogf\gf\v2@v2.9.1\net\ghttp\ghttp_server.go:301:9: table.SetRowLine undefined (type *tablewriter.Table has no field or method SetRowLine)
C:\Users\JT\go\pkg\mod\github.com\gogf\gf\v2@v2.9.1\net\ghttp\ghttp_server.go:302:9: table.SetBorder undefined (type *tablewriter.Table has no field or method SetBorder)
C:\Users\JT\go\pkg\mod\github.com\gogf\gf\v2@v2.9.1\net\ghttp\ghttp_server.go:303:9: table.SetCenterSeparator undefined (type *tablewriter.Table has no field or method SetCenterSeparator)

修复依赖版本问题

1
2
$ go get github.com/olekukonko/[email protected]
go: downgraded github.com/olekukonko/tablewriter v1.0.9 => v0.0.5

测试

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
43
44
45
46
47
48
$ go run main.go
2025-08-29T16:32:54.176+08:00 [INFO] swagger ui is serving at address: http://127.0.0.1:8000/swagger/
2025-08-29T16:32:54.176+08:00 [INFO] pid[108732]: http server started listening on [:8000]
2025-08-29T16:32:54.176+08:00 [INFO] openapi specification is serving at address: http://127.0.0.1:8000/api.json

ADDRESS | METHOD | ROUTE | HANDLER | MIDDLEWARE
----------|--------|----------------|------------------------------------------------------------|----------------------------------
:8000 | ALL | /api.json | github.com/gogf/gf/v2/net/ghttp.(*Server).openapiSpec |
----------|--------|----------------|------------------------------------------------------------|----------------------------------
:8000 | ALL | /swagger/* | github.com/gogf/gf/v2/net/ghttp.(*Server).swaggerUI | HOOK_BEFORE_SERVE
----------|--------|----------------|------------------------------------------------------------|----------------------------------
:8000 | POST | /user/login | gf_study/internal/controller/v1.(*ControllerUser).Login | ghttp.MiddlewareHandlerResponse
----------|--------|----------------|------------------------------------------------------------|----------------------------------
:8000 | POST | /user/register | gf_study/internal/controller/v1.(*ControllerUser).Register | ghttp.MiddlewareHandlerResponse
----------|--------|----------------|------------------------------------------------------------|----------------------------------



# 测试注册
$ curl --location --request POST 'http://127.0.0.1:8000//user/register' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1:8000' \
--header 'Connection: keep-alive' \
--data-raw '{
"username": "cola316",
"nickname": "闽丽芳",
"password": "h7qUWLzgo4o1fJd"
}'
#输出
{
"code": 0,
"message": "OK",
"data": {
"Info": {
"id": 1,
"username": "cola316",
"nickname": "闽丽芳",
"password": "",
"status": 0,
"registTime": null,
"lastLoginTime": null,
"openId": ""
}
}
}

登录

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
43
44
45
46
#internal/controller/v1/v1_user_login.go
package v1

import (
"context"

"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"

"gf_study/api/v1/user"
"gf_study/internal/dao"
"gf_study/internal/model/do"
"gf_study/internal/model/entity"
)

func (c *ControllerUser) Login(ctx context.Context, req *user.LoginReq) (res *user.LoginRes, err error) {
var userData do.GfUsers // 改变变量名

//查看用户名是否注册
err = dao.GfUsers.Ctx(ctx).Where("username", req.Username).Scan(&userData)
if err != nil {
return nil, gerror.WrapCode(gcode.CodeDbOperationError, err, "用户信息有误或未注册")
}
if userData.Id == 0 {
return nil, gerror.New("用户名未注册")
}
//查看密码是否正确
checkPassword, err := EncryptPassword(req.Password)
if err != nil {
return nil, gerror.WrapCode(gcode.CodeInternalError, err, "密码加密失败")
}
if userData.Password != checkPassword {
return nil, gerror.New("密码错误")
}
userEntity := &entity.GfUsers{
Id: uint(userData.Id.(int)),
Username: req.Username,
Nickname: req.Nickname,
}

// 构建返回结果(注意:不要返回原始密码)
return &user.LoginRes{
Info: userEntity,
}, nil
}

登录测试

1
2
3
$ curl --location --request POST "http://127.0.0.1:8000//user/login" ^--header "User-Agent: Apifox/1.0.0 (https://apifox.com)" ^--header "Content-Type: application/json" ^--header "Accept: */*" ^--header "Host: 127.0.0.1:8000" ^--header "Connection: keep-alive" ^--data-raw "{    \"username\": \"cola316\",    \"password\": \"h7qUWLzgo4o1fJd\"}"

{"code":0,"message":"OK","data":{"info":{"id":1,"username":"cola316","nickname":"闽丽芳","password":"","status":0,"registTime":null,"lastLoginTime":null,"openId":""}}}