gin框架中,默认集成了数据效验包 validator,首先定义接收请求参数的结构体,在结构体中 定义指定的效验规则。
基本使用
定义结构体
实例一个登录接口
go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
// Login 用户登录
func Login(ctx *gin.Context) {
type TempData struct {
Name string `json:"username" binding:"required,max=2"`
Password string `json:"password"`
}
temp := TempData{}
if err := ctx.ShouldBind(&temp); err != nil {
ctx.JSON(http.StatusBadRequest, ParamsNilError.WithMsg(err.Error()))
}
}
请求结果
通httpClient请求接口
http
### 用户登录
// @no-log
POST http://localhost:8000/api/v1/user/login
Content-Type: application/json
{
"username": "how2j"
}
响应结果
http
POST http://localhost:8000/api/v1/user/login
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Date: Tue, 26 Nov 2024 05:39:20 GMT
Content-Length: 129
{
"code": -1,
"status": false,
"message": "Key: 'TempData.Name' Error:Field validation for 'Name' failed on the 'max' tag",
"data": null
}
响应文件已保存。
> 由于禁用了文件登录,无法显示响应
Response code: 400 (Bad Request); Time: 7ms (7 ms); Content length: 129 bytes (129 B)
错误信息自定义
添加自定义错误信息tag
自定义tag规则: [tag]Msg: message
go
type TempData struct {
Name string `json:"username" binding:"required,max=2" requiredMsg:"用户名不能为空"`
Password string `json:"password"`
}
添加错误消息处理方法
创建/utils/request.go
文件, ctx.ShouldBind(&temp)
方法产生的error中,数据校验失败返回的是validator.ValidationErrors类型,根据这个类型进行错误消息的处理。
一、首先进行错误类型判断
go
// ValidateErrorMsg 消息类型
type ValidateErrorMsg map[string]string
func GetErrorMsg(err error, structure interface{}) string {
// 如果err是validator.ValidationErrors类型,获取第一个错误信息
if errors.As(err, &validationErrors) && len(validationErrors) > 0 {
// ...processing
}
}
二、 使用反射机制来获取结构体中自定义的tag信息
- 使用 reflect.TypeOf() 函数获取结构体的类型信息
- 通过FieldByName找到指定结构体字段信息
- filed.Tag.Get方法获取tag信息
go
// ValidateErrorMsg 消息类型
type ValidateErrorMsg map[string]string
func GetErrorMsg(err error, structure interface{}) string {
// 如果err是validator.ValidationErrors类型,获取第一个错误信息
if errors.As(err, &validationErrors) && len(validationErrors) > 0 {
s := reflect.TypeOf(structure)
errMsg := validationErrors[0]
filed, _ := s.FieldByName(errMsg.Field()) // 获取效验失败字段信息
errText := filed.Tag.Get(errMsg.Tag() + "Msg") // 获取自定义信息
}
}
三、完整代码
go
package utils
import (
"errors"
"github.com/go-playground/validator/v10"
"reflect"
)
// ValidateErrorMsg 消息类型
type ValidateErrorMsg map[string]string
func GetErrorMsg(err error, structure interface{}) string {
var validationErrors validator.ValidationErrors
// 如果err是validator.ValidationErrors类型,获取第一个错误信息
if errors.As(err, &validationErrors) && len(validationErrors) > 0 {
s := reflect.TypeOf(structure)
errMsg := validationErrors[0]
filed, _ := s.FieldByName(errMsg.Field())
errText := filed.Tag.Get(errMsg.Tag() + "Msg")
// 如果没有自定义消息,返回错误成员本身的错误信息
if errText == "" {
return err.Error()
}
return errText
}
// 其他类型的错误直接返回错误信息
return err.Error()
}
自定义效验规则
可以查看Gin-自定义验证器文档
创建validator.go
文件
go
func InitValidator() {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 自定义验证器注册
_ = v.RegisterValidation("mobile", validateMobile)
}
}
// 校验手机号
func validateMobile(fl validator.FieldLevel) bool {
mobile := fl.Field().String()
// 手机号为空则不验证,这里只验证有值的
if mobile == "" {
return true
}
ok, _ := regexp.MatchString(`^1[3-9]\d{9}$`, mobile)
return ok
}
在 main.go
文件中注册
go
func main() {
// 注册验证器
validator.InitValidator()
}