Gin框架自帶參數(shù)校驗(yàn)的使用詳解
gin 框架內(nèi)置參數(shù)驗(yàn)證,寫在 binging tag 中,如下所示:
type Tag struct {
ID int32 `json:"id" binding:"required"`
Name string `json:"name" binding:"required"`
}這個(gè)驗(yàn)證器是由 validator 提供的,文檔
常用的操作符:
,:且,多個(gè)驗(yàn)證之間同時(shí)滿足|:或,滿足其中一個(gè)-:跳過(guò)驗(yàn)證=:等于
例子來(lái)源于官方文檔:
type User struct {
FirstName string `binding:"required"`
LastName string `binding:"required"`
Age uint8 `binding:"gte=0,lte=130"`
Email string `binding:"required,email"` // 驗(yàn)證是否是一個(gè)有效的 email 地址
Gender string `binding:"oneof=male female prefer_not_to` // oneof 表示只能是其中之一 可以用 eq=male|eq=female|eq=prefer_not_to 代替
FavouriteColor string `binding:"iscolor"` // iscolor 表示是否是一個(gè)有效的顏色值
Addresses []*Address `binding:"required,dive,required"` // dive 對(duì)嵌套結(jié)構(gòu)體進(jìn)行遞歸驗(yàn)證
}
type Address struct {
Street string `binding:"required"`
City string `binding:"required"`
Planet string `binding:"required"`
Phone string `binding:"required"`
}在我們?nèi)粘V袝?huì)經(jīng)常做手機(jī)號(hào)驗(yàn)證,但是官方只有一個(gè) e164 的驗(yàn)證,e164 是國(guó)際通用標(biāo)準(zhǔn)(要加區(qū)號(hào)),就不太符合國(guó)內(nèi)用戶
這就需要自定義驗(yàn)證器 mobile,根據(jù)官網(wǎng)提供的例子,實(shí)現(xiàn)它也是比較簡(jiǎn)單的
自定義驗(yàn)證器
首先定義一個(gè) ValidateMobile 方法
import (
"regexp"
"github.com/go-playground/validator/v10"
)
func ValidateMobile(fl validator.FieldLevel) bool {
mobile := fl.Field().String()
ok, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]16[6]|7[1-35-8]|9[189])\d{8}$`, mobile) // 用正則去匹配
return ok
}將方法注冊(cè)到 validator 中
import (
"github.com/gin-gonic/gin/binding"
)
// 從 gin 中獲取到 validator 驗(yàn)證器,然后注冊(cè) mobile
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("mobile", myvalidator.ValidateMobile)
}自定義驗(yàn)證器就定義好了,使用的時(shí)候就可以這樣寫了
type User struct {
Name string `json:"name" binding:"required"`
Mobile string `json:"mobile" binding:"required,mobile"`
}錯(cuò)誤信息翻譯
validator 默認(rèn)錯(cuò)誤信息是英文,如果需要翻譯成中文,自己做轉(zhuǎn)換:
- 跳過(guò)
json tag為-的字段 - 實(shí)例化
zh和en翻譯包 - 初始化翻譯器
- 注冊(cè)翻譯器
- 調(diào)用
InitTrans,傳入zh或者en即可
具體代碼如下:
import (
"fmt"
"mxshop_api/order_web/global"
"reflect"
"strings"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
"github.com/go-playground/validator/v10"
ut "github.com/go-playground/universal-translator"
en_translations "github.com/go-playground/validator/v10/translations/en"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
)
func InitTrans(local string) (err error) {
// 修改 gin 中 validator 實(shí)現(xiàn)定制
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 將 json tag 作為字段名
v.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
// 如果 json tag 為 - 則不處理
if name == "-" {
return ""
}
return name
})
zhT := zh.New()
enT := en.New()
// 第一個(gè)參數(shù)是備用的語(yǔ)言環(huán)境,后面的參數(shù)是應(yīng)該支持的語(yǔ)言環(huán)境
uni := ut.New(enT, zhT, enT)
// 初始化翻譯器
global.Trans, ok = uni.GetTranslator(local)
if !ok {
return fmt.Errorf("uni.GetTranslator(%s)", local)
}
switch local {
case "en":
en_translations.RegisterDefaultTranslations(v, global.Trans)
case "zh":
zh_translations.RegisterDefaultTranslations(v, global.Trans)
default:
en_translations.RegisterDefaultTranslations(v, global.Trans)
}
return
}
return
}使用:
if err := initialize.InitTrans("zh"); err != nil {
panic(err)
}這個(gè)翻譯器只能夠翻譯內(nèi)置的錯(cuò)誤信息,自定義的驗(yàn)證器需要自己翻譯
比如我們上面定義的 mobile 驗(yàn)證器,如果驗(yàn)證失敗,返回的錯(cuò)誤信息需要我們自己翻譯
參照官方例子,如下代碼:
// 四個(gè)參數(shù)
// 需要翻譯的字段名 翻譯器實(shí)例 翻譯方法 返回錯(cuò)誤的信息
_ = validator.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error {
// 翻譯的內(nèi)容
return ut.Add("mobile", "{0} 非法的手機(jī)號(hào)碼!", true)
}, func(ut ut.Translator, fe validator.FieldError) string {
// fe.Field() 獲取到的是字段名,而不是 json tag
t, _ := ut.T("mobile", fe.Field())
return t
})這樣就可以翻譯自定義的驗(yàn)證器了,最終代碼如下:
// 注冊(cè)驗(yàn)證器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
_ = v.RegisterValidation("mobile", myvalidator.ValidateMobile)
_ = v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error {
return ut.Add("mobile", "{0} 非法的手機(jī)號(hào)碼!", true) // see universal-translator for details
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("mobile", fe.Field())
return t
})
}格式化返回信息
validator 默認(rèn)返回的錯(cuò)誤信息是 json tag,這不是我們希望的
我們希望拋出去的錯(cuò)誤是結(jié)構(gòu)化的
- 使用
shouldBindJSON將參數(shù)接寫到對(duì)應(yīng)的結(jié)構(gòu)體中 - 如果解析失敗,則斷言這個(gè)錯(cuò)誤為
validator.ValidationErrors - 如果斷言成功,則將錯(cuò)誤進(jìn)行翻譯
- 去掉結(jié)構(gòu)體中的前綴,并生成一個(gè)
map - 將這個(gè)
map拋出去
最終代碼如下:
if err := ctx.ShouldBindJSON(&bannerForm); err != nil {
HandleValidatorError(ctx, err)
return
}
func HandleValidatorError(c *gin.Context, err error) {
errs, ok := err.(validator.ValidationErrors)
if !ok {
c.JSON(http.StatusOK, gin.H{
"msg": err.Error(),
})
}
c.JSON(http.StatusBadRequest, gin.H{
"error": removeTopStruct(errs.Translate(global.Trans)),
})
return
}
func removeTopStruct(fields map[string]string) map[string]string {
rsp := map[string]string{}
for field, err := range fields {
// 去掉結(jié)構(gòu)體中的前綴 {User.mobile: "mobile 非法的手機(jī)號(hào)碼!"}
rsp[field[strings.Index(field, ".")+1:]] = err
}
return rsp
}錯(cuò)誤類型在文檔中有說(shuō)明type FieldError
Tag():得到的是你寫的require、mobile等Field():結(jié)構(gòu)體中定義的字段名Translate():翻譯
總結(jié)
validator 能夠滿足我們?nèi)粘5男枨螅?/p>
- 對(duì)嵌套結(jié)構(gòu)體進(jìn)行遞歸驗(yàn)證
- 自定義驗(yàn)證器
- 錯(cuò)誤信息翻譯
- 格式化返回信息
到此這篇關(guān)于Gin框架自帶參數(shù)校驗(yàn)的使用詳解的文章就介紹到這了,更多相關(guān)Gin參數(shù)校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Kotlin編程基礎(chǔ)語(yǔ)法編碼規(guī)范
這篇文章主要為大家介紹了Kotlin編程條件控制示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
go語(yǔ)言優(yōu)雅地處理error工具及技巧詳解
這篇文章主要為大家介紹了go語(yǔ)言優(yōu)雅地處理error工具及技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

