golang validator 包的使用指北

看到 validator 咱们第一反应会想起啥?见名知意我就可以知道他是一个验证器,如果用过 gin web 框架的同学,自然是用过 gin 里面的 validator,只不过 gin 中使用的关键字是 binding 去做标识

开门见山

Validator 实际上是一个验证工具,属于 golang 的第三方包,这个包中使用了各种反射技巧来提供了各种校验和约束数据的方式方法,非常实用,常用的有这些:

  • 基本的字段长度,大小,范围的约束

    • len:约束参数长度
    • eq:数值等于参数值
    • max:数值小于等于参数值
    • min:数值大于等于参数值
    • ne:不等于参数值
    • gt:大于参数值,gte:大于等于参数值
    • lt:小于参数值, lte:小于等于参数值
    • oneof:只能是枚举值中的一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,则使用单引号包围。例如:oneof=changsha beijing haerbing
  • 是否必选,是否跳过,是否忽略

    • -:跳过该字段
    • | :使用多个约束,只需要满足其中一个,例如:xxx| xxx
    • required:必选约束,不能为默认值
    • omitempty:如果字段未设置,则忽略它
  • 各种格式约束如

    • email
    • url
    • ip、ipv4、ipv6
    • uuid
    • datetime
    • json
    • file , 参数必须是一个合法的文件路径

常用的大概有上述这些,我们也不需要去背,只需要知道如何去使用,以及咱们需要处理数据校验的时候,能够想到 validator 库就行了,实在记不起来看官方文档或者看本篇文章的例子就可以了,这个是官网:

validator package - github.com/go-playground/validator/v10 - Go Packages

使用

使用 validator 工具, 自然是为了提高我们的开发效率以及让我们写出来的内容更加优雅和健壮

如果我们自己每一个字段都显示的去校验是否符合我们预期,那么代码大概率会很臃肿,来一个简单的 demo,举个栗子

package main

import (
   "fmt"
   "github.com/go-playground/validator/v10"
)

type Data struct {
   City       string `validate:"min=8,max=15"`
   Name       string `validate:"min=6,max=10"`
   Addr       string `validate:"url"`
   Age        int    `validate:"gte=18,lte=100"`
   Tall       int    `validate:"required"`
   IpAddr     string `validate:"ipv4"`
   Email      string `validate:"email"`
   Content    string `validate:"json"`
   CreateTime string `validate:"datetime=2006-01-02"`
   NewPwd     string `validate:"min=8"`
   RePwd      string `validate:"eqfield=NewPwd"`
}

func main() {
   // 示例 , 基本使用介绍
   validate := validator.New()

   demo1 := Data{
      City:       "changsha11111111111111",
      Name:       "xiaozhu",
      Addr:       "xxxxxxxxx",
      Age:        25,
      Tall:       185,
      IpAddr:     "xxxxxxxxxxx",
      Email:      "helloworld@qq.com",
      Content:    "{"name":"xiaozhu"}",
      CreateTime: "xxxxx2006-03-02",
      NewPwd:     "12345",
      RePwd:      "123456789xxxxx",
   }

   err := validate.Struct(demo1)
   if err == nil {
      fmt.Println("params check success")
      return
   }

   invalid, ok := err.(*validator.InvalidValidationError)
   if ok {
      fmt.Println("param invalid : ", invalid)
      return
   }

   valiErrs := err.(validator.ValidationErrors)

   for _, valiErr := range valiErrs {
      fmt.Println(valiErr)
   }
}

此处我们可以看到我们在 Data 数据结构中,对其成员进行了不同的约束,相信通过 xdm 看到 Data 结构中的 validate 标识后面的约束,就知道响应字段的约束是啥意思了

例如

Age int `validate:"gte=18,lte=100"`

约束 Age 这个字段,需要满足 大于等于 18 ,小于等于 100 的范围

RePwd string `validate:"eqfield=NewPwd"`

RePwd 字段,需要和 NewPwd 字段相等 ,这个是用 eqfield 做标识的

关于 xxfield 的跨字段约束的相关标识可以查看官网的此处

这里是 valiator 能支持的所有类型,从字段内容,网络方面,字符串,数据结构,比较的字符,其他的标识

[图片上传失败...(image-c417e3-1694309176532)]

另外关于邮箱约束的:

Email string `validate:"email"`

Email字段,必须是 email 格式的,才能够检验通过

如上,每一个字段,如果需要校验的,校验失败,我们也可以全部打印出来

目前在 validator 中,处理错误信息,分为 2 种错误的情况:

  • InvalidValidationError

咱们将我们的 err 转换成 InvalidValidationError ,表示输入参数错误

  • ValidationErrors:字段违反约束,错误信息如下

咱们将我们的 err 转换成 ValidationErrors,这是一个切片,所以咱们可以遍历输出,这个是表示不符合约束字符的有错误原因

[图片上传失败...(image-f85411-1694309176532)]

validator.ValidationErrors 是一个 FieldError 类型的切片

type ValidationErrors []FieldError

FieldError 中包含了关于 error 的全部信息,我们可以调用 FieldError 里面的成员方法进行输出即可

type FieldError interface {
   Tag() string
   ActualTag() string
   Namespace() string
   StructNamespace() string
   Field() string
   StructField() string
   Value() interface{}
   Param() string
   Kind() reflect.Kind
   Type() reflect.Type
   Translate(ut ut.Translator) string
   Error() string
}

关于其他标识的使用就不过多赘述了,使用方式都大同小异,咱们可以参考上述的 demo 即可

自定义约束

当然,如果认为官方提供的支持的标识还不能满足我们的要求,那么我们也是可以自定义咱们的标识的,例如,咱们要定义的标识是 happyhead含义就是,咱们定义的字符串,必须是以 happy 开头的,否则就校验不通过

此时咱们就需要使用到 validator 包中的 RegisterValidation 方法,再按照这个方法,提供一个校验实际参数的回调函数即可:

[图片上传失败...(image-a6c41d-1694309176532)]

我们就可以这样来写

[图片上传失败...(image-8adfbb-1694309176532)]

查看实际效果如下:

demo1 validate failed :  Key: 'RegisterFormat.Name' Error:Field validation for 'Name' failed on the 'happyhead' tag
demo2 validate success ...

至此,咱们将 validator 包中的特殊约束,格式约束,错误处理,范围约束,字符串约束,以及自定义约束都简单过了一下,这些东西不需要朗读和背诵,只需要咱们知道有他,需要的时候,能够找到,能够迅速使用起来即可

当然,如果想研究他的实现原理的,可以好好看看 validator 源码包以及官方文档,还是非常有意思的

感谢阅读,欢迎交流,点个赞,关注一波 再走吧

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

[图片上传失败...(image-3abc82-1694309176532)]

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容