欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解go-zero如何使用validator進行參數(shù)校驗

 更新時間:2024年01月26日 08:18:29   作者:lovevivi121  
這篇文章主要介紹了如何使用validator庫做參數(shù)校驗的一些十分實用的使用技巧,包括翻譯校驗錯誤提示信息、自定義提示信息的字段名稱、自定義校驗方法等,感興趣的可以了解下

validator庫參數(shù)校驗若干實用技巧

在web開發(fā)中一個不可避免的環(huán)節(jié)就是對請求參數(shù)進行校驗,通常我們會在代碼中定義與請求參數(shù)相對應(yīng)的模型(結(jié)構(gòu)體),借助模型綁定快捷地解析請求中的參數(shù)。本文就以 go-zero 框架的請求參數(shù)校驗為例,介紹一些validator庫的實用技巧。

go-zero框架使用github.com/go-playground/validator進行參數(shù)校驗,目前已經(jīng)支持github.com/go-playground/validator/v10了,我們需要在定義結(jié)構(gòu)體時使用 validate tag標識相關(guān)校驗規(guī)則,可以查看validator文檔查看支持的所有 tag。

安裝validator庫

go get github.com/go-playground/validator/v10

基本示例

首先來看go-zero框架內(nèi)置使用validator做參數(shù)校驗的基本示例。

在api層編寫Req時進行validator標簽的編輯

生成.go文件的時候type就會帶上相關(guān)標簽(types里面)

type (
    TestReq {
        Age        int64  `json:"age" validate:"gte=1,lte=130"`
        Name       string `json:"name" validate:"required"`
        Email      string `json:"email" validate:"required,email"`
        Password   string `json:"password" validate:"required"`
        RePassword string `json:"re_password" validate:"required,eqfield=Password"`
    }
    TestResp {
    }
)

在handler層調(diào)用validator庫

這個是沒有使用validator前的handler

func TestApiHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.TestReq
        if err := httpx.Parse(r, &req); err != nil {
            httpx.ErrorCtx(r.Context(), w, err)
            return
        }
        l := lottery.NewTestApiLogic(r.Context(), svcCtx)
        resp, err := l.TestApi(&req)
        if err != nil {
            result.ParamErrorResult(r, w, err)
        } else {
            result.HttpResult(r, w, resp, err)
        }
    }
}

使用validator校驗

err := validator.New().StructCtx(r.Context(), req)
if err != nil {
    httpx.ErrorCtx(r.Context(), w, err)
    return
}

后續(xù)配合模板,直接生成這段代碼即可,這樣handler層可以不必再編輯

翻譯校驗錯誤提示信息

validator庫本身是支持國際化的,借助相應(yīng)的語言包可以實現(xiàn)校驗錯誤提示信息的自動翻譯。下面的示例代碼演示了如何將錯誤提示信息翻譯成中文,翻譯成其他語言的方法類似。

安裝翻譯相關(guān)包

go get github.com/go-playground/universal-translator

編寫validate的方法

func Validate(dataStruct interface{}) error {
    zh_ch := zh.New()
    validate := validator.New()
    // 注冊一個函數(shù),獲取struct tag里自定義的label作為字段名
    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
        if name == "-" {
            return ""
        }
        return name
    })
?
    uni := ut.New(zh_ch)
    trans, _ := uni.GetTranslator("zh")
    // 驗證器注冊翻譯器
    zh_translations.RegisterDefaultTranslations(validate, trans)
    err := validate.Struct(dataStruct)
    if err != nil {
        for _, err := range err.(validator.ValidationErrors) {
            return errors.New(err.Translate(trans))
        }
    }
    return nil
}

編寫handler中的攔截(直接放模板里面去)

validateErr := translator.Validate(&req)
if validateErr != nil {
    result.ParamErrorResult(r, w, validateErr)
    return
}

自定義結(jié)構(gòu)體校驗方法

上面的校驗還是有點小問題,就是當涉及到一些復(fù)雜的校驗規(guī)則,比如re_password字段需要與password字段的值相等這樣的校驗規(guī)則,我們的自定義錯誤提示字段名稱方法就不能很好解決錯誤提示信息中的其他字段名稱了。

當我們測試re_password字段的時候,可以看到re_password字段的提示信息中還是出現(xiàn)了Password這個結(jié)構(gòu)體字段名稱。這有點小小的遺憾,畢竟自定義字段名稱的方法不能影響被當成param傳入的值。

{
    "code": 100002,
    "msg": "參數(shù)錯誤 ,re_password必須等于Password"
}

此時如果想要追求更好的提示效果,將上面的Password字段也改為和json tag一致的名稱,就需要我們自定義結(jié)構(gòu)體校驗的方法。

例如,我們?yōu)?code>SignUpParam自定義一個校驗方法如下:

// SignUpParamStructLevelValidation 自定義SignUpParam結(jié)構(gòu)體校驗函數(shù)
func SignUpParamStructLevelValidation(sl validator.StructLevel) {
	su := sl.Current().Interface().(types.TestReq)

	if su.Password != su.RePassword {
		// 輸出錯誤提示信息,最后一個參數(shù)就是傳遞的param
		sl.ReportError(su.RePassword, "re_password", "RePassword", "eqfield", "password")
	}
}

并且刪掉原先的校驗

eqfield=Password // api中的這個校驗不要,重新生成.go文件

然后在初始化校驗器的函數(shù)中注冊該自定義校驗方法即可:

validate.RegisterStructValidation(lottery.SignUpParamStructLevelValidation, types.TestReq{})

最終再請求一次,看一下效果:

{
    "code": 100002,
    "msg": "參數(shù)錯誤 ,re_password必須等于password"
}

這一次re_password字段的錯誤提示信息就符合我們預(yù)期了。

自定義字段校驗方法

除了上面介紹到的自定義結(jié)構(gòu)體校驗方法,validator還支持為某個字段自定義校驗方法,并使用RegisterValidation()注冊到校驗器實例中。

接下來我們來為SignUpParam添加一個需要使用自定義校驗方法checkDate做參數(shù)校驗的字段Date。

TestReq {
    Age        int64  `json:"age" validate:"gte=1,lte=130"`
    Name       string `json:"name" validate:"required"`
    Email      string `json:"email" validate:"required,email"`
    Password   string `json:"password" validate:"required"`
    RePassword string `json:"re_password" validate:"required"`
    // 需要使用自定義校驗方法checkDate做參數(shù)校驗的字段Date
    Date       string `json:"date" validate:"required,datetime=2006-01-02,checkDate"`
}

其中datetime=2006-01-02是內(nèi)置的用于校驗日期類參數(shù)是否滿足指定格式要求的tag。 如果傳入的date參數(shù)不滿足2006-01-02這種格式就會提示如下錯誤:

{
    "code": 100002,
    "msg": "參數(shù)錯誤 ,date的格式必須是2006-01-02"
}

針對date字段除了內(nèi)置的datetime=2006-01-02提供的格式要求外,假設(shè)我們還要求該字段的時間必須是一個未來的時間(晚于當前時間),像這樣針對某個字段的特殊校驗需求就需要我們使用自定義字段校驗方法了。

首先我們要在需要執(zhí)行自定義校驗的字段后面添加自定義tag,這里使用的是checkDate,注意使用英文分號分隔開。

// customFunc 自定義字段級別校驗方法
func customFunc(fl validator.FieldLevel) bool {
	date, err := time.Parse("2006-01-02", fl.Field().String())
	if err != nil {
		return false
	}
	if date.Before(time.Now()) {
		return false
	}
	return true
}

定義好了字段及其自定義校驗方法后,就需要將它們聯(lián)系起來并注冊到我們的校驗器實例中。

// 注冊自定義結(jié)構(gòu)體字段校驗方法
if err := validate.RegisterValidation("checkDate", customFunc); err != nil {
    return err
}

這樣,我們就可以對請求參數(shù)中date字段執(zhí)行自定義的checkDate進行校驗了。 我們發(fā)送如下請求測試一下,得到響應(yīng)結(jié)果如下:

{
    "code": 100002,
    "msg": "參數(shù)錯誤 ,Key: 'TestReq.date' Error:Field validation for 'date' failed on the 'checkDate' tag"
}

這…自定義字段級別的校驗方法的錯誤提示信息很“簡單粗暴”,和我們上面的中文提示風(fēng)格有出入,必須想辦法搞定它呀!

自定義翻譯方法

我們現(xiàn)在需要為自定義字段校驗方法提供一個自定義的翻譯方法,從而實現(xiàn)該字段錯誤提示信息的自定義顯示。

// registerTranslator 為自定義字段添加翻譯功能
func registerTranslator(tag string, msg string) validator.RegisterTranslationsFunc {
	return func(trans ut.Translator) error {
		if err := trans.Add(tag, msg, false); err != nil {
			return err
		}
		return nil
	}
}

// translate 自定義字段的翻譯方法
func translate(trans ut.Translator, fe validator.FieldError) string {
	msg, err := trans.T(fe.Tag(), fe.Field())
	if err != nil {
		panic(fe.(error).Error())
	}
	return msg
}

定義好了相關(guān)翻譯方法之后,我們在InitTrans函數(shù)中通過調(diào)用RegisterTranslation()方法來注冊我們自定義的翻譯方法。

// InitTrans 初始化翻譯器
func InitTrans(locale string) (err error) {
	// ...liwenzhou.com...
	
		// 注冊翻譯器
		switch locale {
		case "en":
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		case "zh":
			err = zhTranslations.RegisterDefaultTranslations(v, trans)
		default:
			err = enTranslations.RegisterDefaultTranslations(v, trans)
		}
		if err != nil {
			return err
		}
		// 注意!因為這里會使用到trans實例
		// 所以這一步注冊要放到trans初始化的后面
		if err := v.RegisterTranslation(
			"checkDate",
			trans,
			registerTranslator("checkDate", "{0}必須要晚于當前日期"),
			translate,
		); err != nil {
			return err
		}
		return
	}
	return
}

這樣再次嘗試發(fā)送請求,就能得到想要的錯誤提示信息了。

{
    "code": 100002,
    "msg": "參數(shù)錯誤 ,date的格式必須是2006-01-02"
}

總結(jié)

本文總結(jié)的go-zero框架中validator的使用技巧同樣也適用于直接使用validator庫,區(qū)別僅僅在于我們配置的是go-zero框架中的校驗器還是由validator.New()創(chuàng)建的校驗器。同時使用validator庫確實能夠在一定程度上減少我們的編碼量,但是它不太可能完美解決我們所有需求,所以你需要找到兩者之間的平衡點。

以上就是詳解go-zero如何使用validator進行參數(shù)校驗的詳細內(nèi)容,更多關(guān)于go validator參數(shù)校驗的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語言讀取json并下載高清妹子圖片

    go語言讀取json并下載高清妹子圖片

    前面我們介紹了使用python下載高清妹子圖,作為程序猿,我們當然不能只會一種語言,今天我們就來使用go語言來讀取API來下載妹子圖吧,有需要的宅男們可以參考下。
    2015-03-03
  • golang切片原理詳細解析

    golang切片原理詳細解析

    這篇文章主要介紹了golang切片原理詳細解析,切片在編譯時定義為Slice結(jié)構(gòu)體,并通過NewSlice()函數(shù)進行創(chuàng)建,更多相關(guān)內(nèi)容感興趣的小伙伴可以參考一下下面文章內(nèi)容
    2022-06-06
  • Go 常量基礎(chǔ)概念(聲明更改只讀)

    Go 常量基礎(chǔ)概念(聲明更改只讀)

    這篇文章主要為大家介紹了Go常量基礎(chǔ)概念包括常量的聲明更改只讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Go語言kube-scheduler深度剖析與開發(fā)之pod調(diào)度

    Go語言kube-scheduler深度剖析與開發(fā)之pod調(diào)度

    這篇文章主要為大家介紹了Go語言kube-scheduler深度剖析與開發(fā),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Go語言reflect.TypeOf()和reflect.Type通過反射獲取類型信息

    Go語言reflect.TypeOf()和reflect.Type通過反射獲取類型信息

    這篇文章主要介紹了Go語言reflect.TypeOf()和reflect.Type通過反射獲取類型信息,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • VSCode安裝go相關(guān)插件失敗的簡單解決方案

    VSCode安裝go相關(guān)插件失敗的簡單解決方案

    這篇文章主要給大家介紹了關(guān)于VSCode安裝go相關(guān)插件失敗的簡單解決方案,VSCode是我們開發(fā)go程序的常用工具,最近安裝的時候遇到了些問題,需要的朋友可以參考下
    2023-07-07
  • Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    這篇文章給大家介紹了Go實現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱),需求很簡單,就是用戶輸入自己的郵箱后,使用官方郵箱給用戶發(fā)送替郵件模版,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下
    2023-10-10
  • Golang 操作TSV文件的實戰(zhàn)示例

    Golang 操作TSV文件的實戰(zhàn)示例

    本文主要介紹了Golang 操作TSV文件的實戰(zhàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • GO語言基礎(chǔ)之數(shù)組

    GO語言基礎(chǔ)之數(shù)組

    或許您是從其他語言轉(zhuǎn)到GO語言這邊的,那麼在其他語言的影響下您可能會不太適應(yīng)GO語言的數(shù)組,因為GO語言把數(shù)組給拆分成了array,slice和map,需要的朋友可以參考下
    2015-01-01
  • 一文詳解Go語言中切片的底層原理

    一文詳解Go語言中切片的底層原理

    在Go語言中,切片作為一種引用類型數(shù)據(jù),相對數(shù)組而言是一種動態(tài)長度的數(shù)據(jù)類型,使用的場景也是非常多,所以本文主要來和大家聊聊切片的底層原理,需要的可以參考一下
    2023-06-06

最新評論