1. 程式人生 > 程式設計 >golang validator引數校驗的實現

golang validator引數校驗的實現

今天在改後臺頁面,引數校驗錯誤時輸出全是英文,使用著很難看懂到底時什麼錯了
故而決定去做i18n前端國際化. 改的時候踩了很多坑,故而記錄一下,順便記錄以下查問題的方式。

效果

從原來的Title is required變為標題為必填欄位

完成後的程式碼:

這裡主要定義了初始化了一箇中文的trans和Validate的變數,並對其做初始化
初始化主要做了以下事情:

註冊了TagName函式
// RegisterTagNameFunc registers a function to get alternate names for StructFields.
這個方法主要就是提供一個tag的解析器,返回一個Field替代的字串

我自己是定義了一個label的tag用於替換

註冊了validate的翻譯函式
直接使用了原來提供的中文轉換,對required等標籤做對應的國際化

package service

import (
  zhongwen "github.com/go-playground/locales/zh"
  ut "github.com/go-playground/universal-translator"
  "github.com/go-playground/validator/v10"
  zh_translations "github.com/go-playground/validator/v10/translations/zh"
  "reflect"
  "strings"
)

var Validate *validator.Validate
var trans ut.Translator

func init() {
  zh := zhongwen.New()
  uni := ut.New(zh,zh)
  trans,_ = uni.GetTranslator("zh")

  Validate = validator.New()
  Validate.RegisterTagNameFunc(func(field reflect.StructField) string {
    label := field.Tag.Get("label")
    if label == "" {
      return field.Name
    }
    return label
  })
  zh_translations.RegisterDefaultTranslations(Validate,trans)
}
func Translate(errs validator.ValidationErrors) string {
  var errList []string
  for _,e := range errs {
    // can translate each error one at a time.
    errList = append(errList,e.Translate(trans))
  }
  return strings.Join(errList,"|")
}

呼叫方式

type ArticlesPost struct {
  Title      string `json:"title" validate:"required,max=32,min=4" label:"標題"`
}
var ap ArticlePost
err = service.Validate.Struct(ap)
if err!=nil{
 errStr =Translate(errs)
 fmt.Sprintln(errStr)
}

思路

  • 最剛開始去百度查了,無果
  • 查了iris的文件,也無果
  • 去看了validate的文件,找到了universal-translator 這個包,可以初步將is required等樣式改為必填欄位
  • 還是沒法將欄位名對映成中文,google搜尋到了How can I translate fieldName? #364這個issue,評論裡給出了en.Add("MyField","Field",false)的方式新增欄位的對映,最後在alidate.RegisterTranslation註冊required的時候,通過T方法轉換成對應的中文fld,_ := ut.T(fe.Field()),考慮到要每次都註冊Struct的欄位,而且全域性的同一個key肯定沒法定義不同的值,棄用
  • 第一次想著是不是校驗本身已經提供了對應的位置,看了interface,有些英文半知半解,沒找到結果,放棄
  • 繼續,想到是不是可以自定義tag,然後重寫type TranslationFunc func(ut ut.Translator,fe FieldError) string 函式,想在這個翻譯階段,去動態過去struct中那個tag的值,這樣就不會重複了.
  • 研究了這個函式的傳參,FieldError中已經只剩下欄位對應的資料了,無法獲取到tag資訊,差點已經想放棄了
  • 再次研究validator關於tag的函式

第一個是設定一個新的tag來替換validate,另一個的說明是註冊一個方法來為結構體欄位獲取替換的名字

仔細看看說明,果然就是這個,在看看TagNameFunc的簽名,引數是reflect.StructField,能夠拿到tag等一系列資訊

// TagNameFunc allows for adding of a custom tag name parser
type TagNameFunc func(field reflect.StructField) string
// SetTagName allows for changing of the default tag name of 'validate'
func (v *Validate) SetTagName(name string) {
  v.tagName = name
}

// RegisterTagNameFunc registers a function to get alternate names for StructFields.
//
// eg. to use the names which have been specified for JSON representations of structs,rather than normal Go field names:
//
//  validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
//    name := strings.SplitN(fld.Tag.Get("json"),",2)[0]
//    if name == "-" {
//      return ""
//    }
//    return name
//  })
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
  v.tagNameFunc = fn
  v.hasTagNameFunc = true
}

至此,終於找到了正確的解決方案

總結

在這裡發現為了解決這個問題走了很多彎路,查了一大堆資料才發現甚至原來就有提供該功能。

發現自己的幾個問題:

  • 英文不是很好,偶爾有些單詞不認識,阻止了進一步發現問題,這裡也突然想到,英語好一些確實可以在學程式設計這個路子上受益匪淺
  • 看文件不是很仔細,鄙人覺得大部分的程式設計問題都不是很高深,能讀得懂錯誤是什麼意思,然後去查查文件或者搜尋引擎就能解決,另一個是大部分的程式設計文件還是英文好一些,細節性的東西在翻譯的時候可能會被略掉。

到此這篇關於golang validator引數校驗的實現的文章就介紹到這了,更多相關golang validator引數校驗內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!