Skip to content

定制

本节介绍如何基于四层应用架构进行定制,各层需要先嵌入基础抽象,再决定是 用函数选项覆写已有方法 还是 自定义新方法

方案取舍

方案适用场景
选项配置(首选)只是 出入库字段选择与忽略、关联预加载、需要少量扩展数据、出库数据需加工 时使用
覆写已有方法需要自定义 DTO、返回结构完全不同、基类语义不适用
自定义新方法基础抽象根本没有这个能力,是新的业务操作、其他任何需要纠结用什么的情况

覆写已有方法

基控制器、基服务、基仓储的方法,都可以被覆写;

覆写一个方法,就是将对应基础抽象的同名方法复制过来,然后修改一下 接收者

如基服务的 Update 方法:

go
// Update 根据主键更新记录
func (s *Service[T]) Update(ctx context.Context, tri *bindx.Tri[T], opts Options) error {
	return s.repo.Update(ctx, tri.Map, s.BuildRepoOpts(opts))
}

子服务文件覆写:

internal\service\admin\auth\admin.go 文件 (s *AuthAdminService) 部分就是接受者:

go
// Update 覆写通用更新方法: 用户名唯一校验 + 密码为空时移除字段不更新,非空则加密 + 分组关联替换
func (s *AuthAdminService) Update(ctx context.Context, tri *bindx.Tri[model.Admin], opts service.Options) error {
	pk, err := strconv.ParseUint(opts.PrimaryKeyValue, 10, 32)
	if err != nil {
		return errors.New("主键值错误")
	}

	// 用户名唯一校验...

	// 密码为空时移除字段,确保不覆盖旧密码;非空则加密后写入...

	// 分组信息提取...

	// 校验分组权限...

	return nil
}

自定义方法

控制器、服务、仓储层,都可以自定义方法;自定义有一个好处,方法签名不受任何限制。

控制器新增自定义方法:

go
// SendTestMail 发送测试邮件
func (h *ConfigHandler) SendTestMail(c *gin.Context) {
    var req struct {
        SMTPServer string `json:"smtp_server"`
        // ...
    }
    if err := c.ShouldBindJSON(&req); err != nil {
        httpx.Fail(c, httpx.WithMessage("参数错误: "+err.Error()))
        return
    }
    // ... 发邮件逻辑 ...
    httpx.Success(c, httpx.WithMessage("测试邮件发送成功~"))
}

func (h *ConfigHandler) RegisterRoutes(group *gin.RouterGroup) {
    handler.RegisterBaseRoutes(h, group)

    // 记得追加自定义路由
    group.POST("/send-test-mail", middleware.AdminAuth(), middleware.AdminPermission(), h.SendTestMail)
}

服务层新增自定义方法:

go
// 管理员登录(构造参数直接传,签名自己定)
func (s *AdminService) Login(ctx context.Context, req *dto.LoginRequest, clientIP string) (*dto.LoginResponse, error) {
    admin, err := s.repo.FindByUsername(ctx, req.Username)
    // ... 校验验证码、密码、生成 token ...
    return &dto.LoginResponse{Admin: adminDTO, Token: tokenStr}, nil
}

仓储层新增自定义方法:

go
// 按用户名查询
func (r *AdminRepository) FindByUsername(ctx context.Context, username string) (*model.Admin, error) {
    admin, err := gorm.G[model.Admin](r.DB()).Where("username = ?", username).First(ctx)
    if err != nil {
        return nil, err
    }
    return &admin, nil
}