golang之數據驗證validator
前言
普通驗證對struct的數據方法比較繁瑣,這里介紹一個使用比較多的包:validator
原理
將驗證規則寫在struct對字段tag里,在通過反射獲取struct的tag,實現數據驗證
安裝
go get github.com/go-playground/validator
標記之間特殊符號說明
- 逗號(,):把多個驗證標記隔開。注意:逗號前面和后面都不能有空格,否則panic
- 橫線(-):跳過該字段不驗證
- 豎線(|):使用多個驗證標記,但是只需要滿足其中一個即可
- required:必填
- omitempty:如果字段未設置,則忽略它
特殊字符串驗證
- email:驗證字符串是email格式。默認為必填
- url:驗證字符串是URL格式。默認為必填
- uri:字段值是否包含有效的uri,validate:"uri"
- ip:字段值是否包含有效的IP地址,validate:"ip"
- ipv4:字段值是否包含有效的ipv4地址,validate:"ipv4"
- ipv6:字段值是否包含有效的ipv6地址,validate:"ipv6"
不跨字段范圍驗證規則
- max&min:max字符串最大長度,min字符串最小長度
- len:len字符串長度必須為n,或者是數組、切片、map的len的值
- eq:數字等於n
- ne:數字不等n
- gt:數字大於n
- gte:數字大於等於n
- lt:小於n
- lte:小於等於n
示例(特殊字符串和不跨字段范圍驗證規則)
package main
import (
"log"
"github.com/go-playground/validator"
)
type Users struct {
Phone string `validate:"required"` // 必填
Email string `validate:"email"` // 驗證字符串是email格式。默認為必填
Url string `validate:"url"` // 驗證字符串是URL格式。默認為必填
Passwd string `validate:"required,max=20,min=6"` // max字符串最大長度,min字符串最小長度
Code string `validate:"required,len=6"` // len字符串長度必須為n,或者是數組、切片、map的len的值
Eq int `validate:"eq=4"` // eq數字等於n
Ne int `validate:"ne=4"` // ne數字不等n
Gt int `validate:"gt=4"` // gt數字大於n
Gte int `validate:"gte=4"` // gte數字大於等於n
Lt int `validate:"lt=4"` // lt小於n
Lte int `validate:"lte=4"` // lte小於等於
}
func init() {
log.SetFlags(log.Ldate | log.Lshortfile | log.Ltime)
}
func main() {
users := Users{
Phone: "1326654487",
Email: "1843121593@qq.com",
Url: "https://blog.csdn.net/guyan0319/article/details/105918559",
Passwd: "123456",
Code: "123456",
Eq: 4,
Ne: 3,
Gt: 5,
Gte: 4,
Lt: 3,
Lte: 4,
}
log.Printf("users:%+v\n", users)
validate := validator.New()
validatErr := validate.Struct(&users)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
字符串驗證
- contains:包含參數子串。validate:"contains=ysm" (字段的字符串值包含ysm)
- excludes:不包含參數子串,validate:"excludes=tom" (字段的字符串值不包含tom)
- startswith:以參數子串為前綴,validate:"startswith=golang"
- endswith:以參數子串為后綴,validate:"startswith=world"
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Teacher struct {
Contains string `validate:"contains=ysm"` // 包含參數子串。validate:"contains=ysm" (字段的字符串值包含ysm)
Excludes string `validate:"excludes=tom"` // excludes:不包含參數子串,validate:"excludes=tom" (字段的字符串值不包含tom)
Startswith string `validate:"startswith=start"` // startswith:以參數子串為前綴,validate:"startswith=golang"
Endswith string `validate:"endswith=end"` // endswith:以參數子串為后綴,validate:"startswith=world"
}
func teacher() {
teacher := Teacher{
Contains: "ysmisgood",
Excludes: "isgood",
Startswith: "startgogo",
Endswith: "gogoend",
}
log.Printf("teacher:%+v\n", teacher)
validate := validator.New()
validatErr := validate.Struct(&teacher)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
func main(){
teacher()
}
跨字段驗證
- eqfield=Field: 必須等於 Field 的值
- nefield=Field: 必須不等於 Field 的值
- gtfield=Field: 必須大於 Field 的值
- gtefield=Field: 必須大於等於 Field 的值
- ltfield=Field: 必須小於 Field 的值
- ltefield=Field: 必須小於等於 Field 的值
- eqcsfield:跨不同結構體字段驗證,比如說 Struct1 Filed1,與結構體Struct2 Field2相等 (字段之間為包含關系,並且只能是在Struct1 Filed1 = Struct2 Field2,但是不能Struct2 Field2 = Struct1 Filed1)
- necsfield=Other.Field: 必須不等於 struct Other 中 Field 的值
- gtcsfield=Other.Field: 必須大於 struct Other 中 Field 的值
- gtecsfield=Other.Field: 必須大於等於 struct Other 中 Field 的值;
- ltcsfield=Other.Field: 必須小於 struct Other 中 Field 的值;
- ltecsfield=Other.Field: 必須小於等於 struct Other 中 Field 的值;
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Student struct {
Name string `validate:"required,eqcsfield=Pen.StudentName"` // eqcsfield:Name的值必須等於Pen.StudentName的值
Passwd string `validate:"required,max=20,min=6"`
Repasswd string `validate:"required,max=20,min=6,eqfield=Passwd"` // eqfield必須等於passwd的值
Pen struct {
StudentName string `validate:"required"`
}
}
func student() {
student := Student{
Name: "ysm",
Passwd: "123456",
Repasswd: "123456",
Pen: struct {
StudentName string `validate:"required"`
}{StudentName: "ysm"},
}
log.Printf("student:%+v\n", student)
validate := validator.New()
validatErr := validate.Struct(&student)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
func main(){
student()
}
自定義類型
- 主要使用validator.New().RegisterValidation("tagName",tagFunc)
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Users struct {
Phone string `validate:"required,PhoneValidationErrors"` // 必填
Email string `validate:"email"` // 驗證字符串是email格式。默認為必填
Url string `validate:"url"` // 驗證字符串是URL格式。默認為必填
Passwd string `validate:"required,max=20,min=6"` // max字符串最大長度,min字符串最小長度
Code string `validate:"required,len=6"` // len字符串長度必須為n,或者是數組、切片、map的len的值
Eq int `validate:"eq=4"` // eq數字等於n
Ne int `validate:"ne=4"` // ne數字不等n
Gt int `validate:"gt=4"` // gt數字大於n
Gte int `validate:"gte=4"` // gte數字大於等於n
Lt int `validate:"lt=4"` // lt小於n
Lte int `validate:"lte=4"` // lte小於等於
}
func main() {
users := Users{
Phone: "13345679878",
Email: "1843121593@qq.com",
Url: "https://blog.csdn.net/guyan0319/article/details/105918559",
Passwd: "123456",
Code: "123456",
Eq: 4,
Ne: 3,
Gt: 5,
Gte: 4,
Lt: 3,
Lte: 4,
}
log.Printf("users:%+v\n", users)
validate := validator.New()
// 注冊自定義函數
_ = validate.RegisterValidation("PhoneValidationErrors", PhoneValidationErrors)
validatErr := validate.Struct(&users)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
// 返回TRUE則不會報錯,返回FALSE則會報錯
func PhoneValidationErrors(fl validator.FieldLevel) bool {
return fl.Field().String() == "13345679878"
}