Go源码解析:validator.v8

注:

  1. 获取工程包:go get -u gopkg.in/go-playground/validator.v8
  2. github地址:https://github.com/go-playground/validator/tree/v8.18.2
  3. Api文档:https://godoc.org/gopkg.in/go-playground/validator.v8

这边的分析主要是针对Struct方法,其他的方法比较类型,就不多赘述.

目录

1、包结构

2、静态常量

Ⅰ.tag标签符

Ⅱ.结构体标识(tagType)

Ⅲ.其他tagType字段

Ⅳ.报错信息

3、TagType

4、校验器类型

Ⅰ.tag标签校验器

Ⅱ.结构体类型校验器

Ⅲ.数据类型校验器

Ⅳ.别名校验器

5、默认校验器

Ⅰ.默认别名校验器

 Ⅱ.默认tag校验器

6、注册校验器

Ⅰ.RegisterStructValidation

Ⅱ.RegisterValidation

Ⅲ.RegisterCustomTypeFunc

Ⅳ.RegisterAliasValidation

7、校验器结构体

Ⅰ.cTag(tag规则)

Ⅱ.cFeild(字段规则)

Ⅲ.cStruct(结构体规则)

Ⅳ.两个缓存

1.structCache(结构体缓存)

2.tagCache(标签规则缓存)

Ⅴ.Validate(校验类)

Ⅵ.config(配置)

8、声明校验类(New)

9、Struct(进行结构体校验)

Ⅰ.整体过程

Ⅱ.ensureValidStruct(结构体校验)

Ⅲ.tranverseStruct(遍历结构体字段)

Ⅳ.extractStructCache(获取校验器缓存)

Ⅴ.traverseField(遍历所有Field)

10、使用方法


1、包结构

validator包就比较简单,没有用到一些比较复杂的操作,有点类似之前做的Java对象对比工具,不过Java比较恶心的处理就是泛型,在go里面只需要对interface、ptr进行处理,相对比较简单.说没有复杂的操作是因为,之前在做对象对比工作的时候有想到参照Lamada表达式的做法,直接在编译时期去操作语法树,直接生成相应的.class源码.

validator包结构比较简单,主要是下面几个部分:

  1. baked_in.go :定义默认【标签校验器】和【别名校验器】,程序初始的时候直接赋值了默认的校验器,相当于你买了个机器人送几根电池的行为。当然这边你的校验器可以手动添加自定义,后面会说到
  2. cache.go:定义结构体校验器缓存、字段校验器缓存和获取的方法,一个validator对象如果一直存活,他会把之前处理过的结构体或者字段校验器进行缓存.
  3. regexes.go:【标签校验器】里面有一些使用到正则进行校验的,这边存储的就是静态的正则表达式
  4. util.go:工具类,一般是用在【标签校验器】里面进行处理
  5. validator.go:校验类主体,提供四个主要的校验方法

2、静态常量

Ⅰ.tag标签符

        validator在解析的时候,处理tag标签,比如说分割、或条件或者转义:

  utf8HexComma = "0x2C" //read note 在tag里面代表【,】;需要这么书写,直接写【,】会被识别成分割符

  utf8Pipe = "0x7C" //read note 在tag里面代表【|】;需要这么书写,直接写【|】会被识别成条件符

  tagSeparator = "," //read note tag标签分割符

  orSeparator = "|" //read note tag判断条件【或】

  tagKeySeparator = "=" //read note tag里面需要等值 使用=

Ⅱ.结构体标识(tagType)

        结构体标签这边有两个,作用应该是类似的:

structOnlyTag     = "structonly"         //read note 结构体上有的tagType,因为结构体的特殊性,他在获取cTag的时候是从第二个开始的,也就是说第二个才是生效的,所以当只书写structonly的时候,他会略过这个tag,那么必须跟着前面的一个标签才行,比如说 `valid="require,structonly"`,这样才会生效

noStructLevelTag  = "nostructlevel" //  同上

       文档的说法如下:

When a field that is a nested struct is encountered, and contains this flag any validation on the nested struct will be run, but none of the nested struct fields will be validated.

This is usefull if inside of you program you know the struct will be valid, but need to verify it has been assigned. NOTE: only "required" and "omitempty" can be used on a struct itself.

      这边测试和看完源码发现这两个tag只对结构体生效,如果加上这个标签,只会去校验结构体,而不会校验结构体中的参数,但是对于结构体来说,标签的实现是从第二个开始的。

也就是说比如说我的Person类中嵌套了一个Cat类,我不想校验Cat类的属性,只要Cat存在即可,需要这么使用(需要书写两个标签,起作用的是第二个标签):

	type Ower struct {
		Age int `validate:"min=10"`
	}

	type Cat struct {
		Age  int `validate:"min=10"`
		Ower Ower
	}

	type Person struct {
		Cat     Cat            `validate:"required,nostructlevel"`
	}

Ⅲ.其他tagType字段

         这边还有其他四个被称为tagType的字段,也是分别在结构体字段tag中进行声明,然后程序会转换成对应的tagType,在校验的时候起作用:

omitempty         = "omitempty"     //read note 如果字段未设值则忽略它

skipValidationTag = "-"             //read note 忽略字段

diveTag           = "dive"          //read note 深入到slice, array or map 里面去校验里面的字段是否正确,每一层都需要多一个【div】来标识   |     read note 比如说 [][]string "gt=0,dive,dive,required" gt是校验[][]string长度,第一个div是校验[]string,第二个div是校验string

existsTag         = "exists"        //read note 校验值存在即可(除非是nil则会报错),和require的区别是说,require对默认值也会报错

Ⅳ.报错信息

        下面的一些字段就是数据结构名称和固定报错信息的字段.其实这是一个比较好的做法,如果工具类中有一些报错信息,可以直接写成静态参数,然后在需要的时候进行引用,这就保证了错误信息的一致性

//read note 数组结构的名称组成

arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket

mapIndexFieldName   = "%s" + leftBracket + "%v" + rightBracket

//read note 字段校验错误信息打印

fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"

//read note 报错信息(非字段校验错误)

invalidValidation       = "Invalid validation tag on field %s"

undefinedValidation     = "Undefined validation function on field %s"

validatorNotInitialized = "Validator instance not initialized"

fieldNameRequired       = "Field Name Required"

tagRequired             = "Tag Required"

3、TagType

tagType对应【cTag】结构体中的【typeOf】字段,在进行字段处理的时候,如果存在typeOf字段,则会根据对应的字段进行相应的处理,这边有几个默认的tagType类型,相应的处理举个例子就是,比如说tagType为【|】的时候,只要满足一个条件即可,则遇到满足的条件直接跳过所有tagType为【|】的cTag.其他的一些tagType的处理后面详细说到

typeOmitEmpty      :对应上面的【omitempty】标签,实现对应功能

typeNoStructLevel :对应上面的【nostructlevel】,实现对应功能

typeStructOnly       :对应上面的【structonly】标签,实现对应功能

typeDive                 :对应上面的【dive】标签,实现对应功能

typeOr                    :对应上面的【|】标签,实现对应功能

typeExists               :对应上面的【exists】标签,实现对应功能

4、校验器类型

validator一共提供了四种校验器:

validationFuncs     map[string]Func                                     //规则类型的校验           【tag标签】->        校验规则

structLevelFuncs    map[reflect.Type]StructLevelFunc        //规则结构体的校验       【结构体类型】->        校验规则

customTypeFuncs     map[reflect.Type]CustomTypeFunc  //类型校验器                   【数据类型】->         校验规则

aliasValidators     map[string]string                                     //别名校验器                   【别名匹配规则组合】->   校验规则

四种校验器都可以进行注册,tag标签校验器和别名校验器 在validator初始化的时候已经把默认的校验器加载进去了,我们来看一下不同校验器的作用

Ⅰ.tag标签校验器

validationFuncs map[string]Func       //规则类型的校验 【tag标签】-> 校验规则             

// Func accepts all values needed for file and cross field validation
// v             = validator instance, needed but some built in functions for it's custom types
// topStruct     = top level struct when validating by struct otherwise nil
// currentStruct = current level struct when validating by struct otherwise optional comparison value
// field         = field value for validation
// param         = parameter used in validation i.e. gt=0 param would be 0
type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool

这个校验器比较好理解,就是我们在结构体字段的【tag】上加上对应的标签,通过标签去找到对应的【校验方法】,进行校验处理,比如说我们在tag上面加上:`len = 10`,那么他就会通过【len】这个标签去找到【HasLengthOf】这个校验方法,并调用它.

Ⅱ.结构体类型校验器

structLevelFuncs map[reflect.Type]StructLevelFunc //规则结构体的校验 【结构体类型】-> 校验规则

// StructLevelFunc accepts all values needed for struct level validation
type StructLevelFunc func(v *Validate, structLevel *StructLevel)

结构体校验器是通过结构体类型(【Type】)去找到对应的【结构体校验器】,并调用该校验器进行处理

这个校验器处理结束之后,会把对应的结果进行输出,并且这个被注册类型的结构体内部的其他字段如果有配置tag标签也会被validator校验.

Ⅲ.数据类型校验器

customTypeFuncs map[reflect.Type]CustomTypeFunc    //类型校验器 【数据类型】-> 校验规则

// CustomTypeFunc allows for overriding or adding custom field type handler functions
// field = field value of the type to return a value to be validated
// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
type CustomTypeFunc func(field reflect.Value) interface{}

     数据类型校验器,通过【类型(Type)】进行关联,可以注册一个结构体类型,也可以注册基本类型

     这里有一个需要注意的问题就是说,如果我们自定义结构体校验器,那么对于【结构体校验器集】来说这个结构体类型已经存在了,他不会再去处理解析对应结构体的参数,然后再往【结构体校验器集】里面添加这个类型对应的校验器,也就是说这个类型的校验完全按照你自己的定义的方法来处理了,你在这个结构体字段上定义的【tag标签将不再生效】(即使是基础类型的tag标签也不会生效了)。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用:HTTP Status 500 - javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find ... 引用:Java Spring应用发送数据报如下问题。 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 原因分析: 引用:用httpclient访问https资源时,会出现异常,与环境也有关系,有些机器请求正常。 解决方案: 在HTTPS通信中,当Java程序尝试与服务端建立安全连接时,会进行SSL握手过程。如果在握手过程中出现异常javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException,可能是由于证书验证失败导致的。这种异常通常有两种原因:一是服务端证书不被信任,二是客户端无法找到合适的证书链。 解决这个问题的方法有以下几种: 1. 信任自签名证书:可以通过自定义TrustManager来信任自签名的证书。但这种方法存在安全风险,因为所有的自签名证书都会被信任。 2. 导入服务端证书:可以将服务端的证书导入到Java的信任证书库中,以确保它被信任。可以使用keytool工具将证书导入到Java信任库中。 3. 禁用证书验证:在开发环境中,可以禁用证书验证来避免这个问题。但在生产环境中不建议这样做,因为会降低通信的安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了-凡

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值