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》

相关推荐
蒙娜丽宁3 天前
Go语言错误处理详解
ios·golang·go·xcode·go1.19
qq_172805594 天前
GO Govaluate
开发语言·后端·golang·go
littleschemer4 天前
Go缓存系统
缓存·go·cache·bigcache
程序者王大川5 天前
【GO开发】MacOS上搭建GO的基础环境-Hello World
开发语言·后端·macos·golang·go
Grassto5 天前
Gitlab 中几种不同的认证机制(Access Tokens,SSH Keys,Deploy Tokens,Deploy Keys)
go·ssh·gitlab·ci
高兴的才哥6 天前
kubevpn 教程
kubernetes·go·开发工具·telepresence·bridge to k8s
少林码僧7 天前
sqlx1.3.4版本的问题
go
蒙娜丽宁7 天前
Go语言结构体和元组全面解析
开发语言·后端·golang·go
蒙娜丽宁7 天前
深入解析Go语言的类型方法、接口与反射
java·开发语言·golang·go
三里清风_7 天前
Docker概述
运维·docker·容器·go