一、介绍
validator
是Gin
官方默认的验证器,基于结构和单个字段的tag
标签实现值验证。
它具有以下独特功能:
- 使用验证标记或自定义验证程序进行跨字段和跨结构验证。
- Slice、Array 和 Map,允许验证多维字段的任何或所有级别。
- 能够深入了解映射键和值以进行验证
- 通过在验证之前确定类型接口的基础类型来处理类型接口。
- 处理自定义字段类型,如 sql 驱动程序 Valuer 请参阅 Valuer
- 别名验证标记,允许将多个验证映射到单个标记,以便更轻松地在结构上定义验证
- 例如,提取自定义字段名称可以指定在验证时提取JSON名称,并在生成的FieldError中使用它
- 可定制的 i18n 感知错误消息,即将错误信息按中文输出。
二、常用校验规则
标记 | 标记说明 | 例 |
---|---|---|
required | 必填 | Field或Struct validate:"required" |
omitempty | 空时忽略 | Field或Struct validate:"omitempty" |
len | 长度 | Field validate:"len=0" |
eq | 等于 | Field validate:"eq=0" |
gt | 大于 | Field validate:"gt=0" |
gte | 大于等于 | Field validate:"gte=0" |
lt | 小于 | Field validate:"lt=0" |
lte | 小于等于 | Field validate:"lte=0" |
eqfield | 同一结构体字段相等 | Field validate:"eqfield=Field2" |
nefield | 同一结构体字段不相等 | Field validate:"nefield=Field2" |
gtfield | 大于同一结构体字段 | Field validate:"gtfield=Field2" |
gtefield | 大于等于同一结构体字段 | Field validate:"gtefield=Field2" |
ltfield | 小于同一结构体字段 | Field validate:"ltfield=Field2" |
ltefield | 小于等于同一结构体字段 | Field validate:"ltefield=Field2" |
eqcsfield | 跨不同结构体字段相等 | Struct1.Field validate:"eqcsfield=Struct2.Field2" |
necsfield | 跨不同结构体字段不相等 | Struct1.Field validate:"necsfield=Struct2.Field2" |
gtcsfield | 大于跨不同结构体字段 | Struct1.Field validate:"gtcsfield=Struct2.Field2" |
gtecsfield | 大于等于跨不同结构体字段 | Struct1.Field validate:"gtecsfield=Struct2.Field2" |
ltcsfield | 小于跨不同结构体字段 | Struct1.Field validate:"ltcsfield=Struct2.Field2" |
ltecsfield | 小于等于跨不同结构体字段 | Struct1.Field validate:"ltecsfield=Struct2.Field2" |
min | 最大值 | Field validate:"min=1" |
max | 最小值 | Field validate:"max=2" |
structonly | 仅验证结构体,不验证任何结构体字段 | Struct validate:"structonly" |
nostructlevel | 不运行任何结构级别的验证 | Struct validate:"nostructlevel" |
dive | 向下延伸验证,多层向下需要多个dive标记 | [][]string validate:"gt=0,dive,len=1,dive,required" |
dive Keys & EndKeys | 与dive同时使用,用于对map对象的键的和值的验证,keys为键,endkeys为值 | map[string]string `validate:”gt=0,dive,keys,eq=1 |
required_with | 其他字段其中一个不为空且当前字段不为空 | Field validate:"required_with=Field1 Field2" |
required_with_all | 其他所有字段不为空且当前字段不为空 | Field validate:"required_with_all=Field1 Field2" |
required_without | 其他字段其中一个为空且当前字段不为空 | Field `validate:”required_without=Field1 Field2” |
required_without_all | 其他所有字段为空且当前字段不为空 | Field validate:"required_without_all=Field1 Field2" |
isdefault | 是默认值 | Field validate:"isdefault=0" |
oneof | 其中之一 | Field validate:"oneof=5 7 9" |
containsfield | 字段包含另一个字段 | Field validate:"containsfield=Field2" |
excludesfield | 字段不包含另一个字段 | Field validate:"excludesfield=Field2" |
unique | 是否唯一,通常用于切片或结构体 | Field validate:"unique" |
alphanum | 字符串值是否只包含 ASCII 字母数字字符 | Field validate:"alphanum" |
alphaunicode | 字符串值是否只包含 unicode 字符 | Field validate:"alphaunicode" |
alphanumunicode | 字符串值是否只包含 unicode 字母数字字符 | Field validate:"alphanumunicode" |
numeric | 字符串值是否包含基本的数值 | Field validate:"numeric" |
hexadecimal | 字符串值是否包含有效的十六进制 | Field validate:"hexadecimal" |
hexcolor | 字符串值是否包含有效的十六进制颜色 | Field validate:"hexcolor" |
lowercase | 符串值是否只包含小写字符 | Field validate:"lowercase" |
uppercase | 符串值是否只包含大写字符 | Field validate:"uppercase" |
字符串值包含一个有效的电子邮件 | Field validate:"email" | |
json | 字符串值是否为有效的 JSON | Field validate:"json" |
file | 符串值是否包含有效的文件路径,以及该文件是否存在于计算机上 | Field validate:"file" |
url | 符串值是否包含有效的 url | Field validate:"url" |
uri | 符串值是否包含有效的 uri | Field validate:"uri" |
base64 | 字符串值是否包含有效的 base64值 | Field validate:"base64" |
contains | 字符串值包含子字符串值 | Field validate:"contains=@" |
containsany | 字符串值包含子字符串值中的任何字符 | Field validate:"containsany=abc" |
containsrune | 字符串值包含提供的特殊符号值 | Field validate:"containsrune=☢" |
excludes | 字符串值不包含子字符串值 | Field validate:"excludes=@" |
excludesall | 字符串值不包含任何子字符串值 | Field validate:"excludesall=abc" |
excludesrune | 字符串值不包含提供的特殊符号值 | Field validate:"containsrune=☢" |
startswith | 字符串以提供的字符串值开始 | Field validate:"startswith=abc" |
endswith | 字符串以提供的字符串值结束 | Field validate:"endswith=abc" |
ip | 字符串值是否包含有效的 IP 地址 | Field validate:"ip" |
ipv4 | 字符串值是否包含有效的 ipv4地址 | Field validate:"ipv4" |
datetime | 字符串值是否包含有效的 日期 | Field validate:"datetime" |
三、在 Blog 项目中的具体运用
1、业务流程分析
在添加用户时校验数据,要求:
- 用户名必填,长度4-12位
- 密码必填,长度6-20位
- 角色码必须≥
2
,因为1
表示管理员
2、添加Model
的tag
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null" json:"username" validate:"required,min=4,max=12" label:"用户名"`
Password string `gorm:"type:varchar(100);not null" json:"password" validate:"required,min=6,max=20" label:"密码"`
Role int `gorm:"type:int;default:2" json:"role" validate:"required,gte=2" label:"角色码"` //validate 将 0 视作空值。所以修改为管理员:role=1;游客role=2
}
★3、在通用工具包utils/ 下新建 validator.go
package validator
import (
"github.com/go-playground/locales/zh_Hans_CN"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zhs "github.com/go-playground/validator/v10/translations/zh"
"go-vue-blog/utils/errmsg"
"reflect"
)
// Validator 传入待检验的对象实例。错误则返回汉化的错误信息,正确则返回空串
// 在添加用户时调用
func Validator(data interface{}) (string, int) {
validate := validator.New() // 实例化验证器
uni := ut.New(zh_Hans_CN.New()) // 设置成中文翻译器
trans, _ := uni.GetTranslator("zh_Hans_CN") //获取翻译词典
// 注册翻译器
_ = zhs.RegisterDefaultTranslations(validate, trans)
//当用户名出错时,返回的信息为:"Username长度不能超过12个字符" 希望字段也是中文:
//1. 在 Model 的字段后tag添加label对应中文名
//2. 使用 RegisterTagNameFunc() 获取并返回该中文
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
label := field.Tag.Get("label")
return label
})
//验证器验证
`err := validate.Struct(data)`
if err != nil {
// err 类型断言成功,确实为 ValidationErrors 将值赋给 v
for _, v := range err.(validator.ValidationErrors) {
return v.Translate(trans), errmsg.ERROR
}
}
return "", errmsg.SUCCESS
}
4、在API层的user.go的AddUser() 调用
// AddUser 添加用户
func AddUser(c *gin.Context) {
...
msg, errCode := validator.Validator(&user)
if errCode != errmsg.SUCCESS {...}
...
}