详细介绍:Java转Go日记(五十九):参数验证

1. 结构体验证

gin框架的数据验证,可以不用解析数据,减少if else,会简洁许多。

package main import (    "fmt"    "time"     "github.com/gin-gonic/gin") //Person ..type Person struct {    //不能为空并且大于10    Age      int       `form:"age" binding:"required,gt=10"`    Name     string    `form:"name" binding:"required"`    Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`} func main() {    r := gin.Default()    r.GET("/5lmh", func(c *gin.Context) {        var person Person        if err := c.ShouldBind(&person); err != nil {            c.String(500, fmt.Sprint(err))            return        }        c.String(200, fmt.Sprintf("%#v", person))    })    r.Run()}

代码启动之后,示例访问地址:

http://localhost:8080/5lmh?age=11&name=枯藤&birthday=2006-01-02

2. 自定义验证

package main import (    "net/http"    "reflect"    "github.com/gin-gonic/gin"    "github.com/gin-gonic/gin/binding"    "gopkg.in/go-playground/validator.v8") /*    对绑定解析到结构体上的参数,自定义验证功能    比如我们要对 name 字段做校验,要不能为空,并且不等于 admin ,类似这种需求,就无法 binding 现成的方法    需要我们自己验证方法才能实现 官网示例(https://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Custom_Functions)    这里需要下载引入下 gopkg.in/go-playground/validator.v8*/type Person struct {    Age int `form:"age" binding:"required,gt=10"`    // 2、在参数 binding 上使用自定义的校验方法函数注册时候的名称    Name    string `form:"name" binding:"NotNullAndAdmin"`    Address string `form:"address" binding:"required"`} // 1、自定义的校验方法func nameNotNullAndAdmin(v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {     if value, ok := field.Interface().(string); ok {        // 字段不能为空,并且不等于  5lmh        return value != "" && !("5lmh" == value)    }     return true} func main() {    r := gin.Default()     // 3、将我们自定义的校验方法注册到 validator中    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {        // 这里的 key 和 fn 可以不一样最终在 struct 使用的是 key        v.RegisterValidation("NotNullAndAdmin", nameNotNullAndAdmin)    }     /*        curl -X GET "http://127.0.0.1:8080/testing?name=&age=12&address=beijing"        curl -X GET "http://127.0.0.1:8080/testing?name=lmh&age=12&address=beijing"        curl -X GET "http://127.0.0.1:8080/testing?name=adz&age=12&address=beijing"    */    r.GET("/5lmh", func(c *gin.Context) {        var person Person        if e := c.ShouldBind(&person); e == nil {            c.String(http.StatusOK, "%v", person)        } else {            c.String(http.StatusOK, "person bind err:%v", e.Error())        }    })    r.Run()}

示例2:

package main import (    "net/http"    "reflect"    "time"     "github.com/gin-gonic/gin"    "github.com/gin-gonic/gin/binding"    "gopkg.in/go-playground/validator.v8") // Booking contains binded and validated data.type Booking struct {    //定义一个预约的时间大于今天的时间    CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`    //gtfield=CheckIn退出的时间大于预约的时间    CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`} func bookableDate(    v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,    field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,) bool {    //field.Interface().(time.Time)获取参数值并且转换为时间格式    if date, ok := field.Interface().(time.Time); ok {        today := time.Now()        if today.Unix() > date.Unix() {            return false        }    }    return true} func main() {    route := gin.Default()    //注册验证    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {        //绑定第一个参数是验证的函数第二个参数是自定义的验证函数        v.RegisterValidation("bookabledate", bookableDate)    }     route.GET("/5lmh", getBookable)    route.Run()} func getBookable(c *gin.Context) {    var b Booking    if err := c.ShouldBindWith(&b, binding.Query); err == nil {        c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})    } else {        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})    }} // curl -X GET "http://localhost:8080/5lmh?check_in=2019-11-07&check_out=2019-11-20"// curl -X GET "http://localhost:8080/5lmh?check_in=2019-09-07&check_out=2019-11-20"// curl -X GET "http://localhost:8080/5lmh?check_in=2019-11-07&check_out=2019-11-01"

 

3. 多语言翻译验证

当业务系统对验证信息有特殊需求时,例如:返回信息需要自定义,手机端返回的信息需要是中文而pc端发挥返回的信息需要时英文,如何做到请求一个接口满足上述三种情况。

package main import (    "fmt"     "github.com/gin-gonic/gin"    "github.com/go-playground/locales/en"    "github.com/go-playground/locales/zh"    "github.com/go-playground/locales/zh_Hant_TW"    ut "github.com/go-playground/universal-translator"    "gopkg.in/go-playground/validator.v9"    en_translations "gopkg.in/go-playground/validator.v9/translations/en"    zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"    zh_tw_translations "gopkg.in/go-playground/validator.v9/translations/zh_tw") var (    Uni      *ut.UniversalTranslator    Validate *validator.Validate) type User struct {    Username string `form:"user_name" validate:"required"`    Tagline  string `form:"tag_line" validate:"required,lt=10"`    Tagline2 string `form:"tag_line2" validate:"required,gt=1"`} func main() {    en := en.New()    zh := zh.New()    zh_tw := zh_Hant_TW.New()    Uni = ut.New(en, zh, zh_tw)    Validate = validator.New()     route := gin.Default()    route.GET("/5lmh", startPage)    route.POST("/5lmh", startPage)    route.Run(":8080")} func startPage(c *gin.Context) {    //这部分应放到中间件中    locale := c.DefaultQuery("locale", "zh")    trans, _ := Uni.GetTranslator(locale)    switch locale {    case "zh":        zh_translations.RegisterDefaultTranslations(Validate, trans)        break    case "en":        en_translations.RegisterDefaultTranslations(Validate, trans)        break    case "zh_tw":        zh_tw_translations.RegisterDefaultTranslations(Validate, trans)        break    default:        zh_translations.RegisterDefaultTranslations(Validate, trans)        break    }     //自定义错误内容    Validate.RegisterTranslation("required", trans, func(ut ut.Translator) error {        return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details    }, func(ut ut.Translator, fe validator.FieldError) string {        t, _ := ut.T("required", fe.Field())        return t    })     //这块应该放到公共验证方法中    user := User{}    c.ShouldBind(&user)    fmt.Println(user)    err := Validate.Struct(user)    if err != nil {        errs := err.(validator.ValidationErrors)        sliceErrs := []string{}        for _, e := range errs {            sliceErrs = append(sliceErrs, e.Translate(trans))        }        c.String(200, fmt.Sprintf("%#v", sliceErrs))    }    c.String(200, fmt.Sprintf("%#v", "user"))}

正确的链接:http://localhost:8080/testing?user_name=枯藤&tag_line=9&tag_line2=33&locale=zh

http://localhost:8080/testing?user_name=枯藤&tag_line=9&tag_line2=3&locale=en 返回英文的验证信息

http://localhost:8080/testing?user_name=枯藤&tag_line=9&tag_line2=3&locale=zh 返回中文的验证信息

查看更多的功能可以查看官网 gopkg.in/go-playground/validator.v9

posted @ 2025-07-22 16:47  yfceshi  阅读(18)  评论(0)    收藏  举报