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》

相关推荐
郝同学的测开笔记1 天前
云原生探索系列(十二):Go 语言接口详解
后端·云原生·go
一点一木2 天前
WebAssembly:Go 如何优化前端性能
前端·go·webassembly
千羽的编程时光3 天前
【CloudWeGo】字节跳动 Golang 微服务框架 Hertz 集成 Gorm-Gen 实战
go
27669582924 天前
阿里1688 阿里滑块 231滑块 x5sec分析
java·python·go·验证码·1688·阿里滑块·231滑块
Moment5 天前
在 NodeJs 中如何通过子进程与 Golang 进行 IPC 通信 🙄🙄🙄
前端·后端·go
唐僧洗头爱飘柔95276 天前
(Go基础)变量与常量?字面量与变量的较量!
开发语言·后端·golang·go·go语言初上手
黑心萝卜三条杠6 天前
【Go语言】深入理解Go语言:并发、内存管理和垃圾回收
google·程序员·go
不喝水的鱼儿6 天前
【LuatOS】基于WebSocket的同步请求框架
网络·websocket·网络协议·go·luatos·lua5.4
微刻时光6 天前
程序员开发速查表
java·开发语言·python·docker·go·php·编程语言
lidenger7 天前
服务认证-来者何人
后端·go