golang中使用validator进行数据校验及自定义翻译器

目录

  • 一、概述
  • 二、使用官方标记符进行数据效验
  • 三、自定义标记符和翻译器进行数据效验

一、概述

在接口开发经常需要进行数据校验,validator包是一个比较强大的校验工具包。下面是一些学习总结,全文使用gin框架进行讲解,详细内容可以查看validator

二、使用官方标记符进行数据效验

下面我以“required”进行代码演示,要查看更多标记符可以查看官方文档

导包

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"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"
	"net/http"
	"reflect"
	"regexp"
	"strings"
)

定义全局键值对,可以方便取到验证器和翻译器,以及要翻译的语言

const (
	ValidatorKey  = "ValidatorKey"
	TranslatorKey = "TranslatorKey"
	locale = "zh"
)

初始化验证器和翻译器

func TransInit(c *gin.Context)  {
	//设置支持语言
	chinese := zh.New()
	english := en.New()
	//设置国际化翻译器
	uni := ut.New(chinese, chinese, english)
	//设置验证器
	val := validator.New()
	//根据参数取翻译器实例
	trans, _ := uni.GetTranslator(locale)
	//翻译器注册到validator
	switch locale {
		case "chinese":
			zhTranslations.RegisterDefaultTranslations(val, trans)
			//使用fld.Tag.Get("comment")注册一个获取tag的自定义方法
			val.RegisterTagNameFunc(func(fld reflect.StructField) string {
				return fld.Tag.Get("comment")
			})
		case "english":
			enTranslations.RegisterDefaultTranslations(val, trans)
			val.RegisterTagNameFunc(func(fld reflect.StructField) string {
				return fld.Tag.Get("en_comment")
			})
	}
	c.Set(TranslatorKey, trans)
	c.Set(ValidatorKey, val)
}

将路由变量params和gin框架绑定


func DefaultGetValidParams(c *gin.Context, params interface{}) error {
	c.ShouldBind(params)
	//获取验证器
	val, _ := c.Get(ValidatorKey)
	valid, _ := val.(*validator.Validate)
	//获取翻译器
	tran, _ := c.Get(TranslatorKey)
	trans, _ := tran.(ut.Translator)
	err := valid.Struct(params)
	//如果数据效验不通过,则将所有err以切片形式输出
	if err != nil {
		errs := err.(validator.ValidationErrors)
		sliceErrs := []string{}
		for _, e := range errs {
			//使用validator.ValidationErrors类型里的Translate方法进行翻译
			sliceErrs = append(sliceErrs, e.Translate(trans))
		}
		return errors.New(strings.Join(sliceErrs, ","))
	}
	return nil
}

接下来我们定义一个结构体,对其传参检验输出结果
form是前端传入的参数名;comment是自定义tag,本文表示的是参数报错时显示的名称;validate里传入标记符,这里传入’required’(字段必填)

type login struct {
	Username string ` form:"username" comment:"用户名" validate:"required"`
}

编写路由函数

func loginTest(c *gin.Context) {
	TransInit(c)
	req:=&login{}
	err:=DefaultGetValidParams(c,req)
	//失败时输出
	if err != nil {
		c.JSON(404, gin.H{
			"code": 2000,
			"err":  err.Error(),
		})
		return
	}
	//成功时输出
	c.JSON(http.StatusOK, gin.H{
		"code": 0,
		"msg":  "success",
		"name":req.Username,
	})
}

最后运行

func main()  {
	route := gin.Default()
	route.POST("/login",loginTest)
	route.Run(":8099")
}

使用Postman进行测试:
golang中使用validator进行数据校验及自定义翻译器_第1张图片
如果没填参数则提示“必填”:
golang中使用validator进行数据校验及自定义翻译器_第2张图片
如果把翻译的语言改为英语,效验失败时如下输出:

const (
	ValidatorKey  = "ValidatorKey"
	TranslatorKey = "TranslatorKey"
	//locale = "chinese"
	locale = "english"
)

golang中使用validator进行数据校验及自定义翻译器_第3张图片

三、自定义标记符和翻译器进行数据效验

相比于官方定义好可以直接拿来用的标记符,自定义标记符具有更广泛的应用,我在项目中经常用的也是自定义标记符。同时自定义翻译器也可以更清楚的告诉用户格式输入错误。
首先自定义一个标识符"valid_username"

type login struct {
	Username string ` form:"username" comment:"用户名" validate:"required,valid_username"`
}

这里我使用了正则进行效验。更多的正则匹配规则可自行百度,这里不作更多介绍
在初始化翻译器中加入如下函数:

//自定义验证方法
val.RegisterValidation("valid_username", func(fl validator.FieldLevel) bool {
	matched, _ := regexp.Match("^[a-z]{6,30}$", []byte(fl.Field().String()))
	return matched
})
//自定义翻译器
val.RegisterTranslation("valid_username", trans, func(ut ut.Translator) error {
	return ut.Add("valid_username", "{0}输入格式不正确或长度不符", true)
},
func(ut ut.Translator, fe validator.FieldError) string {
	t, _ := ut.T("valid_username", fe.Field())
	return t
})

即:

func TransInit(c *gin.Context)  {
	//设置支持语言
	chinese := zh.New()
	english := en.New()
	//设置国际化翻译器
	uni := ut.New(chinese, chinese, english)
	//设置验证器
	val := validator.New()
	//根据参数取翻译器实例
	trans, _ := uni.GetTranslator(locale)
	//翻译器注册到validator
	switch locale {
		case "chinese":
			zhTranslations.RegisterDefaultTranslations(val, trans)
			val.RegisterTagNameFunc(func(fld reflect.StructField) string {
				return fld.Tag.Get("comment")
			})
	
			//自定义验证方法
			val.RegisterValidation("valid_username", func(fl validator.FieldLevel) bool {
				matched, _ := regexp.Match("^[a-z]{6,30}$", []byte(fl.Field().String()))
				return matched
			})
			//自定义翻译器
			val.RegisterTranslation("valid_username", trans, func(ut ut.Translator) error {
				return ut.Add("valid_username", "{0}输入格式不正确或长度不符", true)
			},
			func(ut ut.Translator, fe validator.FieldError) string {
				t, _ := ut.T("valid_username", fe.Field())
				return t
			})
	
		case "english":
			enTranslations.RegisterDefaultTranslations(val, trans)
			//使用fld.Tag.Get("en_comment")注册一个获取tag的自定义方法
			val.RegisterTagNameFunc(func(fld reflect.StructField) string {
				return fld.Tag.Get("en_comment")
			})

	}
	c.Set(TranslatorKey, trans)
	c.Set(ValidatorKey, val)
}

重新运行查看结果
golang中使用validator进行数据校验及自定义翻译器_第4张图片

你可能感兴趣的:(go,golang,后端)