golang数据验证与过滤插件库validate的使用

Golang数据验证与过滤插件库validate的使用

validate是一个通用的Go数据验证和过滤工具库,支持快速验证Map、Struct、Request(Form、JSON、url.Values、UploadedFile)数据,并提供数据过滤/转换功能。

主要特性

  • 支持快速验证Map、Struct、Request数据
  • 支持在验证前进行数据过滤/转换
  • 支持添加自定义验证器和过滤器
  • 支持场景设置,在不同场景下验证不同字段
  • 支持自定义错误消息和字段翻译
  • 内置国际化错误消息,支持en、zh-CN、zh-TW
  • 内置70+常用验证器和常见数据类型过滤器
  • 可在任何框架中使用,如Gin、Echo、Chi等

验证结构体

使用结构体标签配置

package main

import (
	"fmt"
	"time"

	"github.com/gookit/validate"
)

// UserForm struct
type UserForm struct {
	Name     string    `validate:"required|min_len:7" message:"required:{field} is required" label:"User Name"`
	Email    string    `validate:"email" message:"email is invalid" label:"User Email"`
	Age      int       `validate:"required|int|min:1|max:99" message:"int:age must int|min:age min value is 1"`
	CreateAt int       `validate:"min:1"`
	Safe     int       `validate:"-"`
	UpdateAt time.Time `validate:"required" message:"update time is required"`
	Code     string    `validate:"customValidator"`
	// ExtInfo nested struct
	ExtInfo struct{
		Homepage string `validate:"required" label:"Home Page"`
		CityName string
	} `validate:"required" label:"Home Page"`
}

// CustomValidator custom validator in the source struct.
func (f UserForm) CustomValidator(val string) bool {
	return len(val) == 4
}

使用结构体方法配置

package main

import (
	"fmt"
	"time"

	"github.com/gookit/validate"
)

// UserForm struct
type UserForm struct {
	Name     string    `validate:"required|min_len:7"`
	Email    string    `validate:"email"`
	Age      int       `validate:"required|int|min:1|max:99"`
	CreateAt int       `validate:"min:1"`
	Safe     int       `validate:"-"`
	UpdateAt time.Time `validate:"required"`
	Code     string    `validate:"customValidator"`
	// ExtInfo nested struct
	ExtInfo struct{
		Homepage string `validate:"required"`
		CityName string
	} `validate:"required"`
}

// CustomValidator custom validator in the source struct.
func (f UserForm) CustomValidator(val string) bool {
	return len(val) == 4
}

// ConfigValidation config the Validation
func (f UserForm) ConfigValidation(v *validate.Validation) {
	v.WithScenes(validate.SValues{
		"add":    []string{"ExtInfo.Homepage", "Name", "Code"},
		"update": []string{"ExtInfo.CityName", "Name"},
	})
}

// Messages you can custom validator error messages. 
func (f UserForm) Messages() map[string]string {
	return validate.MS{
		"required": "oh! the {field} is required",
		"email": "email is invalid",
		"Name.required": "message for special field",
		"Age.int": "age must int",
		"Age.min": "age min value is 1",
	}
}

// Translates you can custom field translates. 
func (f UserForm) Translates() map[string]string {
	return validate.MS{
		"Name": "User Name",
		"Email": "User Email",
		"ExtInfo.Homepage": "Home Page",
	}
}

创建和验证

package main

import (
  "fmt"

  "github.com/gookit/validate"
)

func main() {
	u := &UserForm{
		Name: "inhere",
	}
	
	v := validate.Struct(u)
	// v := validate.New(u)

	if v.Validate() { // validate ok
		// do something ...
	} else {
		fmt.Println(v.Errors) // all error messages
		fmt.Println(v.Errors.One()) // returns a random error message text
		fmt.Println(v.Errors.OneError()) // returns a random error
		fmt.Println(v.Errors.Field("Name")) // returns error messages of the field 
	}
}

验证Map

package main

import (
"fmt"

"github.com/gookit/validate"
)

func main()  {
	m := map[string]any{
		"name":  "inhere",
		"age":   100,
		"oldSt": 1,
		"newSt": 2,
		"email": "some@email.com",
		"tags": []string{"go", "php", "java"},
	}

	v := validate.Map(m)
	// v := validate.New(m)
	v.AddRule("name", "required")
	v.AddRule("name", "minLen", 7)
	v.AddRule("age", "max", 99)
	v.AddRule("age", "min", 1)
	v.AddRule("email", "email")
	
	// can also
	v.StringRule("age", "required|int|min:1|max:99")
	v.StringRule("name", "required|minLen:7")
	v.StringRule("tags", "required|slice|minlen:1")
	// feat: support check sub-item in slice
	v.StringRule("tags.*", "required|string|min_len:7")

	// v.WithScenes(map[string]string{
	//	 "create": []string{"name", "email"},
	//	 "update": []string{"name"},
	// })
	
	if v.Validate() { // validate ok
		safeData := v.SafeData()
		// do something ...
	} else {
		fmt.Println(v.Errors) // all error messages
		fmt.Println(v.Errors.One()) // returns a random error message text
	}
}

验证Request

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gookit/validate"
)

// UserForm struct
type UserForm struct {
	Name     string
	Email    string
	Age      int
	CreateAt int
	Safe     int
	UpdateAt time.Time
	Code     string
}

func main()  {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, err := validate.FromRequest(r)
		if err != nil {
			panic(err)
		}

		v := data.Create()
		// setting rules
		v.FilterRule("age", "int") // convert value to int
		
		v.AddRule("name", "required")
		v.AddRule("name", "minLen", 7)
		v.AddRule("age", "max", 99)
		v.StringRule("code", `required|regex:\d{4,6}`)

		if v.Validate() { // validate ok
			// safeData := v.SafeData()
			userForm := &UserForm{}
			v.BindSafeData(userForm)

			// do something ...
			fmt.Println(userForm.Name)
		} else {
			fmt.Println(v.Errors) // all error messages
			fmt.Println(v.Errors.One()) // returns a random error message text
		}
	})

	http.ListenAndServe(":8090", handler)
}

添加自定义验证器

// 添加全局验证器
validate.AddValidator("myCheck0", func(val any) bool {
	// do validate val ...
	return true
})

// 添加临时验证器
v := validate.Struct(u)
v.AddValidator("myFunc3", func(val any) bool {
	// do validate val ...
	return true
})

添加自定义过滤器

// 添加全局过滤器
validate.AddFilter("myToIntFilter0", func(val any) int {
	// do filtering val ...
	return 1
})

// 添加临时过滤器
v := validate.New(&someStrcut{})
v.AddFilter("myToIntFilter0", func(val any) int {
	// do filtering val ...
	return 1
})

在Gin框架中使用

package main
import (
    "github.com/gin-gonic/gin/binding"
    "github.com/gookit/validate"
)

// implements the binding.StructValidator
type customValidator struct {}

func (c *customValidator) ValidateStruct(ptr any) error {
    v := validate.Struct(ptr)
    v.Validate() // do validating
    
    if v.Errors.Empty() {
	return nil
    }

    return v.Errors
}

func (c *customValidator) Engine() any {
    return nil
}

func main()  {
	// ...

    // after init gin, set custom validator
    binding.Validator = &customValidator{}
}

内置验证器

验证器 描述
required 检查值是否为必填且不能为空
int 检查值是否为int类型
string 检查值是否为字符串类型
email 检查值是否为有效的电子邮件地址
min 检查值是否大于等于给定值
max 检查值是否小于等于给定值
range 检查值是否在给定范围内
len 检查值长度是否等于给定大小
regex 检查值是否能通过正则验证

完整列表请参考官方文档。

内置过滤器

过滤器 描述
int 将值转换为int类型
uint 将值转换为uint类型
float 将值转换为float类型
bool 将字符串值转换为bool
trim 清除字符串两边的空白字符
lower 将字符串转换为小写
upper 将字符串转换为大写

完整列表请参考官方文档。

validate是一个功能强大且灵活的验证库,可以满足各种数据验证需求。通过结构体标签、自定义验证器和过滤器,可以轻松实现复杂的业务验证逻辑。


更多关于golang数据验证与过滤插件库validate的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang数据验证与过滤插件库validate的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 数据验证与过滤插件库 validate 使用指南

validate 是 Go 语言中一个流行的数据验证库,它提供了简单而强大的方式来验证和过滤各种数据结构。下面我将详细介绍 validate 库的使用方法。

安装 validate 库

首先需要安装 validate 库:

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

基本用法

1. 简单验证

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type User struct {
	Name     string `validate:"required,min=3,max=32"`
	Email    string `validate:"required,email"`
	Age      int    `validate:"gte=18,lte=130"`
	Password string `validate:"required,min=8"`
}

func main() {
	validate := validator.New()

	user := User{
		Name:     "John Doe",
		Email:    "john@example.com",
		Age:      25,
		Password: "secure123",
	}

	err := validate.Struct(user)
	if err != nil {
		fmt.Println("Validation errors:", err)
	} else {
		fmt.Println("Validation passed!")
	}
}

2. 常用验证标签

validate 提供了多种内置验证标签:

  • required - 字段必须存在且不为零值
  • min - 最小值(数字)或最小长度(字符串)
  • max - 最大值(数字)或最大长度(字符串)
  • len - 固定长度
  • eq - 等于
  • ne - 不等于
  • gt - 大于
  • gte - 大于等于
  • lt - 小于
  • lte - 小于等于
  • email - 必须是有效的电子邮件地址
  • url - 必须是有效的URL
  • alpha - 只能包含字母字符
  • alphanum - 只能包含字母和数字字符
  • numeric - 必须是有效的数字
  • hexadecimal - 必须是有效的十六进制
  • uuid - 必须是有效的UUID

3. 自定义验证

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

// 自定义验证函数
func validateCountryCode(fl validator.FieldLevel) bool {
	countryCode := fl.Field().String()
	
	// 这里可以添加更复杂的验证逻辑
	validCodes := map[string]bool{
		"US": true,
		"CN": true,
		"JP": true,
		"UK": true,
	}
	
	return validCodes[countryCode]
}

type Address struct {
	CountryCode string `validate:"required,countrycode"`
	City        string `validate:"required"`
}

func main() {
	validate := validator.New()
	
	// 注册自定义验证函数
	_ = validate.RegisterValidation("countrycode", validateCountryCode)
	
	address := Address{
		CountryCode: "US",
		City:        "New York",
	}
	
	err := validate.Struct(address)
	if err != nil {
		fmt.Println("Validation errors:", err)
	} else {
		fmt.Println("Validation passed!")
	}
}

4. 验证嵌套结构

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type User struct {
	Name    string `validate:"required"`
	Age     int    `validate:"gte=18"`
	Address struct {
		Street string `validate:"required"`
		City   string `validate:"required"`
	} `validate:"required"`
}

func main() {
	validate := validator.New()

	user := User{
		Name: "Alice",
		Age:  25,
		Address: struct {
			Street string `validate:"required"`
			City   string `validate:"required"`
		}{
			Street: "123 Main St",
			City:   "Metropolis",
		},
	}

	err := validate.Struct(user)
	if err != nil {
		fmt.Println("Validation errors:", err)
	} else {
		fmt.Println("Validation passed!")
	}
}

5. 错误处理

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type RegistrationForm struct {
	Username string `validate:"required,min=3,max=32"`
	Email    string `validate:"required,email"`
	Password string `validate:"required,min=8"`
}

func main() {
	validate := validator.New()

	form := RegistrationForm{
		Username: "ab", // 太短
		Email:    "invalid-email",
		Password: "123", // 太短
	}

	err := validate.Struct(form)
	if err != nil {
		for _, err := range err.(validator.ValidationErrors) {
			fmt.Printf("Field: %s, Error: %s\n", err.Field(), err.Tag())
		}
	}
}

6. 验证单个字段

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

func main() {
	validate := validator.New()

	email := "invalid-email"
	err := validate.Var(email, "required,email")
	if err != nil {
		fmt.Println("Email validation failed:", err)
	} else {
		fmt.Println("Email is valid")
	}
}

高级功能

1. 跨字段验证

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type User struct {
	Password        string `validate:"required,min=8"`
	ConfirmPassword string `validate:"required,eqfield=Password"`
}

func main() {
	validate := validator.New()

	user := User{
		Password:        "secure123",
		ConfirmPassword: "secure123",
	}

	err := validate.Struct(user)
	if err != nil {
		fmt.Println("Validation errors:", err)
	} else {
		fmt.Println("Validation passed!")
	}
}

2. 自定义错误消息

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
	"reflect"
)

type User struct {
	Name string `validate:"required" label:"用户名"`
	Age  int    `validate:"gte=18" label:"年龄"`
}

func main() {
	validate := validator.New()

	// 注册自定义标签名函数
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := fld.Tag.Get("label")
		if name == "" {
			name = fld.Name
		}
		return name
	})

	user := User{
		Name: "",
		Age:  15,
	}

	err := validate.Struct(user)
	if err != nil {
		for _, err := range err.(validator.ValidationErrors) {
			switch err.Tag() {
			case "required":
				fmt.Printf("%s 是必填字段\n", err.Field())
			case "gte":
				fmt.Printf("%s 必须大于等于 %s\n", err.Field(), err.Param())
			}
		}
	}
}

3. 国际化错误消息

validate 库支持国际化错误消息,可以通过自定义翻译器实现:

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 User struct {
	Name string `validate:"required"`
	Age  int    `validate:"gte=18"`
}

func main() {
	validate := validator.New()
	
	// 设置中文翻译器
	zh_ch := zh.New()
	uni := ut.New(zh_ch, zh_ch)
	trans, _ := uni.GetTranslator("zh")
	_ = zh_translations.RegisterDefaultTranslations(validate, trans)

	user := User{
		Name: "",
		Age:  15,
	}

	err := validate.Struct(user)
	if err != nil {
		errs := err.(validator.ValidationErrors)
		for _, e := range errs {
			// 翻译错误信息
			fmt.Println(e.Translate(trans))
		}
	}
}

总结

validate 库是 Go 语言中功能强大且灵活的数据验证工具,它提供了:

  1. 丰富的内置验证规则
  2. 支持自定义验证函数
  3. 嵌套结构验证能力
  4. 跨字段验证
  5. 国际化支持
  6. 详细的错误报告

通过合理使用 validate 库,可以大大简化 Go 应用程序中的数据验证工作,提高代码的健壮性和安全性。

回到顶部