问题描述
在参数校验的时候我们一般会基于"github.com/go-playground/validator/v10"
这个库给结构体加标签实现校验参数,当参数校验错误的时候,他的提示一般是英文的,怎么自定义参数错误提示呢?跟着我一步步来
注册校验器
package initializeimport ("ToDoList/global""ToDoList/model/request""ToDoList/util/validate""github.com/gin-gonic/gin/binding""github.com/go-playground/locales/zh"ut "github.com/go-playground/universal-translator"v10 "github.com/go-playground/validator/v10"zhTranslations "github.com/go-playground/validator/v10/translations/zh"
)func RegisterValidator[T interface{}](fn v10.StructLevelFunc, model T) {translator := zh.New()universalTransator := ut.New(translator, translator)global.GVA_TRANS, _ = universalTransator.GetTranslator("zh")if v, ok := binding.Validator.Engine().(*v10.Validate); ok {v.RegisterStructValidation(fn, model)_ = zhTranslations.RegisterDefaultTranslations(v, global.GVA_TRANS)}}type _Validator struct{}func (receiver _Validator) InitValidator() {RegisterValidator[request.Login](validate.UserLoginValidate.Validation, request.Login{})
}var Validator = new(_Validator)func (receiver *ginEngine) InitEngine() *gin.Engine {r := gin.Default()// 这里进行注册校验器!!Validator.InitValidator()return r
}
定义接口
我们定义一个接口规范,利于代码维护
package validateimport "github.com/go-playground/validator/v10"type Validation interface {CreateValidate() validator.StructLevelFunc
}
定义具体参数校验的方法
ReportError
函数第四个参数Param
将作为错误时消息提示。
package validateimport ("ToDoList/model/request""github.com/go-playground/validator/v10""reflect"
)type userLoginValidate struct{}func (receiver userLoginValidate) CreateValidate() validator.StructLevelFunc {return func(sl validator.StructLevel) {user := sl.Current().Interface().(request.Login)StructNotEmpty(sl, user, []string{})if !VerifyPassword(8, 16, user.Password) {sl.ReportError(reflect.ValueOf(user.Password), "", "", "", "密码要出现数字、大写字母、小写字母、特殊字符(.@$!%*#_~?&^),至少包含其中2种且长度在8-16之间")}}
}var UserLoginValidate = new(userLoginValidate)
定义公共函数
1.定义一个翻译的函数
func CustomErrMessage(err error) string {var result stringerrors := err.(validator.ValidationErrors)for _, err := range errors {if err.Param() != "" {result += err.Param() + ","}}return result
}
2.判断结构体字段是否为空
// 结构体字段判断是否为空
func StructNotEmpty(sl validator.StructLevel, st interface{}, omitKeys []string) {t := reflect.TypeOf(st)if t.Kind() == reflect.Ptr {t = t.Elem()}if t.Kind() != reflect.Struct {fmt.Println("必须传入结构体才能判断是否字段为空")return}v := reflect.ValueOf(st) //获取reflect.Type类for i := 0; i < v.NumField(); i++ {if !slices.Contains(omitKeys, t.Field(i).Name) {label := t.Field(i).Tag.Get("label")value := v.Field(i).Interface().(string)if len(value) == 0 {sl.ReportError(t.Field(i), "", "", "", fmt.Sprintf("%s不能为空", label))}}}
}
结构体标签
label
标签是结构体字段的中文翻译,以便于当结构体字段为空时StructNotEmpty
函数可以进行翻译。
type Login struct {Username string `json:"username" binding:"required,min=4,max=16" label:"用户名"` // 用户名Password string `json:"password" binding:"required,min=8,max=16" label:"密码"` // 密码Captcha string `json:"captcha" binding:"required" label:"验证码"` // 验证码CaptchaId string `json:"captchaId" binding:"required" label:"验证码ID"` // 验证码ID
}
返回结果
func (receiver *userApi) Login(c *gin.Context) {// 1.绑定用户表单数据var loginForm request.Login// 2.检验用户登录表单if err := c.ShouldBindJSON(&loginForm); err != nil {response.Response.FailWithMessage(validate.CustomErrMessage(err), c)return}
}
结果展示
总结
- 先在Gin中注册验证器
- 定义校验函数并通过
sl validator.StructLevel
调用sl.ReportError
传入param
参数作为自定义错误 - 然后绑定结构体
var loginForm request.Login if err := c.ShouldBindJSON(&loginForm);
- 当绑定失败的时候把err传给
CustomErrMessage
函数CustomErrMessage
函数,将会把param的值作为错误结果 - 然后将
CustomErrMessage
函数返回结果给客户端即可