package main import ( "fmt" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "gopkg.in/go-playground/validator.v9" entranslations "gopkg.in/go-playground/validator.v9/translations/en" zhtranslations "gopkg.in/go-playground/validator.v9/translations/zh" "reflect" "unicode/utf8" ) /* 构建验证器 required :必填 email:验证字符串是email格式;例:"email" url:这将验证字符串值包含有效的网址;例:"url" max:字符串最大长度;例:"max=20" min:字符串最小长度;例:"min=6" excludesall:不能包含特殊字符;例:"excludesall=0x2C"//注意这里用十六进制表示。 len:字符长度必须等于n,或者数组、切片、map的len值为n,即包含的项目数;例:"len=6" eq:数字等于n,或者或者数组、切片、map的len值为n,即包含的项目数;例:"eq=6" ne:数字不等于n,或者或者数组、切片、map的len值不等于为n,即包含的项目数不为n,其和eq相反;例:"ne=6" gt:数字大于n,或者或者数组、切片、map的len值大于n,即包含的项目数大于n;例:"gt=6" gte:数字大于或等于n,或者或者数组、切片、map的len值大于或等于n,即包含的项目数大于或等于n;例:"gte=6" lt:数字小于n,或者或者数组、切片、map的len值小于n,即包含的项目数小于n;例:"lt=6" lte:数字小于或等于n,或者或者数组、切片、map的len值小于或等于n,即包含的项目数小于或等于n;例:"lte=6" 跨字段验证 eqfield=Field: 必须等于 Field 的值; nefield=Field: 必须不等于 Field 的值; gtfield=Field: 必须大于 Field 的值; gtefield=Field: 必须大于等于 Field 的值; ltfield=Field: 必须小于 Field 的值; ltefield=Field: 必须小于等于 Field 的值; eqcsfield=Other.Field: 必须等于 struct Other 中 Field 的值; 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 的值; */ type UserInfo struct { Name string `json:"name" validate:"checkName" label:"姓名" checkName_err:"姓名长度不能大于5"` FirstName string `json:"first_name" validate:"required" label:"姓"` LastName string `json:"last_name" validate:"required" label:"名"` Age uint8 `json:"age" validate:"gte=0,lte=100" label:"年龄"` Email string `json:"email" validate:"required,email" label:"邮箱"` } // 自定义验证函数 func checkName(fl validator.FieldLevel) bool { count := utf8.RuneCountInString(fl.Field().String()) if count > 5 { return false } return true } func main() { user := UserInfo{ Name: "rosers", FirstName: "Badger", LastName: "Smith", Age: 105, Email: "", } c := make(map[string]validator.Func, 0) c["checkName"] = checkName res := myValidate(user, "zh", c) fmt.Println("res=", res) } //通用验证器 func myValidate(s interface{}, language string, customValidate map[string]validator.Func) []string { errs := make([]string, 0) //验证器 validate := validator.New() //注册字段翻译 validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := fld.Tag.Get("label") return name }) //注册自定义规则 for k, v := range customValidate { err := validate.RegisterValidation(k, v) if err != nil { panic(err) } } //语言切换 var trans ut.Translator switch language { case "en": trans, _ = ut.New(en.New()).GetTranslator(language) err1 := entranslations.RegisterDefaultTranslations(validate, trans) if err1 != nil { panic(err1) } case "zh": trans, _ = ut.New(zh.New()).GetTranslator(language) err1 := zhtranslations.RegisterDefaultTranslations(validate, trans) if err1 != nil { panic(err1) } default: panic("语言错误!") } //获取reflect.Type 类型 typ := reflect.TypeOf(s) //获取reflect.Value 类型 val := reflect.ValueOf(s) //获取到a对应的类别 kd := val.Kind() //如果传入的不是struct,就退出 if kd != reflect.Struct { fmt.Println("expect struct") } //获取到该结构体有几个字段 num := val.NumField() //注册自定义规则 for k, _ := range customValidate { //变量结构体的所有字段 for i := 0; i < num; i++ { //获取到struct标签, 注意需要通过reflect.Type来获取tag标签的值 tagVal := typ.Field(i).Tag.Get(k + "_err") //如果该字段于tag标签就显示,否则就不显示 if tagVal != "" { //注册自定义函数返回信息 validate.RegisterTranslation(k, trans, func(ut ut.Translator) error { return ut.Add(k, tagVal, true) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T(k, fe.Field(), fe.Field()) return t }) } } } err := validate.Struct(s) if err != nil { for _, err := range err.(validator.ValidationErrors) { errs = append(errs, err.Translate(trans)) } } return errs }
。。。
原文:https://www.cnblogs.com/huay/p/13230558.html