Golang Model 字段自动化校验设计
创作时间:
作者:
@小白创作中心
Golang Model 字段自动化校验设计
引用
CSDN
1.
https://m.blog.csdn.net/weixin_42678507/article/details/145653275
在日常开发中,参数校验是一个不可避免的环节。当需要校验的字段非常多且存在耦合关系时,手写校验逻辑变得低效且难以维护。本文基于DDD领域模型设计的思想,提供了一种自动化的模型字段校验方案,通过定义Validator结构体和相关方法,实现了对模型字段的自动化校验。
背景
在我们日常开发中,不可避免的总要去进行各种参数校验,但是如果在某个场景中,要校验的字段非常多,并且在其中还有耦合关系,那么我们手写校验逻辑就变得非常的低效且难以维护。本篇文档就基于 DDD 领域模型设计的思想下,提供自动化的校验模型字段。
常见的字段校验方式
数据校验在业务逻辑代码中有着至关重要的作用,关系到整个后续业务是否可以正常运行。对参数的校验根据其具体业务逻辑与场景,可以分为字段校验、依赖校验、功能校验与逻辑校验四个部分。
字段校验
字段校验是最常见的校验类型。例如:商品名称不能超过多少个字符,商品状态必须是有效等。
func (e *Shop) ValidateShopName() error {
if e.Name != nil && e.Name == "" {
return errors.New("商品名称不能为空。")
}
if e.Name != nil && utf8.RuneCountInString(e.Name) > constant.MaxShopNameLength {
return errors.Errorf("商品名称长度为 %d, 不能超过 %d ", utf8.RuneCountInString(e.Name), constant.MaxShopNameLength)
}
return nil
}
依赖校验
依赖校验,顾名思义是在业务逻辑中依赖了其他模块。例如,在创建商品信息时,要校验一下商品依赖的商家或供应商等信息是否合法。
func (e *Shop) ValidateMerchant() error {
// 在此方法中可能需要进行外部调用或者查询 DB 的操作。
if e.HasInvalidMerchant() {
return errors.New("商家信息存在异常")
}
return nil
}
功能校验
功能校验例如用户是否有权限发布商品、商品信息是否与其他商品存在冲突等。
func (e *Shop) ValidateUserPermission() error {
if e.UserCreateShopWithoutPermission() {
return errors.New("用户无权限创建商品")
}
return nil
}
逻辑校验
逻辑校验主要是一些具体的业务逻辑。例如在下架商品时,校验是否有新用户下单等。
func (e *Shop) ValidateCloseShop() error{
if e.InvalidShopStatus() {
return errors.New("商品已下架")
}
if e.ExistShopTicket() {
return errors.New("有正在进行的订单信息,无法下架")
}
return nil
}
上面我们列出来常见的四种校验方式,当我们在一个复杂且庞大的业务场景需要把各种各样的校验放在一起去校验时,我们不得不编写一个庞大的校验函数,把这些单点的校验函数聚合起来,更有甚者都没有进行子逻辑校验的函数区分,就是第一个大函数,把各种各样的校验逻辑代码写到一个函数中,那么长此以往,校验逻辑就会非常复杂,无法迭代。
func (e *Shop) ValidateCreateShop() error {
if err = e.ValidateShopName(); err != nil {
return err
}
if err = e.ValidateDescrption(); err != nil {
return err
}
if err = e.ValidateImage(); err != nil {
return err
}
if err = e.ValidateMerchant(); err != nil {
return err
}
if err = e.ValidateUserPermission(); err != nil {
return err
}
if err = e.ValidateCloseShop(); err != nil {
return err
}
return nil
}
自动化校验
type Validator struct {
FieldNames []string // 需要更新的字段
ValidateNames []string // 需要校验的字段列表
ValidateFuncList []Func() error // 校验函数列表
}
func (v *Validator) Validate() error {
for _, validate := range v.validateFuncList {
if err := validate(); err != nil {
return err
}
}
return nil
}
// GetFields2ValidateFuncMap 各个字段的校验函数在这里扩展,在调用 register 函数时,会自动注册
func (a *Aggregate) GetFields2ValidateFuncMap() map[string]func() error {
return map[string]func() error {
constant.ShopForCreate: a.Shop.ValidateCreateShop,
constant.ShopForUpdate: a.Shop.ValidateUpdateShop,
constant.ShopCanStart: a.Shop.CanStart,
// ... 等等各种校验都可以在这里定义一个聚合函数列表
}
}
func DTOToAgg(dto *DTO.Shop) (*shop.Aggregate, error) {
baseShop := base.NewBaseShop()
// 先把传参 model 转化成领域数据
if err = copier.Copy(baseShop, dto); err != nil {
return nil, errors.Wrap(err, err.Error())
}
// New 一个聚合类
shopAgg := shop.NewShopAggregate(baseShop)
// 获取本次传给领域对象的字段,以及加载要校验的字段
setFields := GetSetOptionalFields(*dto)
var validateName []string
for _, field := range setFields {
validateName = append(validateName, field)
}
shopAgg.SetUpdateFields(setFields)
// 注册 validate 函数
shopAgg.RegisterValidator(validateName)
return shopAgg, nil
}
// 执行校验函数
func (v *Validator) ValidateMultipleFields(ctx context.Context) error {
for _, validate := range v.validateFuncList {
if err := validate(); err != nil {
return err
}
}
return
}
简单来描述自动校验分为以下几个步骤:
- 在接收传参的转换函数中,先把本次请求传入的字段拿到,并且注册这些字段对应的校验函数。
- 进入到业务逻辑处理的函数中,再次增加一些当前业务场景需要的特殊校验函数。
- 依次执行校验函数,观察是否有报错。
热门推荐
大语言模型在国际中文教育中的智能语伴应用研究
医学机器学习:数据预处理、超参数调优与模型比较的实用分析
3D打印如何与人工智能相结合
诉讼标的详解:概念、类型与实务要点
【糖友课堂】推荐给糖尿病人的抗阻运动
东航里程积分计算与兑换全解析
微信好友有数量限制吗?
如何改善居住小区的环境质量?这种改善需要克服哪些困难?
止痛药怎么选?哪种效果最好?这两种情况吃错后果很严重
为什么DNA鉴定如此精确?一文了解DNA检测的科学原理
蓝牙跳频扩频技术的作用:提升抗干扰能力与通信可靠性的核心机制
公司到银行开户需要什么材料?
2025年考研调剂待录取通知:如何顺利通过待录取阶段?
高蛋白饮食指南:增肌减脂
张艺谋执导《三体》电影!国产科幻影视精品浪潮来袭?
科学家构建多模态LLM框架,进行3D脑CT放射学报告生成
如何通过官网找到事业编报名入口?
如何制作线上团队报名表
双刀双掷开关的使用方法是什么?
双掷继电器 - 工作、电路图和使用
秋季当季水果大盘点:7种水果的营养价值与选购指南
中国三位唢呐女博士在维也纳金色大厅惊艳亮相,展示中国文化自信
消除噪音的10个方法,让你远离嘈杂环境
EXO团队如何出名
备份域服务器搭建,备份域服务器搭建的操作步骤
欧元兑美元的技术分析
汽车贴膜完全指南:从准备到完成的详细步骤与注意事项
电脑到了怎么查看配置和型号?如何快速识别电脑规格?
怎么查看电脑的配置
详解LED背光源与背光模组元件,揭秘液晶显示屏背后奥秘