go-zero 实战 - User Login

定义数据库表结构,并生成 mysql CRUD 代码

usermanage 下创建 model 文件夹。

bash 复制代码
$ mkdir -p model 
$ cd model

model 下新建 user.sql 文件并编写如下内容。

sql 复制代码
CREATE TABLE `user` (
                        `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户Id',
                        `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名称',
                        `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户密码',
                        `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户邮箱',
                        `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
                        `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                        PRIMARY KEY (`id`),
                        UNIQUE KEY `name_index` (`name`),
                        UNIQUE KEY `email_index` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

model 目录下执行如下命令生成 CRUD 代码:

bash 复制代码
$ goctl model mysql ddl --src user.sql --dir .

当你看到 Done. 输出则代表生成成功了,接下来我们来看一下生成的代码内容:

go 复制代码
➜  model:
# 列出当前目录下的文件  
$ ls  
user.sql usermodel.go usermodel_gen.go vars.go  
# 查看目录树  
$ tree  
.  
├── user.sql  
├── usermodel.go  // CRUD 代码
├── usermodel_gen.go  
└── vars.go // 定义常量和变量

在本机 mysql 中创建 foodguides 数据库,并新建 user 表。

执行如下 SQL 语句新增一条数据:

sql 复制代码
INSERT INTO `foodguides`.`user`(`id`, `name`, `password`, `email`) VALUES (1, 'RenPanPan', '809161', 'renpanpan1990@163.com');

api 代码调用 crud 代码

编辑 usermanage/api/etc 下的 user-api.yaml 文件,新增如下内容。

go 复制代码
DataSource: root:123456@tcp(127.0.0.1:9528)/foodguides?charset=utf8mb4&parseTime=True&loc=Local
AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
AccessExpire: 86400
Salt: ^&yh

Tips

如何配置 DataSource 请参考 github.com/go-sql-driv... 获取详情

编辑 usermanage/api/internal/config 下的 config.go 文件,新增 DataSource, AccessSecret, AccessExpire, Salt 四个变量:

go 复制代码
type Config struct {
    rest.RestConf
    DataSource   string
    AccessSecret string
    AccessExpire int64
    Salt         string
}

编辑 usermanage/api/internal/svc 下的 serviceContext.go 文件,新增 Model 变量 ,新增实例化代码:

go 复制代码
type ServiceContext struct {
    Config config.Config
    Model  model.UserModel
}

func NewServiceContext(c config.Config) *ServiceContext {
    return &ServiceContext{
       Config: c,
       Model:  model.NewUserModel(sqlx.NewMysql(c.DataSource)),
    }
}

编辑 usermanage/api/internal/logic 下的 loginlogic.go 文件, 删除 27~28 行代码,并新增如下代码逻辑:

go 复制代码
func (l *LoginLogic) Login(req *types.LoginRequest) (resp *types.LoginResponse, err error) {
    res, err := l.svcCtx.Model.FindOneByEmail(l.ctx, req.Email)
    if err == nil {
       if req.Password == res.Password {
          now := time.Now().Unix()
          accessExpire := l.svcCtx.Config.AccessExpire
          jwtToken, err := renpanpan.GetJwtToken(l.svcCtx.Config.AccessSecret, now, accessExpire, res.Id)
          if err != nil {
             return nil, err
          }
          token := types.JwtToken{
             AccessToken:  jwtToken,
             AccessExpire: now + accessExpire,
             RefreshAfter: now + accessExpire/2,
          }
          response := types.UserReply{
             Id:       res.Id,
             Username: res.Name,
             Email:    res.Email,
             JwtToken: token,
          }
          return &types.LoginResponse{UserReply: response}, nil
       } else {
          return nil, errors.New("密码错误")
       }
    }
    return nil, err
}

为了简单起见,在 loginlogic.go 中,我只是简单比较了数据库存储的密码是否和请求传的密码参数是否相等(真正的项目此处逻辑应该包含密码加密验证的等相关代码),当两者相等时,即认为用户登录成功,我们将为用户生成一个 token 返回给客户端。

修改 Response 返回格式

我希望客户端接口请求数据的返回格式是这样子的:

json 复制代码
{
    "code": 1,
    "msg": "",
    "data": {
        "id": 1,
        "username": "",
        "email": "renpanpan1990@163.com.com",
        "accessToken": "user-login-token",
        "accessExpire": 1611470394,
        "refreshAfter": 1611427194
    }
}

目前如果需要实现这种格式响应,有 2 种做法:

  1. 自定义响应格式
  2. 使用 go-zero 扩展包来实现

我们用做法 1 来演示一下,做法 2 可参考官方文档的演示实例 HTTP 扩展

foodguides 文件夹下 新增 renpanpan 文件夹,并创建 renpanpan.go 文件,新增如下代码

go 复制代码
package renpanpan

type HttpResponse struct {
    Code    int         `json:"code"`
    Message string      `json:"msg"`
    Data    interface{} `json:"result"`
}

func SuccessResponse(resData interface{}, message string) HttpResponse {
    return HttpResponse{Code: 1, Message: message, Data: resData}
}

func FailureResponse(resData interface{}, message string, code int) HttpResponse {
    return HttpResponse{Code: code, Message: message, Data: resData}
}

usermanage/api/internal/handler 下的 loginhandler.go 文件中,对 LoginHandler 方法做如下修改:

go 复制代码
func LoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
       var req types.LoginRequest
       if err := httpx.Parse(r, &req); err != nil {
          // httpx.ErrorCtx(r.Context(), w, err)
          httpx.OkJson(w, renpanpan.FailureResponse(nil, err.Error(), 1000))
          return
       }

       l := logic.NewLoginLogic(r.Context(), svcCtx)
       resp, err := l.Login(&req)
       if err != nil {
          // httpx.ErrorCtx(r.Context(), w, err)
          httpx.OkJson(w, renpanpan.FailureResponse(nil, err.Error(), 1000))
       } else {
          // httpx.OkJsonCtx(r.Context(), w, resp)
          httpx.OkJson(w, renpanpan.SuccessResponse(resp, "登录成功"))
       }
    }
}

启动服务

启动 user api 服务, 运行成功后,user api 则运行在本机的 8888 端口

bash 复制代码
➜  FoodGuides:
$ go run usermanage/api/user.go -f usermanage/api/etc/user-api.yaml
Starting server at 0.0.0.0:8888...

我们用 Postman 尝试请求登录接口,有如下截图的响应说明登录服务运行正常。

上一篇《go-zero 实战 - User API Gateway》

下一篇《go-zero 实战 - User Register》

相关推荐
程序员爱钓鱼4 小时前
Go字符串与数值转换核心库:strconv深度解析
后端·面试·go
我叫黑大帅5 小时前
Go 标准库 net/http 包都能干嘛?
后端·面试·go
江湖十年6 小时前
AI Agent 生态再添一员,Kratos 带着他的武器 Blades 走来了!
人工智能·后端·go
虚拟世界AI1 天前
Go数据分析模拟代码实战
go
江湖十年1 天前
MCP 官方 Go SDK v1.0.0 正式发布:Go 生态的模型上下文协议步入稳定时代
人工智能·后端·go
Coding君1 天前
每日一Go-39、Go 内存分配器深度拆解--Arena /Span / MSpan / 大对象 / 小对象
go
Bug养殖户1 天前
go语言http解析(二)路由树解析与注册
go
Assby2 天前
Java开发者学习Go语言:Go开发和Java开发的一些区别
后端·go
zach01272 天前
脑机接口技术的现象学重构:梅洛-庞蒂知觉理论在神经资本主义批判中的再语境化
go
July_102 天前
为什么你的 Go 协程(Gor...
go