Loading

Gin 模型绑定和验证

Gin 模型绑定和验证

定义绑定的结构体:

type PhoneExistRequest struct {
	Phone   string `json:"phone" binding:"required,len=11" label:"手机号"`
	SmsCode string `json:"sms_code" binding:"required" label:验证码`
}

错误信息翻译及绑定验证:

package requests

import (
    "net/http"
	"reflect"
	"strings"

    "github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	zh_translations "github.com/go-playground/validator/v10/translations/zh"
)

var (
	uni      *ut.UniversalTranslator
	validate *validator.Validate
	trans    ut.Translator
)

func init() {
	// 注册翻译器
	zh := zh.New()
	uni = ut.New(zh, zh)

	trans, _ = uni.GetTranslator("zh")

	// 获取 gin 的校验器
	validate := binding.Validator.Engine().(*validator.Validate)
	// 字段的替换名称,默认是属性名称,这里改为结构体中的 json 值
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
		if name == "-" {
			return "j"
		}
		return name
	})
	// 注册翻译器
	zh_translations.RegisterDefaultTranslations(validate, trans)
}

// 翻译错误信息
func Translate(err error) map[string][]string {
	var result = make(map[string][]string)

	errors := err.(validator.ValidationErrors)

	for _, err := range errors {
		result[err.Field()] = append(result[err.Field()], err.Translate(trans))
	}
	return result
}

// 绑定验证
func Validate(ctx *gin.Context, request interface{}) bool {
	if err := ctx.ShouldBindJSON(request); err != nil {
		var errors interface{}
		if err.Error() == "EOF" {
			errors = "没有提交参数" // 调用接口没有传入任何参数,这里会返回 EOF
		} else {
			errors = Translate(err)
		}

		ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
			"message": "请求验证未通过",
			"errors":  errors,
		})
		return false
	}

	return true
}

controller 中调用:

func IsPhoneExist(ctx *gin.Context) {

	request := requests.PhoneExistRequest{}
	if ok := requests.Validate(ctx, &request); !ok {
		return
	}

	// todo::验证逻辑

	ctx.JSON(http.StatusOK, gin.H{
		"message": "OK",
	})
}

请求接口:

E:\zhpj\Desktop>curl -H "Content-Type: application/json" -X POST http://localhost:8080/login/by/phone
{
    "errors":"没有提交参数",
    "message":"请求验证未通过"
}
E:\zhpj\Desktop>

E:\zhpj\Desktop>curl -H "Content-Type: application/json" -X POST -d "{\"tel\":\"1234567890\"}" http://localhost:8080/login/by/phone
{
    "errors":{
        "phone":[
            "phone为必填字段"
        ],
        "sms_code":[
            "sms_code为必填字段"
        ]
    },
    "message":"请求验证未通过"
}
E:\zhpj\Desktop>


E:\zhpj\Desktop>curl -H "Content-Type: application/json" -X POST -d "{\"phone\":\"1234567890\"}" http://localhost:8080/login/by/phone
{
    "errors":{
        "phone":[
            "phone长度必须是11个字符"
        ],
        "sms_code":[
            "sms_code为必填字段"
        ]
    },
    "message":"请求验证未通过"
}
E:\zhpj\Desktop>

调整错误信息的结构:

func Translate(err error) []string {
	errors := err.(validator.ValidationErrors)
	var result = make([]string, len(errors))

	for idx, err := range errors {
		result[idx] = err.Translate(trans)
	}
	return result
}

请求接口:

E:\zhpj\Desktop>curl -H "Content-Type: application/json" -X POST -d "{\"tel\":\"1234567890\"}" http://localhost:8080/login/by/phone
{
    "errors":[
        "phone为必填字段",
        "sms_code为必填字段"
    ],
    "message":"请求验证未通过"
}
E:\zhpj\Desktop>
posted @ 2024-03-11 08:45  zhpj  阅读(52)  评论(0)    收藏  举报