gin - validator 参数校验

最近自己也在用gin框架做项目,然后在群里也有人问关于,参数验证的问题,今天有时间正好研究一下。

gin版本 : v1.6.2

基本验证

  • 定义参数绑定结构体account_io.go

    package controller
    type Register struct {
        Mobile   uint   `json:"mobile" binding:"required"`
        Password string `json:"password" binding:"required,gte=6"`
    }
  • 将相求参数与结构体绑定account.go

    package controller
    
    import (
        "fmt"
        "mid-anding/pkg"
    
        "github.com/gin-gonic/gin"
    )
    
    type AccountController struct {
    }
    
    // Register 账户注册
    func (ctl *AccountController) Register(c *gin.Context) {
        var (
            err error
            req Register
        )
        if err = pkg.ParseRequest(c, &req); err != nil {
            return
        }
    
        fmt.Printf("%+v\n", req)
    }
    

    pkg.ParseRequest 这是对gin自带参数绑定的封装request.go,具体代码如下

    package pkg
    func ParseRequest(c *gin.Context, request interface{}) error {
        err := c.ShouldBind(request)
    
        if err != nil {
            c.JSON(200, app.Resp{
                Code: 10004,
                Msg:  err.Error(),
            })
            return err
        }
        return nil
    }
    OK,第一阶段的验证算是完成了,具体的验证参数可以查看package validator

自定义验证函数

  • 定义验证函数define.go

    package vali
    
    import (
        "strconv"
        "strings"
    
        "github.com/gin-gonic/gin/binding"
        "github.com/go-playground/validator/v10"
    )
    
    var v *validator.Validate
    var trans ut.Translator
    
    func InitVali() {
        v, ok := binding.Validator.Engine().(*validator.Validate)
        if ok {
            // 自定义验证方法
            v.RegisterValidation("checkMobile", checkMobile)
        }
    }
    
    func checkMobile(fl validator.FieldLevel) bool {
        mobile := strconv.Itoa(int(fl.Field().Uint()))
        re := `^1[3456789]\d{9}$`
        r := regexp.MustCompile(re)
        return r.MatchString(mobile)
    }
    
  • 加载,在main.go中进行加载

        vali.InitVali() // 字段验证
  • 准备工作完成,接下来让我们来使用他

    package controller
    
    type Register struct {
        Mobile   uint   `json:"mobile" binding:"required,checkMobile"`
        Password string `json:"password" binding:"required,gte=6"`
    }
    这个阶段已经完成,我们可以满足我们常见的参数验证场景了,但是还不够完美,哪里不够完美呢,提示信息,现在我们看到的提示信息是英文的,身为一个中国人,我们当然要提示中文才显得更加友好,所以接下来我们做汉化展示。
阶段补充-自定义错误信息
  • 修改define.go并在v.RegisterValidation下一行,加入以下代码

    v.RegisterTranslation("checkMobile", trans, func(ut ut.Translator) error {
            return ut.Add("checkMobile", "{0}长度不等于11位或{1}格式错误!", true) // see universal-translator for details
        }, func(ut ut.Translator, fe validator.FieldError) string {
            t, _ := ut.T("checkMobile", fe.Field(), fe.Field())
    
            return t
        })

错误提示信息汉化

  • 改造完defind.go如下

    package vali
    
    import (
        "strconv"
        "strings"
    
        "github.com/gin-gonic/gin/binding"
        zhongwen "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"
    )
    
    var v *validator.Validate
    var trans ut.Translator
    
    func InitVali() {
        // 中文翻译
        zh := zhongwen.New()
        uni := ut.New(zh, zh)
        trans, _ = uni.GetTranslator("zh")
    
        v, ok := binding.Validator.Engine().(*validator.Validate)
        if ok {
            // 验证器注册翻译器
            zh_translations.RegisterDefaultTranslations(v, trans)
            // 自定义验证方法
            v.RegisterValidation("checkMobile", checkMobile)
        }
    }
    func Translate(errs validator.ValidationErrors) string {
        var errList []string
        for _, e := range errs {
            // can translate each error one at a time.
            errList = append(errList, e.Translate(trans))
        }
        return strings.Join(errList, "|")
    }
    
    func checkMobile(fl validator.FieldLevel) bool {
        mobile := strconv.Itoa(int(fl.Field().Uint()))
        if len(mobile) != 11 {
            return false
        }
        return true
    }
    
  • 改造 request.go,代码如下

    package pkg
    
    import (
        "mid-anding/pkg/vali"
    
        "github.com/gin-gonic/gin"
        "github.com/gin-gonic/gin/binding"
        "github.com/go-playground/validator/v10"
    )
    func ParseRequest(c *gin.Context, request interface{}) error {
        err := c.ShouldBind(request)
        var errStr string
        if err != nil {
            switch err.(type) {
            case validator.ValidationErrors:
                errStr = vali.Translate(err.(validator.ValidationErrors))
            case *json.UnmarshalTypeError:
                unmarshalTypeError := err.(*json.UnmarshalTypeError)
                errStr = fmt.Errorf("%s 类型错误,期望类型 %s", unmarshalTypeError.Field, unmarshalTypeError.Type.String()).Error()
            default:
                errStr = errors.New("unknown error.").Error()
            }
            logging.Error(err)
            app.RespData(c, e.PARAMS_IS_INVALID, errStr, nil)
            return err
        }
        return nil
    }
至此,工作结束,我们可以愉快的使用gin自带的参数绑定验证了。
阅读 2.8k

推荐阅读