golang validate构建


验证规则:https://github.com/go-playground/validator

中文参考:https://www.cnblogs.com/zj420255586/p/13542395.html

https://www.cnblogs.com/wangkun122/articles/11023964.html

验证器构建

package validate_1

import (
    "errors"
    "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"
)

/*
https://www.jianshu.com/p/9ef19d5eac72
构建验证器
numeric:数字
required :必填
email_1:验证字符串是email格式;例:"email_1"
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"` //声明自定义tag,函数必须定义,必须绑定
    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_1" 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 := autoValidate(user, "zh", c)
//    //res := autoValidate(user, map[string]validator.Func{}, "zh")
//    fmt.Println("res=", res)
//}

//通用验证器
func AutoValidate(s interface{}, language string, customValidate map[string]validator.Func) []string {
    errs := make([]string, 0)
    //验证器
    validate := validator.New()
    //注册字段翻译
    if language != "en" {
        validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
            name := fld.Tag.Get("label")
            return name
        })
    }

    if customValidate != nil {
        //注册自定义规则
        for k, v := range customValidate {
            err := validate.RegisterValidation(k, v)
            if err != nil {
                panic(err)
            }
        }

    }

    //语言切换
    var trans ut.Translator
    var err1 error
    switch language {
    case "en":
        trans, _ = ut.New(en.New()).GetTranslator(language)
        err1 = entranslations.RegisterDefaultTranslations(validate, trans)
    case "zh":
        trans, _ = ut.New(zh.New()).GetTranslator(language)
        err1 = zhtranslations.RegisterDefaultTranslations(validate, trans)
    default:
        err1 = errors.New("语言不存在")
    }
    if err1 != nil {
        panic(err1)
    }
    if customValidate != nil {
        //获取reflect.Type 类型
        typ := reflect.TypeOf(s)
        //获取reflect.Value 类型
        val := reflect.ValueOf(s)
        //获取到a对应的类别
        kd := val.Kind()
        //如果传入的不是struct,就退出
        if kd != reflect.Struct {
            panic("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
}
View Code

 

gin构建验证

package ginvalidate

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/gin-gonic/gin/binding"
    "github.com/go-playground/locales/zh"
    ut "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zh_translations "github.com/go-playground/validator/v10/translations/zh"
    "reflect"
)

func init() {
    AutoValidate(nil)
}

var trans ut.Translator

type AutoRule struct {
    Func     validator.Func `json:"func"`
    FuncName string         `json:"func_name"`
    ErrMsg   string         `json:"err_msg"`
}

func AutoValidate(customValidate []AutoRule) {

    uni := ut.New(zh.New())
    trans, _ = uni.GetTranslator("zh")

    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        //注册翻译器
        _ = zh_translations.RegisterDefaultTranslations(v, trans)

        //注册自定义函数
        for _, autoRule := range customValidate {
            _ = v.RegisterValidation(autoRule.FuncName, autoRule.Func)
            //根据提供的标记注册翻译
            v.RegisterTranslation(autoRule.FuncName, trans, func(ut ut.Translator) error {
                return ut.Add(autoRule.FuncName, autoRule.ErrMsg, true)
            }, func(ut ut.Translator, fe validator.FieldError) string {
                t, _ := ut.T(autoRule.FuncName)
                return t
            })
        }
        //注册一个函数,获取struct tag里自定义的json作为字段名
        v.RegisterTagNameFunc(func(fld reflect.StructField) string {
            name := fld.Tag.Get("json")
            return name
        })
    }
}

//翻译输出错误
func ValidateErrs(err error) map[string]string {
    //对验证结果进行翻译
    dumpErrs := make(map[string]string, 0)
    errs := err.(validator.ValidationErrors)
    for _, e := range errs {
        dumpErrs[e.Field()] = e.Translate(trans)
    }
    return dumpErrs
}

func ValidateBind(c *gin.Context, obj interface{}) map[string]string {
    fmt.Printf("T=%T,v=%v\n", obj, obj)
    //对验证结果进行翻译
    err := c.ShouldBindJSON(obj)
    errs1 := make(map[string]string, 0)
    if err == nil {
        return errs1
    }
    //翻译
    errs := err.(validator.ValidationErrors)
    for _, e := range errs {
        errs1[e.Field()] = e.Translate(trans)
    }
    return errs1
}

//单条错误
func ValidateErr(err error) string {
    if err == nil {
        return ""
    }
    errs := err.(validator.ValidationErrors)
    for _, e := range errs {
        return e.Translate(trans)
    }
    return ""
}
View Code

 

自定义使用

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/go-playground/validator/v10"
    "go_code/pack/gin_validate/ginvalidate"
    "net/http"
    "time"
)

// 绑定为json 验证
//binding有与validate相似的验证效果
type Login struct {
    User     string    `json:"user"   binding:"required,max=10,min=5"label:"用户名"`
    Password string    `json:"password"  binding:"required"label:"密码"`
    CheckIn  time.Time `json:"check_in" binding:"required" label:"输入时间"`
}

func main() {
    router := gin.Default()
    // Example for binding JSON ({"user": "manu", "password": "123"})
    //注册路由
    router.POST("/loginJSON", login)
    // Listen and serve on 0.0.0.0:8080
    router.Run(":8088")
}

func login(c *gin.Context) {
    fmt.Println(123)
    //自定义
    //c1 := make(map[string]validator.Func, 0)
    //c1["密码长度不正确"] = passrule
    //s1 := []ginvalidate.AutoRule{ginvalidate.AutoRule{
    //    Func:     passrule,
    //    FuncName: "passrule",
    //    ErrMsg:   "密码长度不能小于5",
    //}}
    //ginvalidate.AutoValidate(s1)
    var json Login
    err := c.ShouldBindJSON(&json)
    errs := ginvalidate.ValidateErrs(err)
    //errs := ginvalidate.ValidateBind(c, json)
    fmt.Println(errs)
    if len(errs) != 0 {
        c.JSON(http.StatusBadRequest, errs)
        return
    }
    c.JSON(http.StatusOK, json)
    return

}
func passrule(fl validator.FieldLevel) bool {
    str := fl.Field().String()
    if len(str) < 5 {
        return false
    }
    return true
}

//func bookableDate(fl validator.FieldLevel) bool {
//    date, ok := fl.Field().Interface().(time.Time)
//
//    if ok {
//        today := time.Now()
//        if today.After(date) {
//            return false
//        }
//    }
//    return true
//}
View Code

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM