本章节内容均在
task
目录下完成
准备模块框架
这里我们先把所有接口的框架都生成好, 基本步骤都和
user
模块一样
生成 api 代码
在 cmd/api
目录下新建一个 desc
目录编写 api 文件
syntax = "v1"
info(
title: "Task API"
desc: "API for task"
author: "GuoChenxu"
email: "2269409349@qq.com"
version: "1.0"
)
// task_create
type (
CreateReq {
Title string `form:"title"`
Content string `form:"content"`
Status string `form:"status"`
}
CreateResp {
Status int `json:"status"`
Data string `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
type Task {
Id int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
View int `json:"view"`
Status int `json:"status"`
CreateAt int64 `json:"create_at"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
}
// task_list
type (
ListReq {
Limit string `form:"limit"`
Start string `form:"start"`
}
Data {
Task []Task `json:"item"`
Total int `json:"total"`
}
ListResp {
Status int `json:"status"`
Data Data `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
// task_show
type (
ShowReq {
Id int64 `form:"id"`
}
ShowResp {
Status int `json:"status"`
Data Task `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
// task_update
type (
UpdateReq {
Id string `form:"id"`
Title string `form:"title"`
Content string `form:"content"`
Status string `form:"status"`
}
UpdateResp {
Status int `json:"status"`
Data string `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
// task_search
type (
SearchReq {
Info string `form:"info"`
}
SearchResp {
Status int `json:"status"`
Data Data `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
// task_delete
type (
DeleteReq {
Id string `form:"id"`
}
DeleteResp {
Status int `json:"status"`
Data string `json:"data"`
Message string `json:"msg"`
Error string `json:"error"`
}
)
@server(
prefix: api/v1
jwt: JwtAuth
)
service user {
@doc "task_create"
@handler TaskCreate
post /task_create (CreateReq) returns (CreateResp)
@doc "task_list"
@handler TaskList
get /task_list (ListReq) returns (ListResp)
@doc "task_show"
@handler TaskShow
get /task_show (ShowReq) returns (ShowResp)
@doc "task_update"
@handler TaskUpdate
post /task_update (UpdateReq) returns (UpdateResp)
@doc "task_search"
@handler TaskSearch
post /task_search (SearchReq) returns (SearchResp)
@doc "task_delete"
@handler TaskDelete
post /task_delete (DeleteReq) returns (DeleteResp)
}
然后在 api
目录下生成代码文件
goctl api go --api .\desc\task.api --dir .\ --style=go_zero
生成 rpc 代码
同样地, 在 cmd/rpc
目录下新建 desc
目录, 编写 proto 文件
syntax = "proto3";
package pb;
option go_package = "./pb";
// 定义消息类型
message CreateReq {
int64 Uid = 1;
string Title = 2;
string Content = 3;
int32 Status = 4;
}
message CreateResp{
int32 Status = 1;
string Data = 2;
string Message = 3;
string Error = 4;
}
message Task{
int64 Id = 1;
string Title = 2;
string Content = 3;
int64 View = 4;
int32 Status = 5;
int64 CreateAt = 6;
int64 StartTime = 7;
int64 EndTime = 8;
}
message Data{
repeated Task Task = 1;
int64 Total = 2;
}
message ListReq{
int64 Uid = 1;
int64 Limit = 2;
int64 start = 3;
}
message ListResp{
int32 Status = 1;
Data Data = 2;
string Message = 3;
string Error = 4;
}
message ShowReq{
int64 Id = 1;
int64 Uid = 2;
}
message ShowResp{
int32 status = 1;
Task Task = 2;
string Message = 3;
string Error = 4;
}
message UpdateReq{
string Id = 1;
int64 Uid = 2;
string Title = 3;
string Content = 4;
int32 Status = 5;
}
message UpdateResp{
int32 Status = 1;
string Data = 2;
string Message = 3;
string Error = 4;
}
message SearchReq{
int64 Uid = 1;
string Info = 2;
}
message SearchResp{
int32 Status = 1;
Data Data = 2;
string Message = 3;
string Error = 4;
}
message DeleteReq{
int64 Uid = 1;
string Id = 2;
}
message DeleteResp{
int32 Status = 1;
string Data = 2;
string Message = 3;
string Error = 4;
}
// 定义服务
service taskrpc {
rpc CreateTask(CreateReq) returns(CreateResp);
rpc ListTask(ListReq) returns (ListResp);
rpc ShowTask(ShowReq) returns (ShowResp);
rpc UpdateTask(UpdateReq) returns (UpdateResp);
rpc SearchTask(SearchReq) returns (SearchResp);
rpc DeleteTask(DeleteReq) returns (DeleteResp);
}
然后在 rpc
目录下生成代码
goctl rpc protoc .\desc\task.proto --go_out=.\ --go-grpc_out=.\ --zrpc_out=.\ --style=go_zero
生成 model 代码
在 model
目录下我们根据数据库中的 task
表生成代码文件, 和
goctl model mysql datasource -url="root:101325@tcp(127.0.0.1:3306)/gtodolist" -table="task" --dir="./" --home="../template/gorm-gozero/1.4.2" --style=go_zero --cache=true
到目前为止我们 task
模块的代码就全部生成好了
修改配置文件
接下来我们要修改项目的配置文件
api
修改 etc/task.yaml
配置文件
Name: task
Host: 0.0.0.0
Port: 22302
Log:
Encoding: plain
TaskRpcConfig:
Etcd:
Hosts:
- 127.0.0.1:2379
Key: task.rpc
# jwt验证
JwtAuth:
AccessSecret: gtodolist
AccessExpire: 31536000
internal/config/config.go
type Config struct {
rest.RestConf
JwtAuth struct {
AccessSecret string
AccessExpire int64
}
TaskRpcConfig zrpc.RpcClientConf
}
internal/svc/service_context.go
type ServiceContext struct {
Config config.Config
TaskRpcClient taskrpc.Taskrpc
}
func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
TaskRpcClient: taskrpc.NewTaskrpc(zrpc.MustNewClient(c.TaskRpcConfig)),
}
}
rpc
同样是 etc/task.yaml
文件
Name: task.rpc
ListenOn: 0.0.0.0:22352
Etcd:
Hosts:
- 0.0.0.0:2379
Key: task.rpc
# 日志
Log:
Encoding: plain
# jwt验证
JwtAuth:
AccessSecret: gtodolist
AccessExpire: 31536000
# mysql
Mysql:
Path: 127.0.0.1
Port: 3306
Dbname: gtodolist
Username: root
Password: "101325"
MaxIdleConns: 10
MaxOpenConns: 10
LogZap: false
Config: parseTime=True&loc=Local
Cache:
- Host: 127.0.0.1:6379
Pass: "101325"
Redis:
Host: 127.0.0.1:6379
Pass: "101325"
Type: node
Key: task.rpc
internal/config/config.go
type Config struct {
zrpc.RpcServerConf
Mysql gormc.Mysql
Cache cache.CacheConf
}
internal/svc/service_context.go
type ServiceContext struct {
Config config.Config
TaskModel model.TaskModel
RedisClient *redis.Redis
}
func NewServiceContext(c config.Config) *ServiceContext {
db, err := gormc.ConnectMysql(c.Mysql)
if err != nil {
log.Fatal(err)
}
return &ServiceContext{
Config: c,
TaskModel: model.NewTaskModel(db, c.Cache),
RedisClient: redis.MustNewRedis(c.Redis.RedisConf),
}
}
编写核心逻辑
api
task_create
internal\logic\task_create_logic.go
func (l *TaskCreateLogic) TaskCreate(req *types.CreateReq) (resp *types.CreateResp, err error) {
status, err := strconv.Atoi(req.Status)
if err != nil {
status = 1
}
createResp, err := l.svcCtx.TaskRpcClient.CreateTask(l.ctx, &pb.CreateReq{
Uid: ctxdata.GetUidFromCtx(l.ctx),
Title: req.Title,
Content: req.Content,
Status: int32(status),
})
if err != nil {
return &types.CreateResp{
Status: int(vo.ErrServerCommonError.GetErrCode()),
Message: err.Error(),
Error: err.Error(),
}, nil
}
resp = &types.CreateResp{}
_ = copier.Copy(resp, createResp)
return resp, err
}
task_update
internal\logic\task_update_logic.go
func (l *TaskUpdateLogic) TaskUpdate(req *types.UpdateReq) (resp *types.UpdateResp, err error) {
status, err := strconv.Atoi(req.Status)
if err != nil {
status = 1
}
updateResp, err := l.svcCtx.TaskRpcClient.UpdateTask(l.ctx, &pb.UpdateReq{
Id: req.Id,
Uid: ctxdata.GetUidFromCtx(l.ctx),
Title: req.Title,
Content: req.Content,
Status: int32(status),
})
if err != nil {
return &types.UpdateResp{
Status: int(vo.ErrServerCommonError.GetErrCode()),
Message: err.Error(),
Error: err.Error(),
}, nil
}
resp = &types.UpdateResp{}
_ = copier.Copy(resp, updateResp)
return resp, err
}
rpc
create_task
internal\logic\create_task_logic.go
func (l *CreateTaskLogic) CreateTask(in *pb.CreateReq) (*pb.CreateResp, error) {
task := &model.Task{
Uid: in.Uid,
Title: in.Title,
Status: int64(in.Status),
Content: sql.NullString{
String: in.Content,
Valid: true,
},
StartTime: time.Now(),
}
err := l.svcCtx.TaskModel.Insert(l.ctx, nil, task)
if err != nil {
return nil, errors.Wrap(vo.ErrDBerror, "数据插入出错")
}
return &pb.CreateResp{
Status: vo.OK,
Data: vo.SUCCESS,
Message: vo.SUCCESS,
}, nil
}
update_task
internal\logic\update_create_logic.go
执行流程: 查询该用户是否存在该任务 (捕获错误) -> 修改任务 -> 返回结果
func (l *UpdateTaskLogic) UpdateTask(in *pb.UpdateReq) (*pb.UpdateResp, error) {
// 先根据 id 查询该用户是否存在该任务
id, err := strconv.Atoi(in.Id)
if err != nil {
return nil, errors.Wrap(vo.ErrRequestParamError, "任务id错误")
}
task, err := l.svcCtx.TaskModel.FindOne(l.ctx, int64(id))
if err != nil && err != model.ErrNotFound {
return nil, errors.Wrap(vo.ErrDBerror, "数据库查询出错")
}
if task.Uid != in.Uid {
return nil, errors.Wrap(vo.ErrRequestParamError, "没有这条任务信息")
}
// 修改任务
task = &model.Task{
Id: task.Id,
CreatedAt: task.CreatedAt,
Uid: task.Uid,
Title: in.Title,
Status: int64(in.Status),
Content: sql.NullString{
String: in.Content,
Valid: true,
},
StartTime: time.Now(),
}
err = l.svcCtx.TaskModel.Update(l.ctx, nil, task)
if err != nil {
return nil, errors.Wrap(vo.ErrDBerror, "数据库修改失败")
}
return &pb.UpdateResp{
Status: vo.OK,
Data: vo.SUCCESS,
Message: vo.SUCCESS,
}, nil
}
现在任务的创建和修改就完成了 (现在我们在修改任务信息时都会先获取一下这个任务是否存在, 事实上, 这一部分就是另一个 task_show
接口的实现, 所以后面我们会分开实现)