golang结构体与字段验证工具插件库validator的使用

Golang结构体与字段验证工具插件库validator的使用

简介

validator是一个用于结构体和字段验证的Go语言库,它基于标签(tag)实现验证功能。该库具有以下独特特性:

  • 通过验证标签或自定义验证器实现跨字段和跨结构体验证
  • 支持切片、数组和映射的多层级验证
  • 可以验证映射的键和值
  • 处理接口类型时会先确定其底层类型
  • 支持自定义字段类型如sql driver Valuer
  • 验证标签别名,允许将多个验证映射到单个标签
  • 可提取自定义字段名称
  • 支持可定制的国际化错误消息
  • 是gin框架的默认验证器

安装

使用go get安装:

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

然后在代码中导入:

import "github.com/go-playground/validator/v10"

基本使用示例

下面是一个完整的示例,展示如何使用validator验证结构体字段:

package main

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

// 定义一个用户结构体
type User struct {
	FirstName string `validate:"required"`          // 必填字段
	LastName  string `validate:"required"`          // 必填字段
	Age       uint   `validate:"gte=18,lte=130"`    // 年龄必须在18到130之间
	Email     string `validate:"required,email"`    // 必填且必须是有效邮箱格式
}

func main() {
	// 创建验证器实例
	validate := validator.New(validator.WithRequiredStructEnabled())

	// 创建测试用户
	user := &User{
		FirstName: "John",
		LastName:  "Doe",
		Age:       25,
		Email:     "john.doe@example.com",
	}

	// 验证结构体
	err := validate.Struct(user)
	if err != nil {
		// 如果有错误,转换为验证错误类型
		if validationErrors, ok := err.(validator.ValidationErrors); ok {
			for _, fieldError := range validationErrors {
				fmt.Printf("字段 %s 验证失败: %s\n", fieldError.Field(), fieldError.Tag())
			}
		}
		return
	}

	fmt.Println("用户数据验证通过")
}

验证标签说明

validator支持多种验证标签,以下是一些常用标签:

字段比较

标签 描述
eqfield 字段等于另一个字段
gtfield 字段大于另一个字段
gtefield 字段大于或等于另一个字段
ltfield 字段小于另一个字段
ltefield 字段小于或等于另一个字段
nefield 字段不等于另一个字段

字符串验证

标签 描述
alpha 仅字母
alphanum 字母数字
contains 包含指定字符串
startswith 以指定字符串开头
endswith 以指定字符串结尾
lowercase 小写字母
uppercase 大写字母

格式验证

标签 描述
email 邮箱格式
url URL格式
uuid UUID格式
datetime 日期时间格式
json JSON格式
base64 Base64字符串

数值验证

标签 描述
min 最小值
max 最大值
eq 等于
gt 大于
gte 大于等于
lt 小于
lte 小于等于

其他验证

标签 描述
required 必填字段
len 长度
oneof 值必须在指定列表中

高级示例

嵌套结构体验证

package main

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

// 地址结构体
type Address struct {
	Street string `validate:"required"`
	City   string `validate:"required"`
	Zip    string `validate:"required,len=6"`
}

// 用户结构体包含嵌套地址
type User struct {
	Name    string  `validate:"required"`
	Age     int     `validate:"gte=18"`
	Address Address `validate:"required"`
}

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

	user := User{
		Name: "Alice",
		Age:  25,
		Address: Address{
			Street: "123 Main St",
			City:   "New York",
			Zip:    "10001",
		},
	}

	err := validate.Struct(user)
	if err != nil {
		if validationErrors, ok := err.(validator.ValidationErrors); ok {
			for _, fieldError := range validationErrors {
				fmt.Printf("错误: 字段 %s 验证失败: %s\n", fieldError.Field(), fieldError.Tag())
			}
		}
		return
	}

	fmt.Println("用户数据验证通过")
}

自定义验证函数

package main

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

// 自定义验证函数
func validateCountryCode(fl validator.FieldLevel) bool {
	countryCode := fl.Field().String()
	// 简单的国家代码验证
	return countryCode == "US" || countryCode == "CN" || countryCode == "JP"
}

type User struct {
	Name        string `validate:"required"`
	CountryCode string `validate:"required,countrycode"` // 使用自定义验证标签
}

func main() {
	validate := validator.New()
	
	// 注册自定义验证函数
	_ = validate.RegisterValidation("countrycode", validateCountryCode)

	user := User{
		Name:        "Bob",
		CountryCode: "UK", // 无效的国家代码
	}

	err := validate.Struct(user)
	if err != nil {
		if validationErrors, ok := err.(validator.ValidationErrors); ok {
			for _, fieldError := range validationErrors {
				fmt.Printf("错误: 字段 %s 验证失败: %s\n", fieldError.Field(), fieldError.Tag())
			}
		}
		return
	}

	fmt.Println("用户数据验证通过")
}

错误处理

验证函数返回error类型。如果验证失败,可以将错误转换为validator.ValidationErrors类型来获取详细的验证错误信息:

err := validate.Struct(mystruct)
if err != nil {
    if validationErrors, ok := err.(validator.ValidationErrors); ok {
        for _, fieldError := range validationErrors {
            fmt.Printf("字段 %s 验证失败: %s\n", fieldError.Field(), fieldError.Tag())
        }
    }
}

性能

validator经过高度优化,性能表现优异。在MacBook Pro Max M3上的基准测试结果如下:

BenchmarkFieldSuccess-16                                                42461943                27.88 ns/op            0 B/op          0 allocs/op
BenchmarkFieldSuccessParallel-16                                        486632887                2.289 ns/op           0 B/op          0 allocs/op
BenchmarkFieldFailure-16                                                 9566167               121.3 ns/op           200 B/op          4 allocs/op
BenchmarkFieldFailureParallel-16                                        17551471                83.68 ns/op          200 B/op          4 allocs/op

总结

validator是一个功能强大且灵活的Go语言验证库,适用于各种验证场景。通过结构体标签可以轻松定义验证规则,同时也支持自定义验证函数和复杂的验证逻辑。


更多关于golang结构体与字段验证工具插件库validator的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang结构体与字段验证工具插件库validator的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang结构体与字段验证工具validator使用指南

validator是Go语言中最流行的结构体字段验证库之一,它通过结构体标签(tag)定义验证规则,可以方便地对结构体字段进行各种验证。

安装validator

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

基本使用

package main

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

type User struct {
	Name     string `validate:"required,min=2,max=50"`
	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:     "张三",
		Email:    "zhangsan@example.com",
		Age:      25,
		Password: "12345678",
	}

	err := validate.Struct(user)
	if err != nil {
		for _, err := range err.(validator.ValidationErrors) {
			fmt.Println(err.Field(), "字段验证失败:", err.Tag())
		}
		return
	}

	fmt.Println("验证通过")
}

常用验证标签

validator提供了丰富的内置验证规则:

  • required - 必填字段
  • min - 最小长度/数值
  • max - 最大长度/数值
  • len - 固定长度/数值
  • eq - 等于
  • ne - 不等于
  • gt - 大于
  • gte - 大于等于
  • lt - 小于
  • lte - 小于等于
  • email - 邮箱格式
  • url - URL格式
  • uuid - UUID格式
  • alpha - 仅字母
  • alphanum - 字母和数字
  • numeric - 数字
  • hexadecimal - 十六进制
  • contains - 包含指定字符串
  • excludes - 不包含指定字符串
  • startswith - 以指定字符串开头
  • endswith - 以指定字符串结尾

自定义验证

可以注册自定义验证函数:

package main

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

type User struct {
	Username string `validate:"required,username"`
}

func validateUsername(fl validator.FieldLevel) bool {
	username := fl.Field().String()
	// 自定义用户名验证逻辑
	return len(username) >= 5 && len(username) <= 20
}

func main() {
	validate := validator.New()
	_ = validate.RegisterValidation("username", validateUsername)

	user := User{Username: "user123"}
	
	err := validate.Struct(user)
	if err != nil {
		fmt.Println("验证失败:", err)
		return
	}
	
	fmt.Println("验证通过")
}

嵌套结构体验证

validator支持嵌套结构体的验证:

type Address struct {
	Street string `validate:"required"`
	City   string `validate:"required"`
	Planet string `validate:"required"`
	Phone  string `validate:"required"`
}

type User struct {
	Name    string  `validate:"required"`
	Address Address `validate:"required"`
}

func main() {
	validate := validator.New()
	
	user := User{
		Name: "李四",
		Address: Address{
			Street: "科技园路",
			City:   "深圳",
			Planet: "地球",
			Phone:  "13800138000",
		},
	}
	
	err := validate.Struct(user)
	// 处理验证结果...
}

国际化错误消息

可以自定义错误消息:

package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
	"gopkg.in/go-playground/validator.v9/translations/zh"
)

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

func main() {
	validate := validator.New()
	
	// 注册中文翻译
	zhT := zh.New()
	_ = zhT.RegisterDefaultTranslations(validate)
	
	user := User{
		Name: "",
		Age:  16,
	}
	
	err := validate.Struct(user)
	if err != nil {
		for _, err := range err.(validator.ValidationErrors) {
			fmt.Println(err.Translate(zhT))
		}
	}
}

输出类似:

姓名为必填字段
年龄必须大于或等于18

性能考虑

validator在首次验证时会缓存结构体的验证规则,后续验证会直接从缓存中读取,因此重复验证相同结构体时性能很高。

validator是Go语言中功能强大且易于使用的验证库,通过合理使用可以大大减少业务代码中的参数校验逻辑,提高代码的可读性和可维护性。

回到顶部