gin框架配合go-playground/validator完成json的验证以及json验证错误翻译成中文
安装 go-playground/validator
go get github.com/go-playground/validator/v10
代码如下
package main import ( "fmt" "net/http" "reflect" "strings" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/locales/en" "github.com/go-playground/locales/zh" ut "github.com/go-playground/universal-translator" "github.com/go-playground/validator/v10" en_translations "github.com/go-playground/validator/v10/translations/en" zh_translations "github.com/go-playground/validator/v10/translations/zh" ) type LoginForm struct { User string `json:"user" binding:"required,min=3,max=10"` Password string `json:"password" binding:"required"` } type SignupForm struct { Age uint8 `json:"age" binding:"gte=18,lte=130"` Name string `json:"name" binding:"required,min=3"` Email string `json:"email" binding:"required,email"` Password string `json:"password" binding:"required,min=6"` RePassword string `json:"re_password" binding:"required,eqfield=Password"` // 跨字段验证 } var trans ut.Translator func removeTopStruct(fields map[string]string) map[string]string { // "LoginForm.user": "user长度不能超过10个字符" // 提取user,去掉LoginForm -- "user": "user长度不能超过10个字符" rsp := make(map[string]string) for field, err := range fields { rsp[field[strings.Index(field, ".")+1:]] = err } return rsp } func InitTrans(locale string) (err error) { // 修改gin框架中的validator引擎属性,实现定制 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { // 注册一个获取json的tag的自定义方法 // "LoginForm.User": "User长度不能超过10个字符" // 将大写的User替换为json中定义的tag标签 -- "LoginForm.user": "user长度不能超过10个字符" v.RegisterTagNameFunc(func(field reflect.StructField) string { name := strings.SplitN(field.Tag.Get("json"), ",", 2)[0] if name == "-"{ return "" } return name }) zhT := zh.New() // 中文翻译器 enT := en.New() // 英文翻译器 // 第一个参数是备用的语言环境,后面的参数是应该支持的语言环境 uni := ut.New(enT, zhT, enT) trans, ok = uni.GetTranslator(locale) fmt.Println(ok) if !ok { return fmt.Errorf("uni.GetTranslator(%s)", locale) } switch locale { case "en": en_translations.RegisterDefaultTranslations(v, trans) case "zh": zh_translations.RegisterDefaultTranslations(v, trans) default: en_translations.RegisterDefaultTranslations(v, trans) } return } return } func main() { if err := InitTrans("zh"); err != nil { fmt.Println("初始化翻译器错误") return } r := gin.Default() r.POST("/login", loginView) r.POST("/signup", signupView) r.Run() } func signupView(context *gin.Context) { var signupForm SignupForm if err := context.ShouldBind(&signupForm); err != nil { context.String(http.StatusBadRequest, err.Error()) return } context.JSON(http.StatusOK, gin.H{"message": "注册成功"}) } func loginView(context *gin.Context) { var loginForm LoginForm if err := context.ShouldBind(&loginForm); err != nil { errs, ok := err.(validator.ValidationErrors) if !ok{ context.String(400, err.Error()) } context.JSON(400, removeTopStruct(errs.Translate(trans))) return } context.JSON(http.StatusOK, gin.H{"message": "登录成功"}) }
自定义验证器不翻译解决办法
自定义验证器代码
// 自定义验证器 func ValidateMobile(fl validator.FieldLevel) bool { mobile := fl.Field().String() // 使用正则表达式判断mobile是否合法 //pattern := "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$" pattern := `^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$` ok, _ := regexp.MatchString(pattern, mobile) if !ok{ return false } return true } 注册验证器,同时解决自定义验证器不翻译问题 // 5. 注册验证器 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { _ = v.RegisterValidation("mobile", myvalidator.ValidateMobile) // 解决自定义验证器不翻译问题, 注意上面注册的自定义验证器mobile要和下面的保持一致 _ = v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error { return ut.Add("mobile", "{0} 非法的手机号码!", true) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T("mobile", fe.Field()) return t }) }