定义数据库表结构,并生成 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 种做法:
- 自定义响应格式
- 使用
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
尝试请求登录接口,有如下截图的响应说明登录服务运行正常。