golang之数据验证validator
前言
普通验证对struct的数据方法比较繁琐,这里介绍一个使用比较多的包:validator
原理
将验证规则写在struct对字段tag里,在通过反射获取struct的tag,实现数据验证
安装
go get github.com/go-playground/validator
标记之间特殊符号说明
- 逗号(,):把多个验证标记隔开。注意:逗号前面和后面都不能有空格,否则panic
- 横线(-):跳过该字段不验证
- 竖线(|):使用多个验证标记,但是只需要满足其中一个即可
- required:必填
- omitempty:如果字段未设置,则忽略它
特殊字符串验证
- email:验证字符串是email格式。默认为必填
- url:验证字符串是URL格式。默认为必填
- uri:字段值是否包含有效的uri,validate:"uri"
- ip:字段值是否包含有效的IP地址,validate:"ip"
- ipv4:字段值是否包含有效的ipv4地址,validate:"ipv4"
- ipv6:字段值是否包含有效的ipv6地址,validate:"ipv6"
不跨字段范围验证规则
- max&min:max字符串最大长度,min字符串最小长度
- len:len字符串长度必须为n,或者是数组、切片、map的len的值
- eq:数字等于n
- ne:数字不等n
- gt:数字大于n
- gte:数字大于等于n
- lt:小于n
- lte:小于等于n
示例(特殊字符串和不跨字段范围验证规则)
package main
import (
"log"
"github.com/go-playground/validator"
)
type Users struct {
Phone string `validate:"required"` // 必填
Email string `validate:"email"` // 验证字符串是email格式。默认为必填
Url string `validate:"url"` // 验证字符串是URL格式。默认为必填
Passwd string `validate:"required,max=20,min=6"` // max字符串最大长度,min字符串最小长度
Code string `validate:"required,len=6"` // len字符串长度必须为n,或者是数组、切片、map的len的值
Eq int `validate:"eq=4"` // eq数字等于n
Ne int `validate:"ne=4"` // ne数字不等n
Gt int `validate:"gt=4"` // gt数字大于n
Gte int `validate:"gte=4"` // gte数字大于等于n
Lt int `validate:"lt=4"` // lt小于n
Lte int `validate:"lte=4"` // lte小于等于
}
func init() {
log.SetFlags(log.Ldate | log.Lshortfile | log.Ltime)
}
func main() {
users := Users{
Phone: "1326654487",
Email: "1843121593@qq.com",
Url: "https://blog.csdn.net/guyan0319/article/details/105918559",
Passwd: "123456",
Code: "123456",
Eq: 4,
Ne: 3,
Gt: 5,
Gte: 4,
Lt: 3,
Lte: 4,
}
log.Printf("users:%+v
", users)
validate := validator.New()
validatErr := validate.Struct(&users)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
字符串验证
- contains:包含参数子串。validate:"contains=ysm" (字段的字符串值包含ysm)
- excludes:不包含参数子串,validate:"excludes=tom" (字段的字符串值不包含tom)
- startswith:以参数子串为前缀,validate:"startswith=golang"
- endswith:以参数子串为后缀,validate:"startswith=world"
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Teacher struct {
Contains string `validate:"contains=ysm"` // 包含参数子串。validate:"contains=ysm" (字段的字符串值包含ysm)
Excludes string `validate:"excludes=tom"` // excludes:不包含参数子串,validate:"excludes=tom" (字段的字符串值不包含tom)
Startswith string `validate:"startswith=start"` // startswith:以参数子串为前缀,validate:"startswith=golang"
Endswith string `validate:"endswith=end"` // endswith:以参数子串为后缀,validate:"startswith=world"
}
func teacher() {
teacher := Teacher{
Contains: "ysmisgood",
Excludes: "isgood",
Startswith: "startgogo",
Endswith: "gogoend",
}
log.Printf("teacher:%+v
", teacher)
validate := validator.New()
validatErr := validate.Struct(&teacher)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
func main(){
teacher()
}
跨字段验证
- eqfield=Field: 必须等于 Field 的值
- nefield=Field: 必须不等于 Field 的值
- gtfield=Field: 必须大于 Field 的值
- gtefield=Field: 必须大于等于 Field 的值
- ltfield=Field: 必须小于 Field 的值
- ltefield=Field: 必须小于等于 Field 的值
- eqcsfield:跨不同结构体字段验证,比如说 Struct1 Filed1,与结构体Struct2 Field2相等 (字段之间为包含关系,并且只能是在Struct1 Filed1 = Struct2 Field2,但是不能Struct2 Field2 = Struct1 Filed1)
- necsfield=Other.Field: 必须不等于 struct Other 中 Field 的值
- gtcsfield=Other.Field: 必须大于 struct Other 中 Field 的值
- gtecsfield=Other.Field: 必须大于等于 struct Other 中 Field 的值;
- ltcsfield=Other.Field: 必须小于 struct Other 中 Field 的值;
- ltecsfield=Other.Field: 必须小于等于 struct Other 中 Field 的值;
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Student struct {
Name string `validate:"required,eqcsfield=Pen.StudentName"` // eqcsfield:Name的值必须等于Pen.StudentName的值
Passwd string `validate:"required,max=20,min=6"`
Repasswd string `validate:"required,max=20,min=6,eqfield=Passwd"` // eqfield必须等于passwd的值
Pen struct {
StudentName string `validate:"required"`
}
}
func student() {
student := Student{
Name: "ysm",
Passwd: "123456",
Repasswd: "123456",
Pen: struct {
StudentName string `validate:"required"`
}{StudentName: "ysm"},
}
log.Printf("student:%+v
", student)
validate := validator.New()
validatErr := validate.Struct(&student)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
func main(){
student()
}
自定义类型
- 主要使用validator.New().RegisterValidation("tagName",tagFunc)
示例
package main
import (
"log"
"github.com/go-playground/validator"
)
type Users struct {
Phone string `validate:"required,PhoneValidationErrors"` // 必填
Email string `validate:"email"` // 验证字符串是email格式。默认为必填
Url string `validate:"url"` // 验证字符串是URL格式。默认为必填
Passwd string `validate:"required,max=20,min=6"` // max字符串最大长度,min字符串最小长度
Code string `validate:"required,len=6"` // len字符串长度必须为n,或者是数组、切片、map的len的值
Eq int `validate:"eq=4"` // eq数字等于n
Ne int `validate:"ne=4"` // ne数字不等n
Gt int `validate:"gt=4"` // gt数字大于n
Gte int `validate:"gte=4"` // gte数字大于等于n
Lt int `validate:"lt=4"` // lt小于n
Lte int `validate:"lte=4"` // lte小于等于
}
func main() {
users := Users{
Phone: "13345679878",
Email: "1843121593@qq.com",
Url: "https://blog.csdn.net/guyan0319/article/details/105918559",
Passwd: "123456",
Code: "123456",
Eq: 4,
Ne: 3,
Gt: 5,
Gte: 4,
Lt: 3,
Lte: 4,
}
log.Printf("users:%+v
", users)
validate := validator.New()
// 注册自定义函数
_ = validate.RegisterValidation("PhoneValidationErrors", PhoneValidationErrors)
validatErr := validate.Struct(&users)
errs := make([]validator.FieldError, 0)
if validatErr != nil {
for _, err := range validatErr.(validator.ValidationErrors) {
errs = append(errs, err)
}
}
if len(errs) != 0 {
for i := 0; i < len(errs); i++ {
log.Println(errs[i])
}
}
}
// 返回TRUE则不会报错,返回FALSE则会报错
func PhoneValidationErrors(fl validator.FieldLevel) bool {
return fl.Field().String() == "13345679878"
}