Appearance
定制
本节介绍如何基于四层应用架构进行定制,各层需要先嵌入基础抽象,再决定是 用函数选项、覆写已有方法 还是 自定义新方法。
方案取舍
| 方案 | 适用场景 |
|---|---|
| 选项配置(首选) | 只是 出入库字段选择与忽略、关联预加载、需要少量扩展数据、出库数据需加工 时使用 |
| 覆写已有方法 | 需要自定义 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
}