gin自带的validator魔改使用 | Go主题月

361 阅读2分钟

引言

  • 我在使用gin开发自己的框架时,发现一个痛点,就是gin的validator只能在结构体上绑定的同时校验
  • 尴尬的事情是比如Model层操作这个增删改查的时候,我一个Model的结构体实现不了,我需要定义多个
  • 在学习Go-Vue-Admin框架的时候我发现了,他们是自己写了一个简易的校验
  • 于是我就在想可不可以基于gin自带的实现,单独定义验证规则,不需要绑定到Model的结构体
  • 项目github

1、查文档

  • 很遗憾,没有找到完整的中文文档,我只能看一些文章
  • github找对应的demo案例

2、实现的关键

myEmail := "joeybloggs.gmail.com"

errs := validate.Var(myEmail, "required,email")

if errs != nil {
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
return
}

3、验证器代码 (简略)

    type Rules map[string]string

    // st是Model结构体  一般在 c.ShouldBind(&st) 就已经绑定值了
    func Verify(st interface{}, r Rules) error {
	va := global.Verify //全局变量存储的Validate
	typ := reflect.TypeOf(st)
	val := reflect.ValueOf(st) 
	kd := val.Kind()
	if kd != reflect.Struct {
		return errors.New("expect struct")
	}
	num := val.NumField()
	for i := 0; i < num; i++ {
		// 取每个字段
		typVal := typ.Field(i)
		// 获取tag
		tag := typVal.Tag.Get("desc")
		// 查看规则是否有该字段无则忽略
		verify, ok := r[typVal.Name]
		if !ok {
			continue
		}
		// 获取字段的值信息
		v := val.Field(i).Interface()

		if err := va.Var(v, verify); err != nil {
			
			var b strings.Builder
			if tag != "" {
				b.WriteString(tag)
			} else {
				b.WriteString(typVal.Name)
			}
			b.WriteString(GetError(err))//GetError是我处理转成中文错误信息的
			return errors.New(b.String())
		}
	}
	return nil
}

4、验证规则

放在request目录下,验证规则和

package request

var (
	RuleAddVerify = Rules{"Role_name": "required", "Role_desc": "required"}
	RuleUpVerify  = Rules{"Authority_id": "required", "Role_name": "omitempty,required", "Role_desc": "omitempty,required"}
	RuleDelVerify = Rules{"Authority_id": "required"}
)

5、案例

model结构体定义

    type AdminRule struct {
	CreatedOn    int64          `json:"created_on"`
	ModifiedOn   int64          `json:"modified_on"`
	DeletedAt    gorm.DeletedAt `json:"deleted_at"`
	Role_name    string         `desc:"角色名称" json:"role_name" form:"role_name" `
	Role_desc    string         `desc:"角色描述" json:"role_desc" form:"role_desc" `
	Status       int            `desc:"角色状态" json:"status"`
	Authority_id int            `desc:"角色ID" gorm:"primary_key" uri:"id" form:"id" json:"id"`
}

控制器

    func CreateRule(c *gin.Context) {

	var rule models.AdminRule
	c.ShouldBind(&rule)//不接收gin自己的验证错误信息,只需要绑定结构体的值
        //验证规则
	if err := request.Verify(rule, request.RuleAddVerify); err != nil {
		tool.JSONP(c, 400, err.Error(), nil)
		return
	}
        //调用服务层
	if ret := services.CreateRule(rule); !ret.GetStatus() {
		tool.JSONP(c, 40001, ret.GetMsg(), ret["data"])
		return
	} else {
		tool.JSONP(c, 0, ret.GetMsg(), ret["data"])
	}

}

6、结尾

这样的写法就比较清晰了,我们只需要定义一个Model和多个验证器规则,一个接口的增删改查就比较舒服了 与诸君共勉之,写的不好的地址给指正,希望对您有帮助,思路很重要