自定义验证器
7 个预定义自定义验证器详解
自定义验证器
Bamboo Base 提供了 7 个自定义验证器,扩展了 go-playground/validator 的功能。
注册验证器
import (
"github.com/go-playground/validator/v10"
xValid "github.com/bamboo-services/bamboo-base-go/validator"
)
validate := validator.New()
if err := xValid.RegisterCustomValidators(validate); err != nil {
log.Fatal("验证器注册失败:", err)
}验证器列表
| 标签 | 说明 | 示例 |
|---|---|---|
strict_url | 严格 URL 验证 | binding:"strict_url" |
strict_uuid | 严格 UUID 验证 | binding:"strict_uuid" |
alphanum_underscore | 字母数字下划线 | binding:"alphanum_underscore" |
regexp | 正则表达式验证 | binding:"regexp=^[a-z]+$" |
enum_int | 整数枚举验证 | binding:"enum_int=0 1 2" |
enum_string | 字符串枚举验证 | binding:"enum_string=a b c" |
enum_float | 浮点数枚举验证 | binding:"enum_float=0.5 1.0" |
strict_url
严格的 URL 格式验证,仅支持 HTTP/HTTPS 协议。
验证规则
^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(/.*)?$使用示例
type Request struct {
Website string `binding:"strict_url" label:"网站地址"`
Avatar string `binding:"omitempty,strict_url" label:"头像URL"`
}有效值示例
http://example.comhttps://example.com/path/to/pagehttps://sub.domain.com
无效值示例
ftp://example.com(不支持 FTP)example.com(缺少协议)http://localhost(无顶级域名)
strict_uuid
严格的 UUID 格式验证(RFC 4122)。
验证规则
^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$使用示例
type Request struct {
ID string `binding:"required,strict_uuid" label:"唯一标识"`
ParentID string `binding:"omitempty,strict_uuid" label:"父级ID"`
}有效值示例
123e4567-e89b-12d3-a456-426614174000550e8400-e29b-41d4-a716-446655440000
alphanum_underscore
验证字符串仅包含字母、数字和下划线。
验证规则
^[a-zA-Z0-9_]+$使用示例
type Request struct {
Username string `binding:"required,alphanum_underscore,min=3,max=20" label:"用户名"`
Code string `binding:"alphanum_underscore" label:"编码"`
}有效值示例
user_nameUser123test_user_001
无效值示例
user-name(包含连字符)user name(包含空格)用户名(包含中文)
regexp
使用自定义正则表达式验证字符串。
使用示例
type Request struct {
// 用户名:6-64位字母数字下划线
Username string `binding:"regexp=^[a-zA-Z0-9_]{6,64}$" label:"用户名"`
// 密码:至少包含字母和数字,最少6位
Password string `binding:"regexp=^(?=.*[a-zA-Z])(?=.*[0-9]).{6,}$" label:"密码"`
// 手机号:中国大陆格式
Phone string `binding:"regexp=^1[3-9]\\d{9}$" label:"手机号"`
}注意事项
- 正则表达式必须是有效的 Go 正则语法
- 编译失败时验证返回 false
- 建议在服务端定义正则,避免性能问题
enum_int
验证整数值是否在指定枚举列表中。
支持类型
int,int8,int16,int32,int64uint,uint8,uint16,uint32,uint64- 基于以上类型的自定义类型
使用示例
type UserGender int8
type Request struct {
// 性别:0=未知, 1=男, 2=女
Gender UserGender `binding:"enum_int=0 1 2" label:"性别"`
// 状态:-1=禁用, 0=待审核, 1=正常
Status int `binding:"enum_int=-1 0 1" label:"状态"`
// 优先级:1-5
Priority uint8 `binding:"enum_int=1 2 3 4 5" label:"优先级"`
}参数格式
- 使用空格分隔枚举值
- 支持负数
- 必须提供至少一个有效整数
enum_string
验证字符串值是否在指定枚举列表中。
支持类型
string- 基于 string 的自定义类型
使用示例
type UserRole string
type Request struct {
// 角色:admin, user, guest
Role UserRole `binding:"enum_string=admin user guest" label:"角色"`
// 状态:active, pending, inactive
Status string `binding:"enum_string=active pending inactive" label:"状态"`
// 排序方式
OrderBy string `binding:"enum_string=created_at updated_at name" label:"排序字段"`
}注意事项
- 大小写敏感:
Admin和admin是不同的值 - 使用空格分隔枚举值
enum_float
验证浮点数值是否在指定枚举列表中。
支持类型
float32,float64- 基于以上类型的自定义类型
使用示例
type Rating float64
type Request struct {
// 评分:0.5 到 5.0,步长 0.5
Rating Rating `binding:"enum_float=0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0" label:"评分"`
// 折扣:10%, 20%, 50%
Discount float32 `binding:"enum_float=0.1 0.2 0.5" label:"折扣"`
}精度处理
使用 epsilon 容差(1e-9)进行浮点数比较,避免精度问题。
完整示例
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
xValid "github.com/bamboo-services/bamboo-base-go/validator"
)
type UserGender int8
type UserRole string
type CreateUserRequest struct {
Username string `json:"username" binding:"required,alphanum_underscore,min=3,max=20"`
Password string `json:"password" binding:"required,regexp=^(?=.*[a-zA-Z])(?=.*[0-9]).{6,}$"`
Email string `json:"email" binding:"required,email"`
Website string `json:"website" binding:"omitempty,strict_url"`
Gender UserGender `json:"gender" binding:"enum_int=0 1 2"`
Role UserRole `json:"role" binding:"enum_string=admin user guest"`
}
func main() {
// 注册自定义验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
xValid.RegisterCustomValidators(v)
}
r := gin.Default()
r.POST("/users", func(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 处理请求...
})
r.Run()
}