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