validator
validator 是一个数据验证的包
通常我们使用它处理前端发来的字段验证
一个简单的验证
加上validate:"required"
这个字段变成必填字段
go
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// 申明一个validator对象
var validate *validator.Validate
type User struct {
// 必选
Name string `validate:"required,min=2,max=10"`
Age uint `validate:"required,min=2,max=10"`
}
func main() {
var user = User{}
validate = validator.New()
// 验证结构是否符合规则
err := validate.Struct(user)
fmt.Printf("err: %v\n", err)
// 当结构体出错时 err 对象就会存在值
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
// 输出错误信息
// fmt.Println("Namespace >>>", err.Namespace())
// fmt.Println("StructNamespace >>>", err.StructNamespace())
// fmt.Println("StructField >>>", err.StructField())
// fmt.Println("Tag >>>", err.Tag())
// fmt.Println("ActualTag >>>", err.ActualTag())
// fmt.Println("Kind >>>", err.Kind())、
fmt.Println("Field >>>", err.Field())
fmt.Println("Type >>>", err.Type())
fmt.Println("Value >>>", err.Value())
// fmt.Println("Param >>>", err.Param())
}
}
}
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
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
当验证失败的时候就会输出错误内容
约束数值长度
go
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// 申明一个validator对象
var validate *validator.Validate
type User struct {
// 必选 长度必须 >=2 <= 10
Name string `validate:"required,min=2,max=10"`
// 必选 必须>0 < 130
Age uint `validate:"gte=0,lte=130"`
}
func main() {
var user = User{
Name: "t",
Age: 150,
}
validate = validator.New()
// 验证结构是否符合规则
err := validate.Struct(user)
fmt.Printf("err: %v\n", err)
// 当结构体出错时 err 对象就会存在值
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
fmt.Println("Field >>>", err.Field())
fmt.Println("Type >>>", err.Type())
fmt.Println("Value >>>", err.Value())
}
}
}
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
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
抛出错误
我们上面已经看到了使用min
和max
来约束字符串的长度或数值的范围,范围约束的字段类型有以下几种:
- 对于数值,则约束其值;
- 对于字符串,则约束其长度;
- 对于切片、数组和map,则约束其长度。
其他的内置约束范围字段
tag | 作用 |
---|---|
len | 限制长度len=10 , 对于不同类型参考max``min |
eq | 限制内容相等eq=666 |
ne | 不等于参考值ne=666 |
gt | 大于参数值,例如gt=10 |
gte | 大于等于参数值,例如gte=10 |
lt | 小于参数值,例如lt=10 |
lte | 小于等于参数值,例如lte=10 |
oneof | 只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,例如oneof=red green |
跨字段约束
validator
允许定义跨字段的约束,即该字段与其他字段之间的关系。
增加"eqfield=Password"
的验证,限制第二个密码必须要等于第一个密码
go
type User struct {
// 必选 长度必须 >=2 <= 10
Name string `validate:"len=5"`
// 必选 必须>0 < 130
Age uint `validate:"len=10"`
// 密码必须至少是10位
Password string `validate:"min=10"`
// 第二个密码必须要等于第一个密码
Password2 string `validate:"eqfield=Password"`
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
对于字符串的限制
contains=xxx
必须包含某个字符串
go
type User struct {
Name string `validate:"contains=我是"`
}
1
2
3
2
3
excludes=😀
不包含参数字符串
go
type User struct {
Name string `validate:"excludes=😀"`
}
1
2
3
2
3
startswith=xxx
以参数字符串开头endswith=xxx
以参数字符串结尾
唯一性
使用unqiue来规定唯一性
- 对于数组和切片,unique约束没有重复的元素;
- 对于map,unique约束没有重复的值;
- 对于元素类型为结构体的切片,unique约束结构体对象的某个字段不重复,通过
unqiue=field
指定这个字段名。
go
type User struct {
Name string `validate:"min=2"`
// 限制不允许有相同名字的朋友
Friends []User `validate:"unique=Name"`
// 限制不能有相同字符串的爱好
Likes []string `validate:"unique"`
}
func main() {
var user1 = User{
Name: "张三",
}
var user2 = User{
Name: "张三",
}
var user3 = User{
Name: "王五",
Friends: []User{user1, user2},
Likes: []string{"打篮球", "rap", "rap","唱"},
}
validate = validator.New()
err = validate.Struct(user3)
if err != nil {
fmt.Printf("err3: %v\n", err)
}
}
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
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
其他
validator 提供了大量内置数据格式验证,如邮箱
\ 颜色
等等,具体可以查看文档
自定义验证规则
go
var validate *validator.Validate
type User struct {
Name string `validate:"min=2"`
Phone int `validate:"checkPhone"`
}
func main() {
var user1 = User{
Name: "张三",
Phone: 185222200,
}
validate = validator.New()
// 注册一个自己的验证方式
_ = validate.RegisterValidation("checkPhone", func(fl validator.FieldLevel) bool {
val := fl.Field().Int()
s := strconv.FormatInt(val, 10)
reg := regexp.MustCompile("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$")
b := reg.MatchString(s)
return b
})
err := validate.Struct(user1)
if err != nil {
fmt.Printf("err1: %v\n", err)
}
}
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
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
错误处理
validate会返回一个错误对象
go
err := validate.Struct(user1)
1
err 存在三种情况
nil
= 没有错误InvalidValidationError
= 输入参数有无ValidationErrors
= 字段违反了约束 我们可以在程序中判断err != nil
时,依次将err转换为InvalidValidationError
和ValidationErrors
以获取更详细的信息:
go
func processErr(err error) {
if err == nil {
return
}
validationError, ok := err.(*validator.InvalidValidationError)
if ok {
fmt.Printf("param error:%v", validationError)
return
}
validationErrs := err.(validator.ValidationErrors)
for _, validationErr := range validationErrs {
fmt.Printf("validationErr:%v \n", validationErr)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
错误信息基本上是这样的
Key: 'User.Phone' Error:Field validation for 'Phone' failed on the 'checkPhone' tag
1
假如我们希望给得到更加友好的提示,就需要设置一个映射来处理错误了
我们可以将这个validator
封装成一个模块
go
package validate
import (
"github.com/go-playground/validator/v10"
"regexp"
"strconv"
)
var Validate *validator.Validate
// MessageMap 使用tag作为key来映射一些中文提示
var MessageMap map[string]string = map[string]string{
"checkPhone": "手机格式不正确",
"min": "长度不够",
}
// InitValidate 初始化Validate
func InitValidate() {
Validate = validator.New()
_ = Validate.RegisterValidation("checkPhone", checkPhone)
}
// ProcessErr 处理错误信息
func ProcessErr(err error) (errMessage string) {
if err == nil {
return ""
}
validationErrs := err.(validator.ValidationErrors)
var message = ""
for _, validationErr := range validationErrs {
tag := validationErr.Tag()
namespace := validationErr.Namespace()
// 假如存在映射时,将其替换成映射的值
if MessageMap[tag] != "" {
tag = MessageMap[tag]
}
message += namespace + tag + "\n"
}
return message
}
// 确认手机号
func checkPhone(fl validator.FieldLevel) bool {
val := fl.Field().Int()
s := strconv.FormatInt(val, 10)
reg := regexp.MustCompile("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$")
b := reg.MatchString(s)
return b
}
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
48
49
50
51
52
53
54
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
48
49
50
51
52
53
54
在main.go
中使用
go
package main
import "code1/validate"
func init() {
// 初始化验证实例
validate.InitValidate()
}
type User struct {
Name string `validate:"min=2"`
Phone int `validate:"checkPhone"`
}
func main() {
user := User{
Name: "张",
Phone: 1775059664701,
}
err := validate.Instance.Struct(user)
errMessage := validate.ProcessErr(err)
println(errMessage)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
运行后我们就得到了一些相对友好的提示
User.Name长度不够
User.Phone手机格式不正确
1
2
2
参考文章