- InvalidValidationError">type InvalidValidationError
- ValidationErrors">type ValidationErrors
- FieldError">type FieldError
- FieldLevel">type FieldLevel
- StructLevel">type StructLevel
- Func">type Func
- FuncCtx">type FuncCtx
- StructLevelFunc">type StructLevelFunc
- StructLevelFuncCtx">type StructLevelFuncCtx
- Validate">type Validate
- 用法
- 例一:基本使用
- 例二:自定义字段(验证字段)
- 例三:自定义字段(验证结构体一)
- 例四:自定义字段(验证结构体二)
- 例五:输出中文错误提示
- 例六:自定义错误
- 例七:利用反射自定义错误信息
- 例八:嵌套验证错误自定义
项目地址:https://github.com/go-playground/validator
gin使用的验证器
type InvalidValidationError
无效验证错误,该错误很少去判断
type InvalidValidationError struct {
Type reflect.Type
}
type ValidationErrors
验证错误信息数组
type ValidationErrors []FieldError
type FieldError
type FieldError interface {
// 返回验证失败的标签
// eg. alias "iscolor",will return "iscolor"
Tag() string
// 返回验证失败的真实标签
// eg. alias "iscolor",will return "hexcolor|rgb|rgba|hsl|hsla"
ActualTag() string
// 返回验证失败的 结构体.字段
// 当使用validate.Field(...)进行验证是,会返回空
Namespace() string
// 返回验证失败的 结构体.字段
// 当使用validate.Field(...)进行验证是,会返回空
StructNamespace() string
// 返回验证失败的字段
Field() string
// 返回验证失败的字段
StructField() string
// 返回验证失败的值
Value() interface{}
// 给一个正确的值作为参考
Param() string
// Kind returns the Field's reflect Kind
Kind() reflect.Kind
// Type returns the Field's reflect Type
Type() reflect.Type
}
type FieldLevel
type FieldLevel interface {
// 返回第一层结构体
Top() reflect.Value
// 返回当前字段的父结构体
Parent() reflect.Value
// 返回当前字段的值
Field() reflect.Value
// 返回当前字段名
FieldName() string
// 返回当前字段名(真实)
StructFieldName() string
// 返回当前字段设定的值
Param() string
}
type StructLevel
type StructLevel interface {
//返回主验证对象
Validator() *Validate
// 返回第一层结构体
Top() reflect.Value
// 返回当前结字段的父结构体
Parent() reflect.Value
// 返回当前结构体
Current() reflect.Value
// 通过传递字段和标记信息来报告错误
ReportError(field interface{}, fieldName, structFieldName string, tag, param string)
}
type Func
Func接受所有验证需求的现场级接口。验证成功时,返回值应该为true。
type Func func(fl FieldLevel) bool
type FuncCtx
type FuncCtx func(ctx context.Context, fl FieldLevel) bool
type StructLevelFunc
type StructLevelFunc func(sl StructLevel)
type StructLevelFuncCtx
type StructLevelFuncCtx func(ctx context.Context, sl StructLevel)
type Validate
func New() Validate 返回一个“validate”的新实例
func (v Validate) SetTagName(name string) 更改“validate”的默认标记名
func (v Validate) Struct(s interface{}) error 结构体验证,并验证被嵌套的结构体
func (v Validate) StructCtx(ctx context.Context, s interface{}) (err error)
func (v Validate) Var(field interface{}, tag string) error 验证单个变量
func (v Validate) RegisterValidation(tag string, fn Func, callValidationEvenIfNull …bool) error
- 使用给定的标签添加验证
func (v Validate) RegisterValidationCtx(tag string, fn FuncCtx, callValidationEvenIfNull …bool) error
func (v Validate) RegisterStructValidation(fn StructLevelFunc, types …interface{})
- 为结构体添加验证
func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types …interface{})
用法
- :跳过验证,例 `validate:"-"`,常出现在嵌套验证中
| :或操作,例 `validate:"rbg|rgba"`,接受rbg或rgba类型的值
dive :潜入切片,数组或映射,如果是多维嵌套,那么可以用多个dive,dive...
structonly:不对嵌套结构体中的任何字段进行验证
omitempty :如果是空值,忽略其他的验证,注意放的位置,放在最前面,表示对后面的所有要求生效
required :必须字段
oneof :枚举,`validate:"oneof=1 2"`
required_with_all :当默些字段存在时才验证该字段 例required_with_all = f1 f2
required_without : 当默些字段不存在时才验证该字段 例required_without = f1 f2
len : 对于数字型是==判断,对于其他是length判断 例 len = 5
max : 数字验证最大,其他验证length 例 max = 5
min : 数字验证最小,其他验证length 例 min = 5
eq : 数字与字符串验证==,其他验证length 例 eq = 5
ne : 与eq相反,!=
gt : 大于
gte : 大于等于
lt : 小于
lte : 小于等于
eqfield : 判断该字段是否等于另外一个字段 eqfield=ConfirmPassword
: 或validate.VarWithValue(password, confirmpassword, "eqfield")
nefield : 与eqfield相反
unique : 对于数组和片,unique将确保没有重复。对于映射,unique将确保没有重复的值
numeric : 判断字符类型是否只包含整数或浮点数
hexadecimal :验证字符串值是否包含有效的十六进制
hexcolor : 将验证字符串值是否包含有效的十六进制颜色,包括hashtag (#)
rgb : 验证字符串值是否包含有效的rgb颜色
email : 验证字符串值是否包含有效的电子邮件
json : 验证字符串值是否为json格式
file : 验证字符串值是否包含有效的文件路径
url : 将验证字符串值是否包含有效的url,必须包含一个模式,例如http://或rtmp://
uri : 验证字符串值是否包含有效的uri
base64 : 验证字符串值是否包含有效的base64值
contains : 验证字符串是否包含莫子串 例 contains = a
containsany : 验证字符串是否包含莫子串的任意一个 例 containsany = abc
excludes : 与contains相反,是不包含
excludesall : 与containsany相反,是不包含任意一个
startswith : 验证字符串是否已某个字符串开头
endswith : 结尾
uuid : 判断字符串是否是uuid类型
uuid3
uuid4
uuid5
latitude : 是否包含有效的纬度
longitude : 是否包含有效的经度
ip
ipv4
ipv6
datetime : 字符串值是否包含有效的日期
tcp_addr
tcp4_addr
tcp6_addr
......
例一:基本使用
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// User contains user information
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"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
validateStruct()
validateVariable()
}
func validateStruct() {
address := &Address{
Street: "Eavesdown Docks",
City : "Beijing",
Planet: "Persphone",
Phone: "none",
}
user := &User{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000",
Addresses: []*Address{address},
}
// returns nil or ValidationErrors ( []FieldError )
err := validate.Struct(user)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
fmt.Println(err.Namespace()) //User.Age
fmt.Println(err.Field()) //Age
fmt.Println(err.StructNamespace()) //User.Age
fmt.Println(err.StructField()) //Age
fmt.Println(err.Tag()) //lte
fmt.Println(err.ActualTag()) //lte
fmt.Println(err.Kind()) //uint8
fmt.Println(err.Type()) //uint8
fmt.Println(err.Value()) //135
fmt.Println(err.Param()) //130
}
}
}
func validateVariable() {
myEmail := "joeybloggs.gmail.com"
errs := validate.Var(myEmail, "required,email")
if errs != nil {
fmt.Println(errs) // Key: "" Error:Field validation for "" failed on the "email" tag
return
}
}
例二:自定义字段(验证字段)
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
"time"
)
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
Age int `validate:"min=12,max=15"`
CreateAt time.Time `validate:"required,myParam"` // 日期必须大于2000-01-01
}
func main() {
address := &Address{
Street: "Eavesdown Docks",
City: "beijing",
Planet: "Persphone",
Phone: "none",
Age: 12,
CreateAt : time.Now(),
}
validate := validator.New()
//自己定义tag标签以及与之对应的处理逻辑
validate.RegisterValidation("myParam", mytimeFunc)
//查看是否符合验证
err := validate.Struct(address)
fmt.Println(err)
}
func mytimeFunc(fl validator.FieldLevel) bool {
format:= "2006-01-02"
param,_ :=time.ParseInLocation(format,"2000-01-01",time.Local)
param1,ok:=fl.Field().Interface().(time.Time)
if !ok || param1.Before(param){
return false
}
return true
}
例三:自定义字段(验证结构体一)
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
"time"
)
type Time struct {
CreateTime time.Time `validate:"required,myParam"`
T int
}
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
Age int `validate:"min=12,max=15"`
CreateAt *Time `validate:"required"` // 日期必须大于2000-01-01
}
func main() {
CreateAt := &Time{
CreateTime:time.Now(),
}
address := &Address{
Street: "Eavesdown Docks",
City: "beijing",
Planet: "Persphone",
Phone: "none",
Age: 12,
CreateAt : CreateAt,
}
validate := validator.New()
//自己定义tag标签以及与之对应的处理逻辑
validate.RegisterValidation("myParam", mytimeFunc)
//查看是否符合验证
err := validate.Struct(address)
fmt.Println(err)
}
func mytimeFunc(fl validator.FieldLevel) bool {
format:= "2006-01-02"
param,_ :=time.ParseInLocation(format,"2000-01-01",time.Local)
param1,ok:=fl.Field().Interface().(time.Time)
fmt.Println(fl.FieldName())
if !ok || param1.Before(param){
return false
}
return true
}
例四:自定义字段(验证结构体二)
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
"time"
)
type Time struct {
CreateTime time.Time `validate:"required"`
T int `validate:"required"`
}
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
Age int `validate:"min=12,max=15"`
CreateAt *Time `validate:"required"` // 日期必须大于2000-01-01,T必须<=10
}
func main() {
CreateAt := &Time{
CreateTime:time.Now(),
T:11,
}
address := &Address{
Street: "Eavesdown Docks",
City: "beijing",
Planet: "Persphone",
Phone: "none",
Age: 12,
CreateAt : CreateAt,
}
validate := validator.New()
//自己定义tag标签以及与之对应的处理逻辑
validate.RegisterStructValidation(mytimeFunc, &Time{})
//查看是否符合验证
err := validate.Struct(address)
fmt.Println(err)
}
func mytimeFunc(sl validator.StructLevel){
format:= "2006-01-02"
param,_ :=time.ParseInLocation(format,"2000-01-01",time.Local)
t := sl.Current().Interface().(Time)
if t.T > 10{
sl.ReportError(t.T,"T","T","max","10")
}
if t.CreateTime.Before(param){
sl.ReportError(t.T,"CreateTime","CreateTime","after","2000-01-01")
}
}
例五:输出中文错误提示
import “github.com/go-playground/validator/translations/zh”
该包只有一个对外函数
func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (err error)
ps:在与v10结合时出了问题,拉不下来
.\demo2.go:28:43: cannot use validate (type *"github.com/go-playground/validator/v10".Validate)
as type *"gopkg.in/go-playground/validator.v9".Validate in argument to
"github.com/go-playground/validator/translations/zh".RegisterDefaultTranslations
拉下来后需要改一下源码import的内容,按下面源码改即可
或:因为只有一个文件,把代码copy下来作为一个包(推荐)
https://github.com/go-playground/validator/blob/master/translations/zh/zh.go
package main
import (
"fmt"
"github.com/go-playground/locales/zh"
"github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translater "study/validate/zh"
)
type UserInfo struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=100"`
Email string `validate:"required,email"`
}
func main() {
//中文翻译器
zh_ch := zh.New()
uni := ut.New(zh_ch)
trans, _ := uni.GetTranslator("zh")
//验证器
validate := validator.New()
//验证器注册翻译器
zh_translater.RegisterDefaultTranslations(validate, trans)
user := &UserInfo{
FirstName: "Badger",
LastName: "Smith",
Age: 105,
Email: "",
}
err := validate.Struct(user)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
//翻译错误信息
fmt.Println(err.Translate(trans))
}
return
}
fmt.Println("success")
}
//输出:
Age必须小于或等于100
Email为必填字段
例六:自定义错误
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type UserInfo struct {
Age uint8 `validate:"required,gte=0,lte=100"`
Email string `validate:"required,email"`
}
func (self *UserInfo) GetErrors(errs validator.ValidationErrors) string{
errstr := ""
for _,err :=range errs{
if err.Field() == "Age"{
if err.Tag() == "required"{
errstr += "年龄必填,"
}else if err.Tag() == "gte" || err.Tag() == "lte"{
errstr += "年龄需在0-100之间,"
}
}
if err.Field() == "Email"{
if err.Tag() == "required"{
errstr += "邮箱必填,"
}else if err.Tag() == "email"{
errstr += "邮箱格式错误,"
}
}
}
return errstr
}
func main() {
validate := validator.New()
user := &UserInfo{
Age: 105,
Email: "",
}
err := validate.Struct(user)
if err != nil {
errstr := user.GetErrors(err.(validator.ValidationErrors))//断言
fmt.Println(errstr) //年龄需在0-100之间,邮箱必填,
return
}
fmt.Println("success")
}
例七:利用反射自定义错误信息
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
"reflect"
)
var validate *validator.Validate
type UserInfo struct {
Age uint8 `validate:"required,gte=0,lte=100" message:"年龄需在0-100之间"`
Email string `validate:"required,email" message:"email字段必须为结构体"`
}
func StructToValidate(structInter interface{}) (map[string]string, bool) {
structType := reflect.TypeOf(structInter)
var resultMap map[string]string = map[string]string{}
validErr := validate.Struct(structInter)
if validErr != nil {
for _, err := range validErr.(validator.ValidationErrors) {
field, isOK := structType.FieldByName(err.Field())
if isOK {
// fmt.Println("validmsg------------------------>",field.Tag.Get("validmsg"))
resultMap[err.Field()] = field.Tag.Get("message")
}
}
return resultMap, false
} else {
return nil, true
}
}
func main() {
validate = validator.New()
user := UserInfo{
Age: 105,
Email: "",
}
results, isOK :=StructToValidate(user)
if !isOK{
fmt.Println(results) //map[Age:年龄需在0-100之间 Email:email 字段必须为结构体]
}
}
例八:嵌套验证错误自定义
基于例子七:对结构体嵌结构体有用,对结构体嵌数组等暂时不行
package main
import (
"fmt"
"reflect"
)
type AAAA struct {
Name string `name22:"bbb"`
Age string `name22:"ccc"`
}
type AAA struct {
Aaaa []AAAA `name11:"aaa"`
}
func main() {
var a AAA
at := reflect.TypeOf(a)
field,ok := at.FieldByName("Aaaa")
if ok {
if field.Type.Kind() == reflect.Slice{
tag := field.Type.Elem().Field(0).Tag.Get("name22")
fmt.Println(tag) // bbb
fmt.Println("------------------------")
field = field.Type.Elem().Field(0)
fmt.Println(field) // {Name string name22:"bbb" 0 [0] false}
}
}
}
func StructToValidate(structInter interface{}) (map[string]string, bool) {
structType := reflect.TypeOf(structInter)
var resultMap map[string]string = map[string]string{}
validErr := validate.Struct(structInter)
if validErr != nil {
for _, err := range validErr.(validator.ValidationErrors) {
var field reflect.StructField
var isOK bool
if strings.Count(err.StructNamespace(),".") == 1{
field, isOK = structType.FieldByName(err.Field())
}else {
// 命名空间包含的.大于1,说明是嵌套验证
structT := structType
for i:=1;i<strings.Count(err.StructNamespace(),".");i++{
fieldName := strings.Split(err.StructNamespace(),".")[i]
field,isOK = structT.FieldByName(fieldName)
if isOK{
structT = field.Type
}
}
field, isOK = structT.FieldByName(err.Field())
}
if isOK {
resultMap[err.Field()] = field.Tag.Get("validmsg")
}else {
resultMap[err.Field()] = err.Field()+"不能为空"
}
}
return resultMap, false
}
return nil, true
}