golang經常使用庫:gorilla/mux-http路由庫使用
golang經常使用庫:配置文件解析庫-viper使用
golang經常使用庫:操做數據庫的orm框架-gorm基本使用
golang經常使用庫:字段參數驗證庫-validator使用html
在日常開發中,特別是在web應用開發中,爲了驗證輸入字段的合法性,都會作一些驗證操做。好比對用戶提交的表單字段進行驗證,或者對請求的API接口字段進行驗證,驗證字段的合法性,保證輸入字段值的安全,防止用戶的惡意請求。git
通常的作法是用正則表達式,一個字段一個字段的進行驗證。一個一個字段驗證的話,寫起來比較繁瑣。那有沒更好的方法,進行字段的合法性驗證?有, 這就是下面要介紹的 validator 這個驗證組件。github
代碼地址:
https://github.com/go-playground/validatorgolang
文檔地址:
https://github.com/go-playground/validator/blob/master/README.mdweb
這個驗證包 github.com/go-playground/validator 驗證功能很是多。正則表達式
,
):把多個驗證標記隔開。注意
:隔開逗號之間不能有空格, validate:"lt=0,gt=100"
,逗號那裏不能有空格,不然panic-
):跳過該字段不驗證|
):使用多個驗證標記,可是隻需知足其中一個便可doc: https://github.com/go-playground/validator/blob/master/README.md#comparisonssql
範圍驗證: 切片、數組和map、字符串,驗證其長度;數值,驗證大小範圍數據庫
validate:"lte=3"
(小於等於3)validate:"lte=0,gte=120"
(大於等於0小於等於120)validate:"lt=3"
(小於3)validate:"lt=0,gt=120"
(大於0小於120)validate:"len=2"
validate:"max=2"
(大於等於2)validate:"min=2,max=10"
(大於等於2小於等於10)validate:"ne=2"
(不等於2)validate:"oneof=red green"
例子:json
type User struct { Name string `json:"name" validate:"min=0,max=35"` Age unit8 `json:"age" validate:"lte=0,gte=90"` }
更多功能請參看文檔 validator comparisons doc數組
doc: https://github.com/go-playground/validator/blob/master/README.md#strings
validate:"contains=tom"
(字段的字符串值包含tom)validate:"excludes=tom"
(字段的字符串值不包含tom)validate:"startswith=golang"
validate:"startswith=world"
例子:
type User struct { Name string `validate:"contains=tom"` Age int `validate:"min=1"` }
更多功能請參看文檔 validator strings doc
doc: https://github.com/go-playground/validator/blob/master/README.md#fields
type Struct1 struct { Field1 string `validate:eqcsfield=Struct2.Field2` Struct2 struct { Field2 string } }
necsfield:跨不一樣結構體字段不相等
eqfield:同一結構體字段驗證相等,最多見的就是輸入2次密碼驗證
type User struct { Name string `validate:"lte=4"` Age int `validate:"min=20"` Password string `validate:"min=10"` Password2 string `validate:"eqfield=Password"` }
type User struct { Name string `validate:"lte=4"` Age int `validate:"min=20"` Password string `validate:"min=10,nefield=Name"` }
validate:"gtefiled=Field2"
更多功能請參看文檔:validator Fields DOC
doc: https://github.com/go-playground/validator/blob/master/README.md#network
validate:"ip"
validate:"ipv4"
validate:"ipv6"
validate:"uri"
validate:"url"
更多功能請參看文檔:validator network DOC
doc: https://github.com/go-playground/validator/blob/master/README.md#format
更多功能請參看文檔 validator strings doc
請參看文檔: https://github.com/go-playground/validator/blob/master/README.md#other
go get:
go get github.com/go-playground/validator/v10
在文件中引用validator包:
import "github.com/go-playground/validator/v10"
文檔:https://github.com/go-playground/validator/blob/master/README.md#examples
validation1.go
package main import ( "fmt" "github.com/go-playground/validator/v10" ) func main() { validate := validator.New() var boolTest bool err := validate.Var(boolTest, "required") if err != nil { fmt.Println(err) } var stringTest string = "" err = validate.Var(stringTest, "required") if err != nil { fmt.Println(err) } var emailTest string = "test@126.com" err = validate.Var(emailTest, "email") if err != nil { fmt.Println(err) } else { fmt.Println("success") // 輸出: success。 說明驗證成功 } emailTest2 := "test.126.com" errs := validate.Var(emailTest2, "required,email") if errs != nil { fmt.Println(errs) // 輸出: Key: "" Error:Field validation for "" failed on the "email" tag。驗證失敗 } fmt.Println("\r\nEnd!!") }
運行輸出:
go run simple1.go
Key: '' Error:Field validation for '' failed on the 'required' tag
Key: '' Error:Field validation for '' failed on the 'required' tag
success
Key: '' Error:Field validation for '' failed on the 'email' tagEnd!!
from:struct validate
validation_struct.go,這個程序還列出了效驗出錯字段的一些信息,
package main import ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { FirstName string `validate:"required"` LastName string `validate:"required"` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` Addresses []*Address `validate:"required,dive,required"` } type Address struct { Street string `validate:"required"` City string `validate:"required"` Planet string `validate:"required"` Phone string `validate:"required"` } func main() { address := &Address{ Street: "Eavesdown Docks", Planet: "Persphone", Phone: "none", } user := &User{ FirstName: "Badger", LastName: "Smith", Age: 135, Email: "Badger.Smith@gmail.com", Addresses: []*Address{address}, } validate := validator.New() err := validate.Struct(user) if err != nil { fmt.Println("=== error msg ====") fmt.Println(err) if _, ok := err.(*validator.InvalidValidationError); ok { fmt.Println(err) return } fmt.Println("\r\n=========== error field info ====================") for _, err := range err.(validator.ValidationErrors) { // 列出效驗出錯字段的信息 fmt.Println("Namespace: ", err.Namespace()) fmt.Println("Fild: ", err.Field()) fmt.Println("StructNamespace: ", err.StructNamespace()) fmt.Println("StructField: ", err.StructField()) fmt.Println("Tag: ", err.Tag()) fmt.Println("ActualTag: ", err.ActualTag()) fmt.Println("Kind: ", err.Kind()) fmt.Println("Type: ", err.Type()) fmt.Println("Value: ", err.Value()) fmt.Println("Param: ", err.Param()) fmt.Println() } // from here you can create your own error messages in whatever language you wish return } }
運行 輸出:
$ go run validation_struct.go
=== error msg ====
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
Key: 'User.Addresses[0].City' Error:Field validation for 'City' failed on the 'required' tag=========== error field info ====================
Namespace: User.Age
Fild: Age
StructNamespace: User.Age
StructField: Age
Tag: lte
ActualTag: lte
Kind: uint8
Type: uint8
Value: 135
Param: 130Namespace: User.Addresses[0].City
Fild: City
StructNamespace: User.Addresses[0].City
StructField: City
Tag: required
ActualTag: required
Kind: string
Type: string
Value:
Param:
還能夠給字段加一些其餘tag信息,方面form,json的解析,以下:
type User struct { FirstName string `form:"firstname" json:"firstname" validate:"required"` LastName string `form:"lastname" json:"lastname" validate:"required"` Age uint8 ` form:"age" json:"age"validate:"gte=0,lte=130"` Email string ` form:"email" json:"email" validate:"required,email"` }
用戶自定義函數驗證字段是否合法,效驗是否正確。
customer_tag.go:
package main import ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { Name string `form:"name" json:"name" validate:"required,CustomerValidation"` //注意:required和CustomerValidation之間不能有空格,不然panic。CustomerValidation:自定義tag-函數標籤 Age uint8 ` form:"age" json:"age" validate:"gte=0,lte=80"` //注意:gte=0和lte=80之間不能有空格,不然panic } var validate *validator.Validate func main() { validate = validator.New() validate.RegisterValidation("CustomerValidation", CustomerValidationFunc) //註冊自定義函數,前一個參數是struct裏tag自定義,後一個參數是自定義的函數 user := &User{ Name: "jimmy", Age: 86, } fmt.Println("first value: ", user) err := validate.Struct(user) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } user.Name = "tom" user.Age = 29 fmt.Println("second value: ", user) err = validate.Struct(user) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } } // 自定義函數 func CustomerValidationFunc(f1 validator.FieldLevel) bool { // f1 包含了字段相關信息 // f1.Field() 獲取當前字段信息 // f1.Param() 獲取tag對應的參數 // f1.FieldName() 獲取字段名稱 return f1.Field().String() == "jimmy" }
運行輸出:
$ go run customer.go
first value: &{jimmy 86}
Err(s):
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
second value: &{tom 29}
Err(s):
Key: 'User.Name' Error:Field validation for 'Name' failed on the 'CustomerValidation' tag
**注意:
上面代碼user struct
定義中 ,validate
裏的required和CustomerValidation之間不能有空格,不然運行時報panic錯誤:panic: Undefined validation function ' CustomerValidation' on field 'Name'
不經過字段tag自定義函數,直接註冊函數。
https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go
customer1.go
package main import ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { FirstName string `json:firstname` LastName string `json:lastname` Age uint8 `validate:"gte=0,lte=130"` Email string `validate:"required,email"` FavouriteColor string `validate:"hexcolor|rgb|rgba"` } var validate *validator.Validate func main() { validate = validator.New() validate.RegisterStructValidation(UserStructLevelValidation, User{}) user := &User{ FirstName: "", LastName: "", Age: 30, Email: "TestFunc@126.com", FavouriteColor: "#000", } err := validate.Struct(user) if err != nil { fmt.Println(err) } } func UserStructLevelValidation(sl validator.StructLevel) { user := sl.Current().Interface().(User) if len(user.FirstName) == 0 && len(user.LastName) == 0 { sl.ReportError(user.FirstName, "FirstName", "firstname", "firstname", "") sl.ReportError(user.LastName, "LastName", "lastname", "lastname", "") } }
運行輸出:
$ go run customer1.go
Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'firstname' tag
Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'lastname' tag
https://github.com/go-playground/validator/blob/master/_examples/custom/main.go
validate.RegisterCustomTypeFunc:驗證類型的自定義函數
customer2.go:
package main import ( "database/sql" "database/sql/driver" "fmt" "reflect" "github.com/go-playground/validator/v10" ) type DbBackedUser struct { Name sql.NullString `validate:"required"` Age sql.NullInt64 `validate:"required"` } var validate *validator.Validate func main() { validate = validator.New() validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) // build object for validation x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}} err := validate.Struct(x) if err != nil { fmt.Printf("Err(s):\n%+v\n", err) } } func ValidateValuer(field reflect.Value) interface{} { if valuer, ok := field.Interface().(driver.Valuer); ok { val, err := valuer.Value() if err == nil { return val } // handle the error how you want } return nil }
運行輸出:
$ go run customer.go
Err(s):
Key: 'DbBackedUser.Name' Error:Field validation for 'Name' failed on the 'required' tag
Key: 'DbBackedUser.Age' Error:Field validation for 'Age' failed on the 'required' tag
注意,這個函數:
RegisterCustomTypeFunc,它上面有2行註釋:
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
//
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
它是一個驗證數據類型自定義函數,NOTE:這個方法不是線程安全的