Gin 默认的模型验证为 validator 库,并且提供了多个版本供我们使用,如 v8,v9,我自己在使用的时候我会默认使用 v9 这个版本,因为在写自定义验证函数时更方便简洁。

v8 版本的自定义验证

1
2
3
4
5
6
7
8
9
10
11
12
func ValidateUserNameUniq(
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
// 数据库唯一性验证
var count int
user := model.User{}
_ = model.DB.Self.Where("name = ?", field.String()).Find(&user).Count(&count)

res := count > 0
return !res
}

可以看到,我只想简单的验证下字段值是否唯一,但是这有着一堆的反射参数,看着就头疼

v9 版本的自定义验证

1
2
3
4
5
6
7
8
9
10
11
12
13
func FiledValUnique(fl validator.FieldLevel) bool {
var (
conn = db.NewMysql(config.C)
count = 0
)

value := fl.Field().String()
column := strings.ToLower(fl.FieldName())

conn.Table(tableNameVar).Where(column+"= ? ", value).Count(&count)

return ! (count > 0)
}

我自己封装了一个 v9 版本的自定义验证函数,这就非常的简单了,用到什么就取什么,我这里用到了要判断的值,及要判断的哪一列。

Demo

下面的代码中 config.C.Uni 为 "github.com/go-playground/universal-translator" 中的 ut.New() 实例
config.C 为 配置的实例
Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package model

import (
validatorPkg "learnku-api/pkg/validator"
"time"
)

type CategoryParams struct {
Name string `form:"name" binding:"required" validate:"max=25,min=10,filed_unique"`
Description string `form:"description" binding:"required"`
CreatedAt int64
}

func (params *CategoryParams) CategoryStoreValidator() (valError validatorPkg.CommonError) {
return validatorPkg.CustomValParams(params, validatorPkg.FiledValUnique, "filed_unique", "categories")
}
validator
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
package validator

import (
"gopkg.in/go-playground/validator.v9"
"learnku-api/config"
"learnku-api/pkg/db"
"strings"
)

// 无法获取表名,所以直接传表名即可
var tableNameVar string

func CustomValParams(params interface{}, customFunc validator.Func, tagName, tableName string) (valError CommonError) {
tableNameVar = tableName

// 输出错误结果为中文
trans, _ := config.C.Uni.GetTranslator("zh")
_ = config.C.Validate.RegisterValidation(tagName, customFunc)

err := config.C.Validate.Struct(params)

if err != nil {
return GetValidatorError(err, trans)
}

return
}

func FiledValUnique(fl validator.FieldLevel) bool {
var (
conn = db.NewMysql(config.C)
count = 0
)

value := fl.Field().String()
column := strings.ToLower(fl.FieldName())

conn.Table(tableNameVar).Where(column+"= ? ", value).Count(&count)

return ! (count > 0)
}
validator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package validator

import (
"github.com/go-playground/universal-translator"
"gopkg.in/go-playground/validator.v9"
)

type CommonError struct {
Errors map[string]interface{}
}

// 返回错误信息
func GetValidatorError(err error, trans ut.Translator) (res CommonError) {
res = CommonError{}
res.Errors = make(map[string]interface{})
errs := err.(validator.ValidationErrors)

for _, e := range errs {
res.Errors[e.Field()] = e.Translate(trans)
}

return
}

在运行时,发现 FiledValUnique() 函数运行了两次。。。。