Golang Validator使用详解

目录

简介

获取包

代码中使用

初始化

对于普通字段进行验证

对结构体进行验证

对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关键字可以实现任意层级的验证逻辑。

对map进行验证

使用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)
	}

Dive关键字

对于前一个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相关字段

关键字
含义
举例

Required

该字段不能为默认值

数值类型不能为零,string类型不能为空字符串,slices, maps, pointers, interfaces, channels, functions这些类型不能为nil

 
Required_if
当依赖字段为特定值时,该字段不能为默认值
// 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
 
Required_unless
与Required_if含义相反
// 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
 
required_with
当依赖字段出现时,该字段不能为默认值
// 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
 
required_with_all
当依赖字段全部出现时,该字段不能为默认值
// require the field if the Field1 and Field2 is present:
Usage: required_with_all=Field1 Field2
 
required_without
与required_with相反
 
required_without_all
与required_with_all相反
 

相关文档

https://pkg.go.dev/github.com/go-playground/validator/v10#hdr-Custom_Validation_Functions

你可能感兴趣的:(golang常用库)