11-验证器(validator)

Github: https://github.com/go-playground/validator

1、介绍

validatorh 是一个开源的验证器包,可以快速校验输入信息是否符合自定规则。

1.1、安装

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

1.2、引用

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

1.3、示例

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package main

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

// 用户参数结构体
type AddUserPost struct {
Name string `json:"name" validate:"required"` //必填
Email string `json:"email" validate:"required,email"` // 必填,并且格式是 email
Age uint8 `json:"age" validate:"gte=18,lte=30"` // 年龄范围
}

func main() {
engine := gin.Default()
engine.POST("/valid", func(context *gin.Context) {
var adduserPost AddUserPost
// 接收参数
err := context.ShouldBindJSON(&adduserPost)
if err != nil {
context.JSON(500,gin.H{"msg":err})
return
}
fmt.Printf("adduserPost: %+v\n",adduserPost)

// 使用Validate验证
validate := validator.New() // 使用 validator.New() 创建一个验证器,这个验证器可以指定选项、添加自定义约束,
err = validate.Struct(adduserPost) // 调用 Struct() 方法来验证各种结构对象的字段是否符合定义的约束
if err != nil {
fmt.Println(err)
context.JSON(500,gin.H{"msg":err.Error()})
return
}

context.JSON(200,gin.H{"msg":"success"})
})
_ = engine.Run()
}

请求:

1
2
3
4
5
6
7
8
9
# email不合法时
[lepeng@centos ~]# curl -X POST http://127.0.0.1:8080/valid -d '{"name":"张三","email":"123","age":21}'
{"msg":"Key: 'AddUserPost.Email' Error:Field validation for 'Email' failed on the 'email' tag"}
# age 不在指定范围时
[lepeng@centos ~]# curl -X POST http://127.0.0.1:8080/valid -d '{"name":"张三","email":"123@163.com","age":17}'
{"msg":"Key: 'AddUserPost.Age' Error:Field validation for 'Age' failed on the 'gte' tag"}
# 姓名不填时
[lepeng@centos ~]# curl -X POST http://127.0.0.1:8080/valid -d '{"name":"","email":"123@163.com","age":20}'
{"msg":"Key: 'AddUserPost.Name' Error:Field validation for 'Name' failed on the 'required' tag"}

2、返回结果改成中文

2.1、代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zhs "github.com/go-playground/validator/v10/translations/zh"
)
var (
validate = validator.New() // 实例化验证器
chinese = zh.New() // 获取中文翻译器
uni = ut.New(chinese, chinese) // 设置成中文翻译器
trans, _ = uni.GetTranslator("zh") // 获取翻译字典
)
type User struct {
Name string `form:"name" validate:"required,min=3,max=5"`
Email string `form:"email" validate:"email"`
Age int8 `form:"age" validate:"gte=18,lte=20"`
}

func main() {
engine := gin.Default()
engine.GET("/language", func(context *gin.Context) {
var user User
err := context.ShouldBindQuery(&user)
if err != nil {
context.JSON(500, gin.H{"msg": err})
return
}
// 注册翻译器
_ = zhs.RegisterDefaultTranslations(validate, trans)
// 使用验证器验证
err = validate.Struct(user)
if err != nil {
if errors, ok := err.(validator.ValidationErrors); ok {
// 翻译,并返回
context.JSON(500, gin.H{
"翻译前": errors.Error(),
"翻译后": errors.Translate(trans),
})
return
}
}
context.JSON(200,gin.H{"msg":"success"})
})
_ = engine.Run()
}

2.2、请求

1
2
3
4
5
6
7
8
9
10
11
12
# 不传参数
[lepeng@centos ~]# curl -X GET http://127.0.0.1:8080/language
{
"翻译前":"Key: 'User.Name' Error:Field validation for 'Name' failed on the 'required' tag
Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'gte' tag",
"翻译后":{
"User.Age":"Age必须大于或等于18",
"User.Email":"Email必须是一个有效的邮箱",
"User.Name":"Name为必填字段"
}
}

3、常用校验规则

3.1、常用tag

  • ne:不等于参数值,例如ne=5
  • gt:大于参数值,例如gt=5
  • gte:大于等于参数值,例如gte=50
  • lt:小于参数值,例如lt=50
  • lte:小于等于参数值,例如lte=50
  • oneof:只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,例如oneof=male female
  • eq:等于参数值,注意与len不同。对于字符串,eq约束字符串本身的值,而len约束字符串长度。例如eq=10
  • len:等于参数值,例如len=10
  • max:小于等于参数值,例如max=10
  • min:大于等于参数值,例如min=10

3.2、Fields约束

  • eqfield:定义字段间的相等约束,用于约束同一结构体中的字段。例如:eqfield=Password
  • eqcsfield:约束统一结构体中字段等于另一个字段(相对),确认密码时可以使用,例如:eqfiel=ConfirmPassword
  • nefield:用来约束两个字段是否相同,确认两种颜色是否一致时可以使用,例如:nefield=Color1
  • necsfield:约束两个字段是否相同(相对)

3.3、常用约束

  • unique:指定唯一性约束,不同类型处理不同:
    • 对于map,unique约束没有重复的值
    • 对于数组和切片,unique没有重复的值
    • 对于元素类型为结构体的碎片,unique约束结构体对象的某个字段不重复,使用unique=field指定字段名
  • email:使用email来限制字段必须是邮件形式,直接写eamil即可,无需加任何指定。
  • omitempty:字段未设置,则忽略
  • -:跳过该字段,不检验;
  • |:使用多个约束,只需要满足其中一个,例如rgb|rgba
  • required:字段必须设置,不能为默认值;

更多规则,则可查看文档:https://github.com/go-playground/validator

4、自定义规则

4.1、代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// 验证pre
type CustomParam struct {
Pre string `validate:"pre=go_"`
}
func main() {
// 实例化验证器
validate = validator.New()
// 注册自定义标签
_ = validate.RegisterValidation("pre", ValidatePre)
cusParam := CustomParam{
Pre: "php_",
}
err := validate.Struct(cusParam)
fmt.Println(err)
}
// 自定义验证规则
func ValidatePre(fl validator.FieldLevel) bool {
return fl.Field().String() == "go_"
}

4.2、请求返回

1
Key: 'CustomParam.Pre' Error:Field validation for 'Pre' failed on the 'pre' tag

5、在Gin中使用

5.1、代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
"net/http"
"time"
)
// 定义结构体
type User struct {
Name string `form:"name" binding:"required,min=3,max=5" `
BirthDate time.Time `form:"date" binding:"required,birth" time_format:"2006-01-02"`
}

// 运行程序
func main() {
engine := gin.Default()
// 注册自定义验证标签:birth
if validate,ok := binding.Validator.Engine().(*validator.Validate);ok {
validate.RegisterValidation("birth",checkBirthDate)
}

// 接收请求
engine.GET("/valid", func(context *gin.Context) {
var user User
// 集成验证
err := context.ShouldBindQuery(&user)
if err != nil {
context.JSON(http.StatusBadRequest,gin.H{"error":err.Error()})
return
}
context.JSON(http.StatusOK,gin.H{"msg":"success"})
})
_ = engine.Run()
}

// 自定义验证标签:birth
func checkBirthDate(fl validator.FieldLevel) bool {
t,ok := fl.Field().Interface().(time.Time)
if ok {
// 当前时间应该大于生日时间
if time.Now().After(t) {
return true
}
}
return false
}

5.2、请求返回

1
2
3
4
5
6
7
8
9
# name错误时
➜ curl -X GET http://127.0.0.1:8080/valid?name=张三&date=2020-01-01
{"error":"Key: 'User.Name' Error:Field validation for 'Name' failed on the 'min' tag"}
# 自定义birth格式错误时
➜ curl -X GET http://127.0.0.1:8080/valid?name=张是三&date=2020
{"error":"parsing time \"2020\" as \"2006-01-02\": cannot parse \"\" as \"-\""}
# 都正确
➜ curl -X GET http://127.0.0.1:8080/valid?name=张是三&date=2020-10-10
{"msg":"success"}

6、报错显示json tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
....	
// 注册一个获取json tag的自定义方法
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
splitN := strings.SplitN(field.Tag.Get("json"), ",", 2)
fmt.Println(splitN)
n := splitN[0]
if n == "-" {
return ""
}
return n
})
err := validate.Struct(s)
if err != nil {
....
}

7、常用标记说明

标记 标记说明
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"
email 字符串值包含一个有效的电子邮件 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"

11-验证器(validator)
https://flepeng.github.io/021-Go-34-框架-01-Gin-11-验证器-validator/
作者
Lepeng
发布于
2024年11月14日
许可协议