• gin自定义验证器+中文翻译


    1、说明

    gin官网自定义验证器给的例子相对比较简单,主要是语法级别,便于入门学习,并且没有给出翻译相关的处理,因此在这里记录一下通用一点的自定义验证器+中文翻译的代码,可以直接在往后的go-web项目直接使用

    2、global.go

    // Package global 当前包存放全局的变量,便于项目所有包使用
    package global
    
    import (
    	"net/http"
    	"strings"
    
    	"github.com/gin-gonic/gin"
    	ut "github.com/go-playground/universal-translator"
    	"github.com/go-playground/validator/v10"
    )
    
    /****************************** 全局变量 ****************************/
    var (
    	// Trans 全局的翻译器
    	Trans ut.Translator
    )
    
    /****************************** 辅助函数 ****************************/
    
    // removeTopStruct 移除打印的错误信息中的结构体包前缀
    func removeTopStruct(fields map[string]string) map[string]string {
    	rsp := map[string]string{}
    	for field, err := range fields {
    		rsp[field[strings.Index(field, ".")+1:]] = err
    	}
    	return rsp
    }
    
    // HandlerValidatorError 处理校验错误响应
    func HandlerValidatorError(c *gin.Context, err error) {
    	errs, ok := err.(validator.ValidationErrors)
    	if !ok {
    		c.JSON(http.StatusOK, gin.H{
    			"msg": err.Error(),
    		})
    		return
    	}
    	c.JSON(http.StatusBadRequest, gin.H{
    		"error": removeTopStruct(errs.Translate(Trans)),
    	})
    	return
    }
    

    3、validator.go

    package validator
    
    import (
    	"fmt"
    	"reflect"
    	"regexp"
    	"strings"
    
    	"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"
    	entranslations "github.com/go-playground/validator/v10/translations/en"
    	zhtranslations "github.com/go-playground/validator/v10/translations/zh"
    )
    
    // 验证器
    var (
    	trans ut.Translator
    )
    
    
    /****************************** 翻译器、自定义的验证器的初始化 ****************************/
    
    // InitChineseTranslator 初始化中文翻译器
    func InitChineseTranslator(){
    	if err := initTrans("zh"); err != nil {
    		panic("初始化翻译器错误" + err.Error())
    	} else {
    		fmt.Println("初始化中文翻译器成功")
    	}
    }
    
    // InitEnglishTranslator 初始化英文翻译器
    func InitEnglishTranslator(){
    	if err := initTrans("en"); err != nil {
    		panic("初始化翻译器错误" + err.Error())
    	} else {
    		fmt.Println("初始化英文翻译器成功")
    	}
    }
    
    // initTrans 初始化翻译器
    func initTrans(locale string) (err error) {
    	//修改gin框架中的validator引擎属性, 实现定制
    	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    		//注册一个获取json的tag的自定义方法
    		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
    			name := strings.SplitN(fld.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)
    		if !ok {
    			return fmt.Errorf("uni.GetTranslator(%s)", locale)
    		}
    		switch locale {
    		case "en":
    			err = entranslations.RegisterDefaultTranslations(v, trans)
    		case "zh":
    			err = zhtranslations.RegisterDefaultTranslations(v, trans)
    		default:
    			err = entranslations.RegisterDefaultTranslations(v, trans)
    		}
    	}
    	return
    }
    
    // InitValidationRules 注册自定义的验证器
    func InitValidationRules() {
    	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    		// 1、mobile验证器相关
    		{
    			// 设置自定义验证器的翻译配置,每个验证器搭配一个翻译规则
    			err := v.RegisterTranslation("mobile", trans, func(ut ut.Translator) error {
    				return ut.Add("mobile", "{0} 非法的手机号!", true) // see universal-translator for details
    			}, func(ut ut.Translator, fe validator.FieldError) string {
    				t, _ := ut.T("mobile", fe.Field())
    				return t
    			})
    			// mobile验证器
    			err = v.RegisterValidation("mobile", validateMobile)
    			if err != nil {
    				panic("mobile验证器注册失败:" + err.Error())
    			}
    		}
    		//	2、XXX验证器相关
    		{
    
    		}
    		fmt.Println("初始化验证器成功")
    	}
    }
    
    /****************************** 自定义验证器 ****************************/
    
    // validateMobile 手机号码的校验规则,用于gin的请求参数自动校验
    func validateMobile(fl validator.FieldLevel) bool {
    	// 内部通过反射获取mobile的值
    	mobile := fl.Field().String()
    	//使用正则表达式判断是否合法
    	isValid, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$`, mobile)
    	return isValid
    }
    
    
    
    /****************************** 自定义验证器 ****************************/
    
    // validateMobile 手机号码的校验规则,用于gin的请求参数自动校验
    func validateMobile(fl validator.FieldLevel) bool {
    	// 内部通过反射获取mobile的值
    	mobile := fl.Field().String()
    	//使用正则表达式判断是否合法
    	isValid, _ := regexp.MatchString(`^1([38][0-9]|14[579]|5[^4]|16[6]|7[1-35-8]|9[189])\d{8}$`, mobile)
    	return isValid
    }
    

    4、eg:main.go

    使用样例,需要在main函数中先调用validator包中的函数,初始化翻译器跟验证器
    在接口解析参数的地方,判断处理验证异常

    package main
    
    import (
    	"fmt"
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    
    	// 引入全局的校验异常处理函数
    	"Go_Bible/valiator_test/global"
    	// 引入通用的验证器相关代码
    	"Go_Bible/valiator_test/validator"
    )
    
    /****************************** 表单结构体、配置校验约束 ****************************/
    
    // PasswordLoginForm 用户名、密码登录表单结构体
    type PasswordLoginForm struct {
    	Mobile   string `form:"mobile" json:"mobile" binding:"required,mobile"` // 自定义了mobile验证器,使用自定义的校验规则
    	Password string `form:"password" json:"password" binding:"required,min=3,max=10"`
    }
    
    /****************************** 接口实现 ****************************/
    
    // Login 登录接口
    func Login(c *gin.Context) {
    	passwordLoginForm := PasswordLoginForm{}
    	// 解析form参数或者json参数
    	if err := c.ShouldBindJSON(&passwordLoginForm); err != nil {
    		// 处理验证异常
    		global.HandlerValidatorError(c, err)
    		return
    	}
    	fmt.Println("参数通过验证,登录接口请求参数:", passwordLoginForm)
    	c.JSON(http.StatusOK, gin.H{
    		"msg": passwordLoginForm,
    	})
    }
    
    /****************************** 主函数 ****************************/
    func main() {
    	// 1、初始化中文翻译器
    	validator.InitChineseTranslator()
    	// 2、初始化自定义的验证器+验证信息翻译
    	validator.InitValidationRules()
    
    	// 3、初始化gin路由配置
    	router := gin.Default()
    	router.POST("/login", Login)
    	fmt.Println("Gin启动")
    	if err := router.Run(":8081"); err != nil {
    		panic("Gin启动错误:" + err.Error())
    	}
    }
    

    5、调用接口测试

    启动main.go,发送请求测试接口:http://127.0.0.1:8081/login

    在这里插入图片描述

  • 相关阅读:
    【ERROR】ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND No package.json
    单片机C语言实例:14、音频输出
    【操作系统笔记】任务调度&信号处理&CPU上下文
    【VM】保姆级VM算法平台二次开发之-环境配置
    Python堆栈详细介绍
    文心一言 VS 讯飞星火 VS chatgpt (99)-- 算法导论9.3 5题
    3D点云测量:计算三个平面的交点
    Chrome调试工具和Emmet语法
    11.21序列检测,状态机比较与代码,按键消抖原理
    ESP8266-Arduino编程实例-MQ-6异丁烷丙烷传感器驱动
  • 原文地址:https://blog.csdn.net/Hunter_Kevin/article/details/138767889