gin框架 引數驗證
阿新 • • 發佈:2021-06-30
★結構體驗證
用gin框架的資料驗證,可以不用解析資料,減少if else,會簡潔許多
package main import ( "fmt" "github.com/gin-gonic/gin" "time" ) 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() }
★自定義驗證
示例一:
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 { // 欄位不能為空,並且不等於 admin 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() }
示例二:
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()}) } }
★多語言翻譯驗證
當業務系統對驗證資訊有特殊需求時,例如:返回資訊需要自定義,手機端返回的資訊需要是中文而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")) }