Validator 是一個 Golang 的第三方庫,用於對資料進行校驗,常用於 API 的開發中,對使用者端發出的請求資料進行嚴格校驗,防止惡意請求。
安裝:
go get gopkg.in/go-playground/validator.v10
使用:
import "github.com/go-playground/validator/v10"
NOTE:validator 當前最新的版本是 v10,各個版本之間有一些差異,在使用的時候要注意區分。
validator 應用了 Golang 的 Struct Tag 和 Reflect 機制,基本思想是:在 Struct Tag 中為不同的欄位定義各自型別的約束,然後通過 Reflect 獲取這些約束的型別資訊並在校驗器中進行資料校驗。如下例:
package main
import (
"fmt"
"gopkg.in/go-playground/validator.v10"
)
type User struct {
Name string `validate:"min=6,max=10"`
Age int `validate:"min=1,max=100"`
}
func main() {
validate := validator.New()
u1 := User{Name: "fanguiju", Age: 18}
err := validate.Struct(u1)
fmt.Println(err)
u2 := User{Name: "fgj", Age: 101}
err = validate.Struct(u2)
fmt.Println(err)
}
上述例子中,我們定義了結構體 User,有 Name 和 Age 成員。通過 validator 的 min 和 max 約束,分別約束了 Name 的字串長度 [6, 10],Age 的數位範圍為 [1,100]。
使用 validator 的第一步需要 New(構造)一個 「校驗器」,然後呼叫其 Struct 方法對結構體範例進行校驗。如果滿足約束則返回 nil,否則返回相應的錯誤資訊。
validate:"structonly"
。validate:"nostructlevel"
。[][]string
:validate:"gt=0,dive,len=1,dive,required"
。validate:"gt=0,dive,keys,eq=1\|eq=2,endkeys,required"
。Tags:
下面列舉常用的字串約束:
唯一性(unique)約束,對不同型別的處理如下:
validator 允許定義跨欄位的約束,即:約束某個欄位與其他欄位之間的關係。這種約束實際上分為兩種:
約束語法很簡單,如果是約束同一個結構中的欄位,則在基礎的 Tags 後面新增一個 field 字尾,例如:eqfield 定義欄位間的相等(eq)約束。如果是更深層次的欄位,在 field 之前還需要加上 cs(Cross-Struct),eq 就變為了 eqcsfield。
範例:
type RegisterForm struct {
Name string `validate:"min=2"`
Age int `validate:"min=18"`
Password string `validate:"min=10"`
Password2 string `validate:"eqfield=Password"`
}
即:他們組成就是 「比較符號 + 是否跨 Struct(cross struct) + field」:
另外還有幾個挺有用的 Tag:
除了使用 validator 提供的內建約束外,還可以定義自己的約束。首先定義一個型別為 func (validator.FieldLevel) bool 的函數檢查約束是否滿足,可以通過 FieldLevel 取出要檢查的欄位的資訊。然後,呼叫校驗器的 RegisterValidation() 方法將該約束註冊到指定的名字上。最後我們就可以在結構體中使用該約束了。
範例:
type RegisterForm struct {
Name string `validate:"palindrome"`
Age int `validate:"min=18"`
}
func reverseString(s string) string {
runes := []rune(s)
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
return string(runes)
}
func CheckPalindrome(fl validator.FieldLevel) bool {
value := fl.Field().String()
return value == reverseString(value)
}
func main() {
validate := validator.New()
validate.RegisterValidation("palindrome", CheckPalindrome)
f1 := RegisterForm{
Name: "djd",
Age: 18,
}
err := validate.Struct(f1)
if err != nil {
fmt.Println(err)
}
f2 := RegisterForm{
Name: "dj",
Age: 18,
}
err = validate.Struct(f2)
if err != nil {
fmt.Println(err)
}
}
validator 返回的錯誤有兩種,一種是引數錯誤,一種是校驗錯誤,它們都實現了 error 介面。
所以 validator 校驗返回的結果只有 3 種情況:
我們可以在程式中判斷 err != nil 時,可以依次將 err 轉換為 InvalidValidationError 和 ValidationErrors 以獲取更詳細的資訊:
func processErr(err error) {
if err == nil {
return
}
invalid, ok := err.(*validator.InvalidValidationError)
if ok {
fmt.Println("param error:", invalid)
return
}
validationErrs := err.(validator.ValidationErrors)
for _, validationErr := range validationErrs {
fmt.Println(validationErr)
}
}
func main() {
validate := validator.New()
err := validate.Struct(1)
processErr(err)
err = validate.VarWithValue(1, 2, "eqfield")
processErr(err)
}
需要安裝兩個包:
go get github.com/go-playground/universal-translator
go get github.com/go-playground/locales
範例:
package main
import (
"fmt"
"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"
)
type Users struct {
Name string `form:"name" json:"name" validate:"required"`
Age uint8 `form:"age" json:"age" validate:"required,gt=18"`
Passwd string `form:"passwd" json:"passwd" validate:"required,max=20,min=6"`
Code string `form:"code" json:"code" validate:"required,len=6"`
}
func main() {
users := &Users{
Name: "admin",
Age: 12,
Passwd: "123",
Code: "123456",
}
// 中文翻譯器
uni := ut.New(zh.New())
trans, _ := uni.GetTranslator("zh")
// 校驗器
validate := validator.New()
// 註冊翻譯器到校驗器
err := zh_translations.RegisterDefaultTranslations(validate, trans)
if err!=nil {
fmt.Println(err)
}
err = validate.Struct(users)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
fmt.Println(err.Translate(trans))
return
}
}
return
}
https://blog.csdn.net/qq_26273559/article/details/107164846