目录
简介
获取包
代码中使用
初始化
对于普通字段进行验证
对结构体进行验证
对map进行验证
Dive关键字
对自定义类型进行验证
其它关键字
字段间的比较
required相关字段
相关文档
目前项目中有大量的地方需要对用户请求或者配置平台传过来的参数进行合法性验证,通常我们是自己来写这些验证函数。如果参数较少还好说,否者这种做法需要写大量的代码进行参数验证。之前了解过gin框架有使用validator包做过类似的验证工作,因此把它引入到我们项目中。
获取包
go get github.com/go-playground/validator/v10
import "github.com/go-playground/validator/v10"
var validate *validator.Validate
validate = validator.New()
validator.Validate是线程安全的,其变量内会缓存已经验证过结构体的特征,因此用户用一个变量更有利于提高效率
使用validate.Var函数
case1:
var i int
validate.Var(i, "gt=1,lt=10") // 只有i的值在区间(1,10)内才满足判断条件(gt=greater than, lt=less than)
case2:
myEmail := "joeybloggs.gmail.com"
errs := validate.Var(myEmail, "required,email") // 只有myEmail满足email地址格式才符合
它返回的err信息也较清晰
Key: '' Error:Field validation for '' failed on the 'email' tag
使用validate.Struct函数
case1:
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
required关键字表示该字段不能为默认值,否则报错
case2:
type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"iscolor"`
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
gte = greater than or equal to, lte = less than or equal to
Iscolor alias for 'hexcolor|rgb|rgba|hsl|hsla'
对于数组Addresses, required表示其值不能为nil,但可以是{}。如果需要对于数组的个数进行限制,同样可以使用lt,gt等数值比较的关键字。Dive关键字表示对数组里的元素进行验证,如果数组内的元素也是一个struct,需要在该struct中写明验证规则。通过dive关键字可以实现任意层级的验证逻辑。
使用validate.ValidateMap函数
case1:
user := map[string]interface{}{"name": "Arshiya Kiani", "email": "[email protected]"}
rules := map[string]interface{}{"name": "required,min=8,max=32", "email": "omitempty,required,email"}
errs := validate.ValidateMap(user, rules)
和数组一样,对于string类型,min和max关键字表示的是长度值;omitempty关键字表示如果为空则不进行验证。
case2:
data := map[string]interface{}{
"name": "Arshiya Kiani",
"email": "[email protected]",
"details": map[string]interface{}{
"family_members": map[string]interface{}{
"father_name": "Micheal",
"mother_name": "Hannah",
},
"salary": "1000",
},
}
rules := map[string]interface{}{
"name": "min=4,max=32",
"email": "required,email",
"details": map[string]interface{}{
"family_members": map[string]interface{}{
"father_name": "required,min=4,max=32",
"mother_name": "required,min=4,max=32",
},
"salary": "number",
},
}
if errs := validate.ValidateMap(data, rules); len(errs) != 0 {
fmt.Println(errs)
}
对于前一个map中介绍的情况,我们是对已知的key进行验证;对于未知的key同样可以进行验证,如下:
type Test struct {
Array []string `validate:"required,gt=0,dive,required"`
Map map[string]string `validate:"required,gt=0,dive,keys,keymax,endkeys,required,max=1000"`
}
validate.RegisterAlias("keymax", "max=10")
对于Array,第一个required作用在[]string,表示它不能为nil,gt=0表示元素的个数大于零,dive表示下沉验证每个string元素,第二个required表示单个string元素不能为空;
对于Map,第一个required表示整个map不能为nil,gt=0表示map元素的个数大于0,dive下沉到每对key,val pair里,keys和endkeys是对pair中的key进行验证,我们使用validate.RegisterAlias函数对于验证公式keymax起了一个别名,它等价于max=10,表示key的长度不能超过10byte,第二个required后面的max=1000表示pair中val的最大长度为1000byte。
这种情况,通常不是对于单个字段进行验证,而是对于整个类型进行验证(复合条件)
type DbBackedUser struct {
Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"`
}
validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
x := DbBackedUser{Name: sql.NullString{String: "123", Valid: true}, Age: sql.NullInt64{Int64: 1, Valid: true}}
err := validate.Struct(x)
func ValidateValuer(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value()
if err == nil {
return val
}
// handle the error how you want
}
return nil
}
使用validate.RegisterCustomTypeFunc对于自定义类型进行注册,其中第一个参数为验证函数,后面的参数为自定义类型。
eqcsfield Field Equals Another Field (relative)
eqfield Field Equals Another Field
fieldcontains NOT DOCUMENTED IN doc.go
fieldexcludes NOT DOCUMENTED IN doc.go
gtcsfield Field Greater Than Another Relative Field
gtecsfield Field Greater Than or Equal To Another Relative Field
gtefield Field Greater Than or Equal To Another Field
gtfield Field Greater Than Another Field
ltcsfield Less Than Another Relative Field
ltecsfield Less Than or Equal To Another Relative Field
ltefield Less Than or Equal To Another Field
ltfield Less Than Another Field
necsfield Field Does Not Equal Another Field (relative)
nefield Field Does Not Equal Another Field
以eqcsfield和eqfield为例,eqfield只会去同一个level中寻找比较字段(这样效率更高),eqcsfield可以去下级level中寻找比较字段
|
|
|
Required |
|
数值类型不能为零,string类型不能为空字符串,slices, maps, pointers, interfaces, channels, functions这些类型不能为nil |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
https://pkg.go.dev/github.com/go-playground/validator/v10#hdr-Custom_Validation_Functions