因为之前把所有框架都生成好了, 所以现在我们直接编写逻辑代码即可
api
task_list
internal\logic\task_list_logic.go
func (l *TaskListLogic) TaskList(req *types.ListReq) (resp *types.ListResp, err error) {
// 准备参数, 规定默认 limit 为 20, start 为 1
limit, err := strconv.Atoi(req.Limit)
if err != nil || limit <= 0 || limit > 20 {
limit = 20
}
start, err := strconv.Atoi(req.Start)
if err != nil || start <= 0 {
start = 1
}
uid := ctxdata.GetUidFromCtx(l.ctx)
listResp, err := l.svcCtx.TaskRpcClient.ListTask(l.ctx, &pb.ListReq{
Uid: uid,
Limit: int64(limit),
Start: int64(start),
})
if err != nil {
return &types.ListResp{
Status: int(vo.ErrServerCommonError.GetErrCode()),
Message: err.Error(),
Error: err.Error(),
}, nil
}
resp = &types.ListResp{}
_ = copier.Copy(resp, listResp)
return resp, err
}
model
因为模板文件中没有直接实现分页查询, 所以我们需要自己在 model 层中编写分页查询的函数 (事实上, 你也可以直接修改模板文件, 这样每一次 goctl
就都会生成分页查询的函数了)
首先我们先在 model
目录中新建 my_task_model.go
文件, 这里放我们自定义的 model 函数
package model
import (
"context"
"fmt"
"gorm.io/gorm"
)
var (
cacheGtodolistTaskListPrefix = "cache:gtodolist:task:list:"
)
type (
myTaskModel interface {
List(ctx context.Context, uid, page, pageSize int64) ([]Task, error)
}
)
func (m *defaultTaskModel) List(ctx context.Context, uid, page, pageSize int64) ([]Task, error) {
key := fmt.Sprintf("%s%v:%v:%v", cacheGtodolistTaskListPrefix, uid, page, pageSize)
var resp []Task
err := m.QueryCtx(ctx, &resp, key, func(conn *gorm.DB, v interface{}) error {
err := conn.Debug().Model(&Task{}).Where("uid = ?", uid).Offset(int((page - 1) * pageSize)).Limit(int(pageSize)).Find(&resp).Error
return err
})
return resp, err
}
写完以后还要将该接口添加到 task_model.go
中
customTaskLogicModel interface {
myTaskModel
}
rpc
list_task
internal\logic\list_task_logic.go
func (l *ListTaskLogic) ListTask(in *pb.ListReq) (*pb.ListResp, error) {
tasks, err := l.svcCtx.TaskModel.List(l.ctx, in.Uid, in.Start, in.Limit)
if err != nil {
return nil, errors.Wrap(vo.ErrDBerror, "数据库查询出错")
}
taskResp := make([]*pb.Task, len(tasks))
for i := 0; i < len(tasks); i++ {
task := tasks[i]
taskResp[i] = &pb.Task{
Id: task.Id,
Title: task.Title,
Content: task.Content.String,
Status: int32(task.Status),
CreateAt: task.CreatedAt.Unix(),
StartTime: task.StartTime.Unix(),
EndTime: task.EndTime.Time.Unix(),
}
}
return &pb.ListResp{
Status: vo.OK,
Data: &pb.Data{
Task: taskResp,
Total: int64(len(tasks)),
},
Message: vo.SUCCESS,
}, nil
}
在 redis 中我们缓存的键是 prefix:uid:page:pageSize
, 所以在删除时我们需要批量删除以 prefix:uid:
为前缀的键, 所以我们再增加一个 DeleteListCache
方法来批量删除缓存, 在增加/修改/删除时要调用该方法, 这样才能确保缓存一致性
这个地方写的不太好, 以后再优化
func (l *ListTaskLogic) DeleteListCache(uid int64) {
prefix := "cache:gtodolist:task:list:"
listKey := fmt.Sprintf("%s%v:*", prefix, uid)
keys, _, _ := l.svcCtx.RedisClient.Scan(0, listKey, 0)
for _, key := range keys {
_, _ = l.svcCtx.RedisClient.Del(key)
}
}