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
- 必须是有效的URLalpha
- 只能包含字母字符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 语言中功能强大且灵活的数据验证工具,它提供了:
- 丰富的内置验证规则
- 支持自定义验证函数
- 嵌套结构验证能力
- 跨字段验证
- 国际化支持
- 详细的错误报告
通过合理使用 validate 库,可以大大简化 Go 应用程序中的数据验证工作,提高代码的健壮性和安全性。