项目地址: github.com/go-playground/validator/v10
标记
标记说明
例
required
必填
Field或Struct validate:”required”
omitempty
空时忽略
Field或Struct validate:”omitempty”
len
长度
Field validate:”len=0”
eq
等于
Field validate:”eq=0”
gt
大于
Field validate:”gt=0”
gte
大于等于
Field validate:”gte=0”
lt
小于
Field validate:”lt=0”
lte
小于等于
Field validate:”lte=0”
eqfield
同一结构体字段相等
Field validate:”eqfield=Field2”
nefield
同一结构体字段不相等
Field validate:”nefield=Field2”
gtfield
大于同一结构体字段
Field validate:”gtfield=Field2”
gtefield
大于等于同一结构体字段
Field validate:”gtefield=Field2”
ltfield
小于同一结构体字段
Field validate:”ltfield=Field2”
ltefield
小于等于同一结构体字段
Field validate:”ltefield=Field2”
eqcsfield
跨不同结构体字段相等
Struct1.Field validate:”eqcsfield=Struct2.Field2”
necsfield
跨不同结构体字段不相等
Struct1.Field validate:”necsfield=Struct2.Field2”
gtcsfield
大于跨不同结构体字段
Struct1.Field validate:”gtcsfield=Struct2.Field2”
gtecsfield
大于等于跨不同结构体字段
Struct1.Field validate:”gtecsfield=Struct2.Field2”
ltcsfield
小于跨不同结构体字段
Struct1.Field validate:”ltcsfield=Struct2.Field2”
ltecsfield
小于等于跨不同结构体字段
Struct1.Field validate:”ltecsfield=Struct2.Field2”
min
最大值
Field validate:”min=1”
max
最小值
Field validate:”max=2”
structonly
仅验证结构体,不验证任何结构体字段
Struct validate:”structonly”
nostructlevel
不运行任何结构级别的验证
Struct validate:”nostructlevel”
dive
向下延伸验证,多层向下需要多个dive标记
[][]string validate:”gt=0,dive,len=1,dive,required”
dive Keys & EndKeys
与dive同时使用,用于对map对象的键的和值的验证,keys为键,endkeys为值
map[string]string validate:”gt=0,dive,keys,eq=1|eq=2,endkeys,required”
required_with
其他字段其中一个不为空且当前字段不为空
Field validate:”required_with=Field1 Field2”
required_with_all
其他所有字段不为空且当前字段不为空
Field validate:”required_with_all=Field1 Field2”
required_without
其他字段其中一个为空且当前字段不为空
Field `validate:”required_without=Field1 Field2”
required_without_all
其他所有字段为空且当前字段不为空
Field validate:”required_without_all=Field1 Field2”
isdefault
是默认值
Field validate:”isdefault=0”
oneof
其中之一
Field validate:”oneof=5 7 9”
containsfield
字段包含另一个字段
Field validate:”containsfield=Field2”
excludesfield
字段不包含另一个字段
Field validate:”excludesfield=Field2”
unique
是否唯一,通常用于切片或结构体
Field validate:”unique”
alphanum
字符串值是否只包含 ASCII 字母数字字符
Field validate:”alphanum”
alphaunicode
字符串值是否只包含 unicode 字符
Field validate:”alphaunicode”
alphanumunicode
字符串值是否只包含 unicode 字母数字字符
Field validate:”alphanumunicode”
numeric
字符串值是否包含基本的数值
Field validate:”numeric”
hexadecimal
字符串值是否包含有效的十六进制
Field validate:”hexadecimal”
hexcolor
字符串值是否包含有效的十六进制颜色
Field validate:”hexcolor”
lowercase
符串值是否只包含小写字符
Field validate:”lowercase”
uppercase
符串值是否只包含大写字符
Field validate:”uppercase”
email
字符串值包含一个有效的电子邮件
Field validate:”email”
json
字符串值是否为有效的 JSON
Field validate:”json”
file
符串值是否包含有效的文件路径,以及该文件是否存在于计算机上
Field validate:”file”
url
符串值是否包含有效的 url
Field validate:”url”
uri
符串值是否包含有效的 uri
Field validate:”uri”
base64
字符串值是否包含有效的 base64值
Field validate:”base64”
contains
字符串值包含子字符串值
Field validate:”contains=@”
containsany
字符串值包含子字符串值中的任何字符
Field validate:”containsany=abc”
containsrune
字符串值包含提供的特殊符号值
Field validate:”containsrune=☢”
excludes
字符串值不包含子字符串值
Field validate:”excludes=@”
excludesall
字符串值不包含任何子字符串值
Field validate:”excludesall=abc”
excludesrune
字符串值不包含提供的特殊符号值
Field validate:”containsrune=☢”
startswith
字符串以提供的字符串值开始
Field validate:”startswith=abc”
endswith
字符串以提供的字符串值结束
Field validate:”endswith=abc”
ip
字符串值是否包含有效的 IP 地址
Field validate:”ip”
ipv4
字符串值是否包含有效的 ipv4地址
Field validate:”ipv4”
datetime
字符串值是否包含有效的 日期
Field validate:”datetime”
单字段校验
模拟对前端传参进行校验
单字段多个条件 校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package mainimport ( "fmt" "strings" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" zhtrans "github.com/go-playground/validator/v10/translations/zh" ) type Student struct { Name string `validate:required` Email string `validate:"email"` Age int `validate:"max=30,min=12"` } func main () { en := en.New() zh := zh.New() uni := ut.New(en, zh) trans, _ := uni.GetTranslator("zh" ) student := Student{ Name: "tom" , Email: "testemal" , Age: 40 , } validate := validator.New() zhtrans.RegisterDefaultTranslations(validate, trans) err := validate.Struct(student) if err != nil { errs := err.(validator.ValidationErrors) fmt.Println(removeStructName(errs.Translate(trans))) } } func removeStructName (fields map [string ]string ) map [string ]string { result := map [string ]string {} for field, err := range fields { result[field[strings.Index(field, "." )+1 :]] = err } return result }
在线代码
输出:
map[Age:Age必须小于或等于30 Email:Email必须是一个有效的邮箱]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { FirstName string `validate:"required"` LastName string `validate:"required"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` Test string `validate:"len=0|min=6,max=24,len=0|alphanum"` Products []CreateOrderProduct `validate:"min=1"` } type CreateOrderProduct struct { SkuCode string `json:"skuCode"` Quantity int64 `json:"quantity"` } func main () { user := &User{ FirstName: "Badger" , LastName: "Smith" , Age: 115 , Email: "Badger.Smith@gmail.com" , Test: "" , Products: []CreateOrderProduct{}, } validate := validator.New() err := validate.Struct(user) if err != nil { fmt.Println("=== error msg ====" ) fmt.Println(err) return } }
在线代码
输出:
1 2 === error msg ==== Key: 'User.Products' Error:Field validation for 'Products' failed on the 'min' tag
跨字段验证
eqfield 同一结构体字段验证相等
eqfield=Field:必须等于 Field 的值
最常见的就是输入2次密码验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type Account struct { Name string `validate:"lte=16"` Age int `validate:"min=20"` Password string `validate:"min=8"` Password2 string `validate:"eqfield=Password"` } func main () { account := &Account{ Name: "Badger" , Age: 115 , Password: "qwert12345" , Password2: "111111" , } validate := validator.New() err := validate.Struct(account) if err != nil { fmt.Println("=== error msg ====" ) fmt.Println(err) if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } fmt.Println("\r\n=========== error field info ====================" ) for _, err := range err.(validator.ValidationErrors) { fmt.Println("Namespace: " , err.Namespace()) fmt.Println("Fild: " , err.Field()) fmt.Println("StructNamespace: " , err.StructNamespace()) fmt.Println("StructField: " , err.StructField()) fmt.Println("Tag: " , err.Tag()) fmt.Println("ActualTag: " , err.ActualTag()) fmt.Println("Kind: " , err.Kind()) fmt.Println("Type: " , err.Type()) fmt.Println("Value: " , err.Value()) fmt.Println("Param: " , err.Param()) fmt.Println() } return } }
在线运行
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 === error msg ==== Key: 'Account.Password2' Error:Field validation for 'Password2' failed on the 'eqfield' tag =========== error field info ==================== Namespace: Account.Password2 Fild: Password2 StructNamespace: Account.Password2 StructField: Password2 Tag: eqfield ActualTag: eqfield Kind: string Type: string Value: 111111 Param: Password
nefield:同一结构体字段验证不相等
nefield=Field:必须不等于 Field 的值
例如,验证密码不能和用户名相同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type Account struct { Name string `validate:"lte=16"` Age int `validate:"min=20"` Password string `validate:"min=1,nefield=Name"` } func main () { account := &Account{ Name: "Badger" , Age: 115 , Password: "Badger" , } validate := validator.New() err := validate.Struct(account) if err != nil { fmt.Println("=== error msg ====" ) fmt.Println(err) if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } fmt.Println("\r\n=========== error field info ====================" ) for _, err := range err.(validator.ValidationErrors) { fmt.Println("Namespace: " , err.Namespace()) fmt.Println("Fild: " , err.Field()) fmt.Println("StructNamespace: " , err.StructNamespace()) fmt.Println("StructField: " , err.StructField()) fmt.Println("Tag: " , err.Tag()) fmt.Println("ActualTag: " , err.ActualTag()) fmt.Println("Kind: " , err.Kind()) fmt.Println("Type: " , err.Type()) fmt.Println("Value: " , err.Value()) fmt.Println("Param: " , err.Param()) fmt.Println() } return } }
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 === error msg ==== Key: 'Account.Password' Error:Field validation for 'Password' failed on the 'nefield' tag =========== error field info ==================== Namespace: Account.Password Fild: Password StructNamespace: Account.Password StructField: Password Tag: nefield ActualTag: nefield Kind: string Type: string Value: Badger Param: Name
类似的还有
gtfield=Field:必须大于 Field 的值。
gtefield=Field: 必须大于等于 Field 的值。
ltfield=Field:必须小于 Field 的值。
ltefield=Field:必须小于等于 Field 的值。
eqcsfield=Other.Field:必须等于 struct Other 中 Field 的值。
用于验证跨结构体的两个字段 是否相等,需要指定另一个字段的名称或路径作为参数,比如 eqcsfield=Other.Field 中的 Other.Field 就是指定的另一个字段。
在使用该选项时,会比较当前字段和指定的另一个字段的值是否相等,如果相等则验证通过,否则验证失败。这个选项通常用于验证密码和确认密码等类似的场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type Struct1 struct { Field1 string `validate:"eqcsfield=Struct2.Field2""` Struct2 struct { Field2 string } } func main () { s := &Struct1{ Field1: "必须一致" , Struct2: struct { Field2 string }{Field2: "没有一致" }, } validate := validator.New() err := validate.Struct(s) if err != nil { fmt.Println("=== error msg ====" ) fmt.Println(err) if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } fmt.Println("\r\n=========== error field info ====================" ) for _, err := range err.(validator.ValidationErrors) { fmt.Println("Namespace: " , err.Namespace()) fmt.Println("Fild: " , err.Field()) fmt.Println("StructNamespace: " , err.StructNamespace()) fmt.Println("StructField: " , err.StructField()) fmt.Println("Tag: " , err.Tag()) fmt.Println("ActualTag: " , err.ActualTag()) fmt.Println("Kind: " , err.Kind()) fmt.Println("Type: " , err.Type()) fmt.Println("Value: " , err.Value()) fmt.Println("Param: " , err.Param()) fmt.Println() } return } }
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 === error msg ==== Key: 'Struct1.Field1' Error:Field validation for 'Field1' failed on the 'eqcsfield' tag =========== error field info ==================== Namespace: Struct1.Field1 Fild: Field1 StructNamespace: Struct1.Field1 StructField: Field1 Tag: eqcsfield ActualTag: eqcsfield Kind: string Type: string Value: 必须一致 Param: Struct2.Field2
看起来只支持嵌套结构体,不支持两个独立的结构体之间某个字段的比较
eqfield 和 eqcsfield 的区别在于它们用于比较的字段的位置不同:eqfield 比较的是同一个结构体中的两个字段的值,而 eqcsfield 比较的是当前结构体中的某个字段和另一个(子?)结构体中的字段的值
类似的还有
necsfield=Other.Field:必须不等于 struct Other 中 Field 的值。
gtcsfield=Other.Field:必须大于 struct Other 中 Field 的值;
gtecsfield=Other.Field:必须大于等于 struct Other 中 Field 的值。
ltcsfield=Other.Field:必须小于 struct Other 中 Field 的值。
ltecsfield=Other.Field:必须小于等于 struct Other 中 Field 的值。
如何比较两个独立结构体中某两个字段的值?
required_with=Field1 Field2:在 Field1 或者 Field2 存在时,必须;required_with=Field2:在 Field2被填写(即不为空)时,Field1也必须不能为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { Name string `validate:"required"` Email string `validate:"required_with=Phone"` Phone string } func main () { user1 := User{ Name: "John" , Email: "" , Phone: "" , } user2 := User{ Name: "Mary" , Email: "mary@example.com" , Phone: "" , } validate := validator.New() err1 := validate.Struct(user1) if err1 != nil { fmt.Println(err1) } err2 := validate.Struct(user2) if err2 != nil { fmt.Println(err2) } }
验证通过~
在这个例子中,User 结构体包含 Name、Email 和 Phone 字段。Email 字段被标记为 required_with=Phone,这意味着当 Phone 字段被填写时,Email 字段也必须被填写。
而如果把user1改为:
1 2 3 4 5 user1 := User{ Name: "John" , Email: "" , Phone: "123" , }
则会报错:
1 Key: 'User.Email' Error:Field validation for 'Email' failed on the 'required_with' tag
验证不通过
required_with_all=Field1 Field2:在 Field1 与 Field2 都存在时,必须;(仅当所有其他指定的字段都存在时,验证字段才必须存在)
要么有这个tag的全部为空,如果有一个不为空,那所有其他的也都不能为空~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User6 struct { Name string `validate:"required"` Email string `validate:"required_with_all=Phone"` Phone string `validate:"required_with_all=Email"` } func main () { user := User6{ Name: "John" , Email: "" , Phone: "" , } validate := validator.New() err := validate.Struct(user) if err != nil { fmt.Println(err) } }
Email 和 Phone 字段都被标记为 required_with_all,
这意味着当 Email 和 Phone
所以上面代码可以验证通过
如下也是合法的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User6 struct { Name string `validate:"required"` Email string `validate:"required_with_all=Phone"` Phone string `validate:"required_with_all=Email"` } func main () { user := User6{ Name: "John" , Email: "1" , Phone: "2" , } validate := validator.New() err := validate.Struct(user) if err != nil { fmt.Println(err) } }
类似的还有:
required_without=Field1 Field2:在 Field1 或者 Field2 不存在时,必须; Field1 Field2字段其中(至少)一个为空,则当前字段不能为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { Name string `validate:"required"` Email string Phone string Address string `validate:"required_without=Email Phone"` } func main () { user1 := User{ Name: "John" , Email: "" , Phone: "" , Address: "123 Main St." , } user2 := User{ Name: "Mary" , Email: "mary@example.com" , Phone: "" , Address: "" , } validate := validator.New() err1 := validate.Struct(user1) if err1 != nil { fmt.Println("err1:" , err1) } err2 := validate.Struct(user2) if err2 != nil { fmt.Println("err2:" , err2) } }
输出:
1 err2: Key: 'User7.Address' Error:Field validation for 'Address' failed on the 'required_without' tag
User 结构体包含 Name、Email、Phone 和 Address 字段。Address 字段被标记为 required_without=Email Phone,这意味着当 Email 和 Phone 字段至少一个为空时,Address 字段必须被填写。
required_without_all=Field1 Field2:在 Field1 与 Field2 都存在时,必须; (仅当所有其他指定字段都不存在时,验证字段才必须…)
Field1 Field2字段都为空时,则当前字段不能为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User7 struct { Name string `validate:"required"` Email string Phone string Address string `validate:"required_without_all=Email Phone"` } func main () { user1 := User7{ Name: "John" , Email: "" , Phone: "111" , Address: "123 Main St." , } user2 := User7{ Name: "Mary" , Email: "" , Phone: "" , Address: "" , } validate := validator.New() err1 := validate.Struct(user1) if err1 != nil { fmt.Println("err1:" , err1) } err2 := validate.Struct(user2) if err2 != nil { fmt.Println("err2:" , err2) } }
输出:
1 err2: Key: 'User7.Address' Error:Field validation for 'Address' failed on the 'required_without_all' tag
验证proto 可参考 Go gRPC进阶-proto数据验证(九)
更复杂的判断
1 2 3 4 5 6 type User struct {Age uint8 validate:"gte=0,lte=130" Email string validate:"required,email" Score int validate:"min=1" Gender string validate:"required,oneof=男 女" }
如果满足以下任意一项则认为通过:
Gender=男,Age小于35,Score大于60
Gender=女,Age小于40,Score大于50
这种用validator/v10能判断吗?..
这种复杂的验证规则超出了validator/v10的基本功能,需要进行自定义验证函数。可以使用validator/v10的Func函数,通过编写自定义的验证函数来实现这种验证规则。
如下是一个示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package mainimport ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { Age uint8 `validate:"gte=0,lte=130,customValidation"` Email string `validate:"required,email"` Score int `validate:"required,gte=0,customValidation"` Gender string `validate:"required,oneof=男 女,customValidation"` } func validateUser (fl validator.FieldLevel) bool { user, ok := fl.Top().Interface().(*User) fmt.Println("user is:" , user) if !ok { return false } if user.Gender == "男" && user.Age < 35 && user.Score > 60 { return true } if user.Gender == "女" && user.Age < 40 && user.Score > 50 { return true } return false } func main () { user := &User{ Age: 36 , Email: "example@gmail.com" , Score: 1711 , Gender: "男" , } validate := validator.New() err := validate.RegisterValidation("customValidation" , validateUser) if err != nil { fmt.Println(err) return } err = validate.Struct(user) fmt.Println("err is:" , err) if err != nil { fmt.Println(err) return } fmt.Println("validation succeeded" ) }
输出:
1 2 3 4 5 6 7 8 9 user is: &{36 example@gmail.com 1711 男} user is: &{36 example@gmail.com 1711 男} user is: &{36 example@gmail.com 1711 男} err is: Key: 'User.Age' Error:Field validation for 'Age' failed on the 'customValidation' tag Key: 'User.Score' Error:Field validation for 'Score' failed on the 'customValidation' tag Key: 'User.Gender' Error:Field validation for 'Gender' failed on the 'customValidation' tag Key: 'User.Age' Error:Field validation for 'Age' failed on the 'customValidation' tag Key: 'User.Score' Error:Field validation for 'Score' failed on the 'customValidation' tag Key: 'User.Gender' Error:Field validation for 'Gender' failed on the 'customValidation' tag
参考资料:
golang之验证器validator
【Go】数据验证-validator
Go 使用validator进行后端数据校验
gopkg.in/go-playground/validator.v10
结构字段验证--validator.v9
Golang验证器之validator使用详解
Go 每日一库之 validator
golang常用库:字段参数验证库-validator使用
有空还想探究下,这么一个工具怎么可以讲这么多期..
B站视频:论一款强大的验证组件在web开发中的重要性
B站视频:go语言验证框架Validator的6种高端操作
B站视频:go开源验证框架validator必会的3个操作
B站视频:validator验证框架3种自定义验证方法
B站视频:validator快速实现字段格式的验证
B站视频:validator快速搞定字段格式验证
B站视频:validator自定义验证与本地化提示
原文链接: https://dashen.tech/2020/03/11/Go中最常用的数据验证库/
版权声明: 转载请注明出处.