Gin表单绑定验证器

Author Avatar
Yangzzz 7月 13, 2020
876字 | 4分 |
  • 在其它设备中阅读本文章

gin中内置validator的基础使用

type UserLoginParam struct {
    Name     string `form:"name" json:"name" binding:"required,min=2,max=30"`
    Password string `form:"password" json:"password" binding:"required,min=8,max=40"`
}

func TestValidator(t *testing.T) {
    app := gin.New()
    app.POST("/login", func(context *gin.Context) {
        var userLoginService UserLoginParam
        err := context.ShouldBind(&userLoginService)
        if err != nil {
            context.JSON(http.StatusUnprocessableEntity, gin.H{
                "msg": err.Error(),
            })
        }else{
            context.JSON(http.StatusOK, gin.H{
                "msg": "通过验证",
            })
        }
        return
    })
    _ = app.Run(":8888")
}

我们使用postman请求测试下:

拒绝:

通过:

可以看到表单验证已经生效,但是错误提示的字段不是特别友好,我们首先需要整理成前端能够解析的样子,在考虑翻译的问题。

优化返回格式

我们这里可以看到所有的验证输出都是来之或者ShouldBind后的err,我们就先看看这个err在哪里定义的,这里可以通过fmt包查看他的类型,就知道他定义的位置。

fmt.Printf("%T \n", err)

这里发现他的类型为:

下一步就是找到他的定义了。然后发现他是一个FieldError切片类型:

然后我们继续看看FieldError是个什么东西:

发现这里的FieldError是一个接口类型,里面的接口想必就是获取各种信息的。我们打印一下看看,所有我们需要改一下我们的代码,这里我就随便打印几个,其实我们看下官方在接口定义哪里的注释,也大概能明白什么意思。

        if err != nil {
            fmt.Printf("%T \n", err)
            errors := err.(validator.ValidationErrors)

            for _, value := range errors {
                fmt.Println(value.Kind())
                fmt.Println(value.Field())
                fmt.Println(value.ActualTag())
            }


            context.JSON(http.StatusUnprocessableEntity, gin.H{
                "msg": err.Error(),
            })
        } else {
            context.JSON(http.StatusOK, gin.H{
                "msg": "通过验证",
            })
        }

访问接口=>输出

这里也就很明显了。我们现在就能拿到我们错误信息进行封装返回了。我们小改一下代码:

func getParamError(err validator.ValidationErrors) map[string]string {
    result := make(map[string]string, 0)
    for _, v := range err {
        result[v.Field()] = v.Tag()
    }
    return result
}

func TestValidator(t *testing.T) {
    app := gin.Default()
    app.POST("/login", func(context *gin.Context) {
        var userLoginService UserLoginParam
        err := context.ShouldBind(&userLoginService)
        if err != nil {
            fmt.Printf("%T \n", err)
            errors := err.(validator.ValidationErrors)
            context.JSON(http.StatusUnprocessableEntity, gin.H{
                "msg": getParamError(errors),
            })
        } else {
            context.JSON(http.StatusOK, gin.H{
                "msg": "通过验证",
            })
        }
        return
    })
    _ = app.Run(":8888")
}

现在访问一下再看看:

但是这样对于前端,还是不好获取,所有我把他改为数组。前端只需要循环这个数组就行。

自定义字段校验方法

type UserLoginParam struct {
    Name     string `form:"name" json:"name" binding:"required,min=2,max=30,bookableDate"`
    Password string `form:"password" json:"password" binding:"required,min=8,max=40"`
}

func getParamError(err validator.ValidationErrors) []string {
    result := make([]string, 0)
    for _, v := range err {
        result = append(result, fmt.Sprintf("%v错误:%v", v.Field(), v.Tag()))
    }
    return result
}

// customFunc 自定义字段级别校验方法
var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
    date, ok := fl.Field().Interface().(time.Time)
    if ok {
        today := time.Now()
        if today.After(date) {
            return false
        }
    }
    return true
}

func TestValidator(t *testing.T) {

    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
        //注册
        _ = v.RegisterValidation("bookableDate", bookableDate)
    }

    app := gin.Default()
    app.POST("/login", func(context *gin.Context) {
        var userLoginService UserLoginParam
        err := context.ShouldBind(&userLoginService)
        if err != nil {
            errors := err.(validator.ValidationErrors)
            context.JSON(http.StatusUnprocessableEntity, gin.H{
                "msg": getParamError(errors),
            })

        } else {
            context.JSON(http.StatusOK, gin.H{
                "msg": "通过验证",
            })
        }
        return
    })
    _ = app.Run(":8888")
}

参考连接:https://gin-gonic.com/zh-cn/docs/examples/custom-validators/

参考连接:https://github.com/go-playground/validator/

参考连接:https://www.liwenzhou.com/posts/Go/validator_usages/

本文使用CC BY-NC-SA 3.0 中国大陆协议许可
本文链接:https://myxy99.cn/posts/golang/45b8b2b1.html