注册请求/响应
#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
}
注册功能实现
#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
go get golang.org/x/crypto/bcrypt
安装mysql驱动
$ 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"
启动服务
$ 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)
修复依赖版本问题
$ go get github.com/olekukonko/[email protected]
go: downgraded github.com/olekukonko/tablewriter v1.0.9 => v0.0.5
测试
$ 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": ""
}
}
}
登录
#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
}
登录测试
$ 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":""}}}