包验证器基于标签为结构和单个字段实现值验证。
它具有以下独特的功能:
据说说go包里面写的比较好的一个验证包,可以用于中文的翻译等等,跟gorm一样用结构体映射使用
以下为翻译
以下是当前内置验证器的列表:
告诉验证跳过这个结构体字段;这在忽略验证的嵌入式结构时特别方便。
Usage: -
这是“或”运算符,允许使用和接受多个验证器。(用法:rgb|rgba) <-- 这将允许接受 rgb 或 rgba 颜色。例如,这也可以与 ‘and’ 结合使用(用法:omitempty,rgb|rgba)
Usage: |
当遇到嵌套结构的字段并包含此标志时,将运行对嵌套结构的任何验证,但不会验证任何嵌套结构字段。如果您在程序内部知道结构体有效,但需要验证它是否已分配,这将很有用。注意:只有“required”和“omitempty”可以用于结构本身。
Usage: structonly
与 structonly 标记相同,只是不会运行任何结构级别的验证
Usage: nostructlevel
允许条件验证,例如,如果字段未设置值(由“必需”验证器确定),则其他验证(例如 min 或 max)将不会运行,但如果设置了值,则验证将运行。
Usage: omitempty
这告诉验证器深入切片、数组或映射,并使用后面的验证标签验证切片、数组或映射的级别。还支持多维嵌套,您希望潜水的每个级别都需要另一个潜水标签。潜水有一些子标签,‘keys’ 和 ‘endkeys’,请参阅下面的 Keys & EndKeys 部分。
Usage: dive
Example #1
[][]string with validation tag "gt=0,dive,len=1,dive,required"
// gt=0 will be applied to []
// len=1 will be applied to []string
// required will be applied to string
Example #2
[][]string with validation tag "gt=0,dive,dive,required"
// gt=0 will be applied to []
// []string will be spared validation
// required will be applied to string
Keys & EndKeys
这些将在潜水标签之后直接一起使用,并告诉验证器“keys”和“endkeys”之间的任何内容都适用于地图的键而不是值;把它想象成“潜水”标签,但用于映射键而不是值。还支持多维嵌套,您希望验证的每个级别都需要另一个 ‘keys’ 和 ‘endkeys’ 标签。这些标签只对地图有效。
Usage: dive,keys,othertagvalidation(s),endkeys,valuevalidationtags
Example #1
map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required"
// gt=0 will be applied to the map itself
// eg=1|eq=2 will be applied to the map keys
// required will be applied to map values
Example #2
map[[2]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required"
// gt=0 will be applied to the map itself
// eg=1|eq=2 will be applied to each array element in the the map keys
// required will be applied to map values
这将验证该值不是数据类型默认的零值。对于数字,确保值不为零。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required
仅当所有其他指定字段都等于指定字段之后的值时,验证中的字段必须存在且不能为空。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required_if
Examples:
// require the field if the Field1 is equal to the parameter given:
Usage: required_if=Field1 foobar
// require the field if the Field1 and Field2 is equal to the value respectively:
Usage: required_if=Field1 foo Field2 bar
验证中的字段必须存在且不能为空,除非所有其他指定字段都等于指定字段后面的值。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required_unless
Examples:
// require the field unless the Field1 is equal to the parameter given:
Usage: required_unless=Field1 foobar
// require the field unless the Field1 and Field2 is equal to the value respectively:
Usage: required_unless=Field1 foo Field2 bar
仅当存在任何其他指定字段时,验证中的字段必须存在且不能为空。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required_with
Examples:
// require the field if the Field1 is present:
Usage: required_with=Field1
// require the field if the Field1 or Field2 is present:
Usage: required_with=Field1 Field2
仅当所有其他指定字段都存在时,验证中的字段必须存在且不能为空。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required_with_all
Example:
// require the field if the Field1 and Field2 is present:
Usage: required_with_all=Field1 Field2
The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is not “”. For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil.
Usage: required_without
Examples:
// require the field if the Field1 is not present:
Usage: required_without=Field1
// require the field if the Field1 or Field2 is not present:
Usage: required_without=Field1 Field2
仅当任何其他指定字段不存在时,验证中的字段必须存在且不能为空。对于字符串,确保值不是“”。对于切片、映射、指针、接口、通道和函数,确保该值不为零。
Usage: required_without_all
Example:
// require the field if the Field1 and Field2 is not present:
Usage: required_without_all=Field1 Field2
这验证了该值是默认值并且几乎与 required 相反。
Usage: isdefault
对于数字,长度将确保该值等于给定的参数。对于字符串,它会检查字符串长度是否正好是该字符数。对于切片、数组和映射,验证项目数。
Example #1
Usage: len=10
Example #2 (time.Duration)
For time.Duration, len will ensure that the value is equal to the duration given in the parameter.
Usage: len=1h30m
对于数字,max 将确保该值小于或等于给定的参数。对于字符串,它会检查字符串长度是否最多为该字符数。对于切片、数组和映射,验证项目数。
Example #1
Usage: max=10
Example #2 (time.Duration)
For time.Duration, max will ensure that the value is less than or equal to the duration given in the parameter.
Usage: max=1h30m
对于数字,min 将确保该值大于或等于给定的参数。对于字符串,它检查字符串长度是否至少为该字符数。对于切片、数组和映射,验证项目数。
Example #1
Usage: min=10
Example #2 (time.Duration)
For time.Duration, min will ensure that the value is greater than or equal to the duration given in the parameter.
Usage: min=1h30m
对于字符串和数字,eq 将确保该值等于给定的参数。对于切片、数组和映射,验证项目数。
Example #1
Usage: eq=10
Example #2 (time.Duration)
For time.Duration, eq will ensure that the value is equal to the duration given in the parameter.
Usage: eq=1h30m
对于字符串和数字, ne 将确保该值不等于给定的参数。对于切片、数组和映射,验证项目数。
Example #1
Usage: ne=10
Example #2 (time.Duration)
For time.Duration, ne will ensure that the value is not equal to the duration given in the parameter.
Usage: ne=1h30m
对于字符串、整数和 uint,oneof 将确保该值是参数中的值之一。该参数应该是由空格分隔的值列表。值可以是字符串或数字。要匹配带有空格的字符串,请在单引号之间包含目标字符串。
Usage: oneof=red green
oneof='red green' 'blue yellow'
oneof=5 7 9
对于数字,这将确保该值大于给定的参数。对于字符串,它检查字符串长度是否大于该字符数。对于切片、数组和映射,它验证项目数。
Example #1
Usage: gt=10
Example #2 (time.Time)
For time.Time ensures the time value is greater than time.Now.UTC().
Usage: gt
Example #3 (time.Duration)
For time.Duration, gt will ensure that the value is greater than the duration given in the parameter.
Usage: gt=1h30m
与上面的“min”相同。保留两者以使带有“len”的术语更容易。
Example #1
Usage: gte=10
Example #2 (time.Time)
For time.Time ensures the time value is greater than or equal to time.Now.UTC().
Usage: gte
Example #3 (time.Duration)
For time.Duration, gte will ensure that the value is greater than or equal to the duration given in the parameter.
Usage: gte=1h30m
对于数字,这将确保该值小于给定的参数。对于字符串,它检查字符串长度是否小于该字符数。对于切片、数组和映射,它验证项目数。
Example #1
Usage: lt=10
Example #2 (time.Time)
For time.Time ensures the time value is less than time.Now.UTC().
Usage: lt
Example #3 (time.Duration)
For time.Duration, lt will ensure that the value is less than the duration given in the parameter.
Usage: lt=1h30m
与上面的“max”相同。保留两者以使带有“len”的术语更容易。
Example #1
Usage: lte=10
Example #2 (time.Time)
For time.Time ensures the time value is less than or equal to time.Now.UTC().
Usage: lte
Example #3 (time.Duration)
For time.Duration, lte will ensure that the value is less than or equal to the duration given in the parameter.
Usage: lte=1h30m
这将根据结构中或传入字段中的另一个字段值验证字段值。
Example #1:
// Validation on Password field using:
Usage: eqfield=ConfirmPassword
Example #2:
// Validating by field:
validate.VarWithValue(password, confirmpassword, "eqfield")
Field Equals Another Field (relative)
This does the same as eqfield except that it validates the field provided relative to the top level struct.
Usage: eqcsfield=InnerStructField.Field)
这将根据结构中或传入字段中的另一个字段值验证字段值。
Examples:
// Confirm two colors are not the same:
//
// Validation on Color field:
Usage: nefield=Color2
// Validating by field:
validate.VarWithValue(color1, color2, "nefield")
Field Does Not Equal Another Field (relative)
This does the same as nefield except that it validates the field provided relative to the top level struct.
Usage: necsfield=InnerStructField.Field
仅对 Numbers、time.Duration 和 time.Time 类型有效,这将根据结构中或传入字段中的另一个字段值验证字段值。使用示例用于验证开始和结束日期:
Example #1:
// Validation on End field using:
validate.Struct Usage(gtfield=Start)
Example #2:
// Validating by field:
validate.VarWithValue(start, end, "gtfield")
这与 gtfield 的作用相同,除了它验证相对于顶级结构提供的字段。
Usage: gtcsfield=InnerStructField.Field
仅对 Numbers、time.Duration 和 time.Time 类型有效,这将根据结构中或传入字段中的另一个字段值验证字段值。使用示例用于验证开始和结束日期:
Example #1:
// Validation on End field using:
validate.Struct Usage(gtefield=Start)
Example #2:
// Validating by field:
validate.VarWithValue(start, end, "gtefield")
各个字段违反了什么约束,一眼我们便能从错误信息中看出来。看完了简单示例,下面我就来看一看都有哪些tag,我们都可以怎么使用。本文不介绍所有的tag,更多使用方法,请到官方文档自行学习。
字符串约束
excludesall:不包含参数中任意的 UNICODE 字符,例如excludesall=ab;
excludesrune:不包含参数表示的 rune 字符,excludesrune=asong;
startswith:以参数子串为前缀,例如startswith=hi;
endswith:以参数子串为后缀,例如endswith=bye。
contains=:包含参数子串,例如contains=email;
containsany:包含参数中任意的 UNICODE 字符,例如containsany=ab;
containsrune:包含参数表示的 rune 字符,例如`containsrune=asong;
excludes:不包含参数子串,例如excludes=email;
范围约束
范围约束的字段类型分为三种:
对于数值,我们则可以约束其值
对于切片、数组和map,我们则可以约束其长度
对于字符串,我们则可以约束其长度
常用tag介绍:
ne:不等于参数值,例如 ne=5;
gt:大于参数值,例如 gt=5;
gte:大于等于参数值,例如 gte=50;
lt:小于参数值,例如 lt=50;
lte:小于等于参数值,例如 lte=50;
oneof:只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,例如 oneof=male female。
eq:等于参数值,注意与 len不同。对于字符串, eq约束字符串本身的值,而 len约束字符串长度。例如 eq=10;
len:等于参数值,例如 len=10;
max:小于等于参数值,例如 max=10;
min:大于等于参数值,例如 min=10
Fields约束
eqfield:定义字段间的相等约束,用于约束同一结构体中的字段。例如: eqfield=Password
eqcsfield:约束统一结构体中字段等于另一个字段(相对),确认密码时可以使用,例如: eqfiel=ConfirmPassword
nefield:用来约束两个字段是否相同,确认两种颜色是否一致时可以使用,例如: nefield=Color1
necsfield:约束两个字段是否相同(相对)
常用约束
unique:指定唯一性约束,不同类型处理不同:
对于map,unique约束没有重复的值
对于数组和切片,unique没有重复的值
对于元素类型为结构体的碎片,unique约束结构体对象的某个字段不重复,使用 unique=field指定字段名
email:使用email来限制字段必须是邮件形式,直接写eamil即可,无需加任何指定。
omitempty:字段未设置,则忽略
-:跳过该字段,不检验;
|:使用多个约束,只需要满足其中一个,例如rgb|rgba;
required:字段必须设置,不能为默认值;
好啦,就介绍这些常用的约束,更多约束学习请到文档自行学习吧,都有example供你学习,很快的。
gin中的参数校验
学习了validator,我们也就知道了怎么在gin中使用参数校验了。这些约束是都没有变的,在validator中,我们直接结构体中将约束放到validate tag中,同样道理,在gin中我们只需将约束放到bindingtag中就可以了。是不是很简单。
但是有些时候,并不是所有的参数校验都能满足我们的需求,所以我们可以定义自己的约束。自定义约束支持自定义结构体校验、自定义字段校验等。这里来介绍一下自定义结构体校验。
// -*- coding: utf-8 -*-
//@Time : 2021/8/12 9:45
//@Author : xizheng
package validator
import (
"fmt"
"github.com/go-playground/locales/zh_Hans_CN"
unTrans "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zhTrans "github.com/go-playground/validator/v10/translations/zh"
"reflect"
//"reflect"
"yang_blog/utils/errmsg"
)
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"` === ===
Password string `gorm:"type:varchar(500);not null" json:"password" validate:"required,min=6,max=120" label:"密码"`
Role int `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色码"`
}
//若不知道传进来的是什么参数,需要进行断言操作,输出的字符信息 和 状态码
func Validate(data interface{}) (string, int) { //全局的公共验证
validate := validator.New() //validator 实例化
uni := unTrans.New(zh_Hans_CN.New()) // 翻译 实例化
trans, _ := uni.GetTranslator("zh_Hans_CN") // 中文翻译方法
err := zhTrans.RegisterDefaultTranslations(validate, trans) // 注册默认的翻译方法
if err != nil {
fmt.Println("err", err)
}
validate.RegisterTagNameFunc(func(field reflect.StructField) string { //解析字符 标签映射 提供的方法
label := field.Tag.Get("label")
return label
})
//此处需要断言,但我们已经
err = validate.Struct(data)
if err != nil {
for _, v := range err.(validator.ValidationErrors) {
return v.Translate(trans), errmsg.ERROR
}
}
return "", errmsg.SUCCESS
}
idate := validator.New() //validator 实例化
uni := unTrans.New(zh_Hans_CN.New()) // 翻译 实例化
trans, _ := uni.GetTranslator(“zh_Hans_CN”) // 中文翻译方法
err := zhTrans.RegisterDefaultTranslations(validate, trans) // 注册默认的翻译方法
if err != nil {
fmt.Println("err", err)
}
validate.RegisterTagNameFunc(func(field reflect.StructField) string { //解析字符 标签映射 提供的方法
label := field.Tag.Get("label")
return label
})
//此处需要断言,但我们已经
err = validate.Struct(data)
if err != nil {
for _, v := range err.(validator.ValidationErrors) {
return v.Translate(trans), errmsg.ERROR
}
}
return "", errmsg.SUCCESS
}
![image-20210823112342214](https://img-blog.csdnimg.cn/img_convert/a402e75d3f5290ae930656c5c8ef9b10.png)