前言
在web后端开发中经常会遇到数据验证的问题,对于前后端分离的web应用来说,后端对前端传来的数据应持有完全不信任的态度,我们要验证前端发来的数据是否包含所有必要字段,每个字段的数据是否符合我们的需求等等。这个时候普通的验证方法比较繁琐,在go中我们可以使用validator这个包来进行数据验证。
作者水平有限,有任何问题欢迎在文章下方留言,谢谢!
安装
validator包安装:
go get github.com/go-playground/validator/v10
validator包的验证提示默认是英文的,如果需要翻译成中文则还需安装验证提示翻译包:
go get github.com/go-playground/locales
go get github.com/go-playground/universal-translator
使用方法
将验证规则写在struct对应字段的tag里,validator包会通过反射(reflect)获取struct的tag,进行数据验证。
示例:
package main
// validator数据验证demo
// github.com/go-playground/validator/v10
import (
"fmt"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zhTranslations "github.com/go-playground/validator/v10/translations/zh"
"strings"
)
type User struct {
UserId string `form:"userId" validate:"required,min=5,max=20"`
Password string `form:"password" validate:"required,min=6,max=25"`
Email string `form:"email" validate:"omitempty,email"`
}
func main() {
daf := User{
UserId: "58888888",
Password: "12345678",
Email: "1234@",
}
// 实例化验证对象
var validate = validator.New()
err := validate.Struct(daf)
if err != nil {
trans := validateTransInit(validate)
verrs := err.(validator.ValidationErrors)
errs := make(map[string]string)
for key, value := range verrs.Translate(trans) {
errs[key[strings.Index(key, ".")+1:]] = value
}
fmt.Println(errs)
}
}
// 数据验证翻译器
func validateTransInit(validate *validator.Validate) ut.Translator {
// 万能翻译器,保存所有的语言环境和翻译数据
uni := ut.New(zh.New())
// 翻译器
trans, _ := uni.GetTranslator("zh")
//验证器注册翻译器
err := zhTranslations.RegisterDefaultTranslations(validate, trans)
if err!=nil {
fmt.Println(err)
}
return trans
}
运行结果:
map[Email:Email必须是一个有效的邮箱]
验证规则
一下列举一部分验证规则,详细验证规则请参考文档:
https://pkg.go.dev/gopkg.in/go-playground/validator.v10
标记 | 标记说明 | 例 |
---|---|---|
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" |
min | 最大值 | Field validate:"min=1" |
max | 最小值 | Field validate:"max=2" |
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" |
lowercase | 符串值是否只包含小写字符 | Field validate:"lowercase" |
uppercase | 符串值是否只包含大写字符 | Field validate:"uppercase" |
字符串值包含一个有效的电子邮件 | Field validate:"email" | |
json | 字符串值是否为有效的 JSON | Field validate:"json" |
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" |
跨字段验证
如果你想实现让用户输入两次邮箱以保证用户对该邮箱确认无误,后台则需要比较用户输入的两次邮箱是否一致,这个时候跨字段验证就派上用场了。
示例:
type User struct {
Email string `form:"email" validate:"required,email"`
ConfirmedEmail string `form:"confirmedEmail" validate:"required,mail,eqfield=Email"`
}
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" |