Golang Model 字段自动化校验设计方案

 更新时间:2025年02月17日 11:06:44   作者:Gerald Kwok  
在我们日常开发中,不可避免的总要去进行各种参数校验,但是如果在某个场景中,要校验的字段非常多,并且在其中还有耦合关系,那么我们手写校验逻辑就变得非常的低效且难以维护,本篇文档就基于 DDD 领域模型设计的思想下,提供自动化的校验模型字段,感兴趣的朋友一起看看吧

背景

在我们日常开发中,不可避免的总要去进行各种参数校验,但是如果在某个场景中,要校验的字段非常多,并且在其中还有耦合关系,那么我们手写校验逻辑就变得非常的低效且难以维护。本篇文档就基于 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
}

简单来描述自动校验分为以下几个步骤:

  • 在接收传参的转换函数中,先把本次请求传入的字段拿到,并且注册这些字段对应的校验函数。
  • 进入到业务逻辑处理的函数中,再次增加一些当前业务场景需要的特殊校验函数。
  • 依次执行校验函数,观察是否有报错。

到此这篇关于Golang Model 字段自动化校验设计的文章就介绍到这了,更多相关Golang Model 字段校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang仿ps实现获取Linux进程信息

    Golang仿ps实现获取Linux进程信息

    这篇文章主要为大家学习介绍了Golang如何仿ps实现获取Linux进程信息,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-07-07
  • Go语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    Go语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    这篇文章主要介绍了Go语言字典(map)用法,结合实例形式较为详细的分析了Go语言字典的创建、填充、遍历、查找、修改、删除等操作相关实现技巧,需要的朋友可以参考下
    2017-02-02
  • Go反射中type和kind区别比较详析

    Go反射中type和kind区别比较详析

    这篇文章主要给大家介绍了关于Go反射中type和kind区别比较的相关资料,Type是接口类型,Value是Struct类型,Type是类型描述,而Value是具体的值,需要的朋友可以参考下
    2023-10-10
  • 详解如何在Go语言中生成随机种子

    详解如何在Go语言中生成随机种子

    这篇文章主要为大家详细介绍了如何在Go语言中生成随机种子,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2024-04-04
  • 深入学习Golang的流程控制

    深入学习Golang的流程控制

    Go 语言是一门现代化的编程语言,以其简洁高效、并发安全等特点被越来越多的开发者所使用。本文将深入探讨 Go 语言中的流程控制,包括条件语句、循环语句以及控制语句等方面
    2023-05-05
  • Golang 并发控制模型的实现

    Golang 并发控制模型的实现

    Go控制并发有三种经典的方式,使用 channel 通知实现并发控制、使用 sync 包中的 WaitGroup 实现并发控制、使用 Context 上下文实现并发控制,下面就来介绍一下
    2024-08-08
  • Go 在 MongoDB 中常用查询与修改的操作

    Go 在 MongoDB 中常用查询与修改的操作

    这篇文章主要介绍了Go 在 MongoDB 中常用查询与修改的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • 浅谈一下前端http与https有什么区别

    浅谈一下前端http与https有什么区别

    这篇文章主要介绍了浅谈一下前端http与https有什么区别,现今大部分的网站都已经使用了 https 协议,那么https对比http协议有哪些不同呢,需要的朋友可以参考下
    2023-04-04
  • Golang通过SSH执行交换机操作实现

    Golang通过SSH执行交换机操作实现

    这篇文章主要介绍了Golang通过SSH执行交换机操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Go语言中的map扩容机制

    Go语言中的map扩容机制

    Go语言中的map是一种高效的数据结构,其扩容机制确保了在大数据量情况下的性能,本文介绍了包括扩容触发条件、扩容过程和渐进式扩容,感兴趣的可以了解一下
    2024-12-12

最新评论