因为之前把所有框架都生成好了, 所以现在我们直接编写逻辑代码即可

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)
	}
}