简介
Gin使用go-playground/validator验证参数;
官方文档
表单验证
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type SignUpForm struct {
// 参数age必填;大于等于1小于等于100
Age uint8 `json:"age" binding:"required,gte=1,lte=100"`
// 参数name必填;最小长度3最大长度15
Name string `json:"name" binding:"required,min=3,max=15"`
// 参数email必填;必须符合email规范
Email string `json:"email" binding:"required,email"'`
// 参数password必填
Password string `json:"password" binding:"required"`
// 参数re_password必填;内容必须与password相同
RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func main() {
r := gin.Default()
r.POST("/signup", func(context *gin.Context) {
var signUpFrom SignUpForm
if err := context.ShouldBind(&signUpFrom); err != nil {
// 参数不符合规则返回400
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"mag": "注册成功",
})
})
r.Run(":8081")
}
将错误翻译成中文
package main
import (
"fmt"
"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"
en1 "github.com/go-playground/validator/v10/translations/en"
zh1 "github.com/go-playground/validator/v10/translations/zh"
"log"
"net/http"
)
var trans ut.Translator
type SignUpForm struct {
// 参数age必填;大于等于1小于等于100
Age uint8 `json:"age" binding:"required,gte=1,lte=100"`
// 参数name必填;最小长度3最大长度15
Name string `json:"name" binding:"required,min=3,max=15"`
// 参数email必填;必须符合email规范
Email string `json:"email" binding:"required,email"'`
// 参数password必填
Password string `json:"password" binding:"required"`
// 参数re_password必填;内容必须与password相同
RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func InitTrans(locale string) error {
// 修改gin框架中的validator引擎属性,实现定制
validate := binding.Validator.Engine().(*validator.Validate)
zhT := zh.New() // 中文翻译器
enT := en.New() // 英文翻译器
// 第一个参数是备用的语言环境;后面的参数是应该支持的语言环境
uni := ut.New(zhT, zhT, enT)
var ok bool
trans, ok = uni.GetTranslator(locale)
if !ok {
return fmt.Errorf("uni.GetTranslator(%s)", locale)
}
if locale == "en" {
// 英文
en1.RegisterDefaultTranslations(validate, trans)
} else {
// 非英文的统一使用中文
zh1.RegisterDefaultTranslations(validate, trans)
}
return nil
}
func main() {
// 初始化翻译器
if err := InitTrans("zh"); err != nil {
log.Println("初始化翻译器错误")
return
}
r := gin.Default()
r.POST("/signup", func(context *gin.Context) {
var signUpFrom SignUpForm
if err := context.ShouldBind(&signUpFrom); err != nil {
errors, ok := err.(validator.ValidationErrors)
if !ok {
// 不属于类型校验错误时就直接原样返回
context.JSON(http.StatusBadRequest, gin.H{
"msg": err.Error(),
})
return
}
// 参数不符合规则返回400
context.JSON(http.StatusBadRequest, gin.H{
"error": errors.Translate(trans),
})
return
}
context.JSON(http.StatusOK, gin.H{
"mag": "注册成功",
})
})
r.Run(":8081")
}
返回细节处理
再发生错误时,返回值细节上还有一些问题
{
"error": {
"SignUpForm.Age": "Age为必填字段",
"SignUpForm.Email": "Email为必填字段",
"SignUpForm.Name": "Name为必填字段",
"SignUpForm.Password": "Password为必填字段",
"SignUpForm.RePassword": "RePassword为必填字段"
}
}
- 提示语里面的属性名全部都是go语言中的属性名
- 还携带了go语言中的struct名
package main
import (
"fmt"
"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"
en1 "github.com/go-playground/validator/v10/translations/en"
zh1 "github.com/go-playground/validator/v10/translations/zh"
"log"
"net/http"
"reflect"
"strings"
)
var trans ut.Translator
type SignUpForm struct {
// 参数age必填;大于等于1小于等于100
Age uint8 `json:"age" binding:"required,gte=1,lte=100"`
// 参数name必填;最小长度3最大长度15
Name string `json:"name" binding:"required,min=3,max=15"`
// 参数email必填;必须符合email规范
Email string `json:"email" binding:"required,email"'`
// 参数password必填
Password string `json:"password" binding:"required"`
// 参数re_password必填;内容必须与password相同
RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}
func InitTrans(locale string) error {
// 修改gin框架中的validator引擎属性,实现定制
if validate, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 注册一个获取json的tag的自定义方法
validate.RegisterTagNameFunc(func(field reflect.StructField) string {
name := strings.SplitN(field.Tag.Get("json"), ",", 2)[0]
if name == "-" {
// json的tag标签没有填默认"-"
return ""
}
return name
})
zhT := zh.New() // 中文翻译器
enT := en.New() // 英文翻译器
// 第一个参数是备用的语言环境;后面的参数是应该支持的语言环境
uni := ut.New(zhT, zhT, enT)
var ok bool
trans, ok = uni.GetTranslator(locale)
if !ok {
return fmt.Errorf("uni.GetTranslator(%s)", locale)
}
if locale == "en" {
// 英文
en1.RegisterDefaultTranslations(validate, trans)
} else {
// 非英文的统一使用中文
zh1.RegisterDefaultTranslations(validate, trans)
}
}
return nil
}
// 去除error信息中的go语言的struct名
func removeTopStruct(fileds map[string]string) map[string]string {
res := map[string]string{}
for k, v := range fileds {
res[k[strings.Index(k, ".")+1:]] = v
}
return res
}
func main() {
// 初始化翻译器
if err := InitTrans("zh"); err != nil {
log.Println("初始化翻译器错误")
return
}
r := gin.Default()
r.POST("/signup", func(context *gin.Context) {
var signUpFrom SignUpForm
if err := context.ShouldBind(&signUpFrom); err != nil {
errors, ok := err.(validator.ValidationErrors)
if !ok {
// 不属于类型校验错误时就直接原样返回
context.JSON(http.StatusBadRequest, gin.H{
"msg": err.Error(),
})
return
}
// 参数不符合规则返回400
context.JSON(http.StatusBadRequest, gin.H{
"error": removeTopStruct(errors.Translate(trans)),
})
return
}
context.JSON(http.StatusOK, gin.H{
"mag": "注册成功",
})
})
r.Run(":8081")
}