go语言学习系列(四):Go 验证器 validator

101 阅读5分钟

1.概述

1.1 validator

validator 包根据 tags 对结构体和单个字段的值进行验证。它具备以下优秀的功能:

  1. 提供了一系列验证规则用于验证,并且支持自定义验证规则;
  2. 支持跨字段、跨结构体进行验证;
  3. 支持多维字段如 array、slice、map 等;
  4. 在验证接口类型前会先确定它的底层数据类型;
  5. 支持自定义字段类型比如 sql 驱动程序 Valuer
  6. 可以自定义并支持国际化(i18n)的错误信息;
  7. 是 gin 框架的默认验证器。

参考链接:juejin.cn/post/725004…

1.2 操作符说明

image.png

1.3 常用标记说明

标记标记说明
required必填Field或Struct validate:"required"
omitempty空时忽略Field或Struct validate:"omitempty"
len长度Field validate:"len=0"
eq等于Field validate:"eq=0"
gt大于Field validate:"gt=0"
gte大于等于Field validate:"gte=0"
lt小于Field validate:"lt=0"
lte小于等于Field validate:"lte=0"
eqfield同一结构体字段相等Field validate:"eqfield=Field2"
nefield同一结构体字段不相等Field validate:"nefield=Field2"
gtfield大于同一结构体字段Field validate:"gtfield=Field2"
gtefield大于等于同一结构体字段Field validate:"gtefield=Field2"
ltfield小于同一结构体字段Field validate:"ltfield=Field2"
ltefield小于等于同一结构体字段Field validate:"ltefield=Field2"
eqcsfield跨不同结构体字段相等Struct1.Field validate:"eqcsfield=Struct2.Field2"
necsfield跨不同结构体字段不相等Struct1.Field validate:"necsfield=Struct2.Field2"
gtcsfield大于跨不同结构体字段Struct1.Field validate:"gtcsfield=Struct2.Field2"
gtecsfield大于等于跨不同结构体字段Struct1.Field validate:"gtecsfield=Struct2.Field2"
ltcsfield小于跨不同结构体字段Struct1.Field validate:"ltcsfield=Struct2.Field2"
ltecsfield小于等于跨不同结构体字段Struct1.Field validate:"ltecsfield=Struct2.Field2"
min最小值Field validate:"min=1"
max最大值Field validate:"max=2"
structonly仅验证结构体,不验证任何结构体字段Struct validate:"structonly"
nostructlevel不运行任何结构级别的验证Struct validate:"nostructlevel"
dive向下延伸验证,多层向下需要多个dive标记[][]string validate:"gt=0,dive,len=1,dive,required"
dive Keys & EndKeys与dive同时使用,用于对map对象的键的和值的验证,keys为键,endkeys为值map[string]string `validate:"gt=0,dive,keys,eq=1eq=2,endkeys,required"`
required_with其他字段其中一个不为空且当前字段不为空Field validate:"required_with=Field1 Field2"
required_with_all其他所有字段不为空且当前字段不为空Field validate:"required_with_all=Field1 Field2"
required_without其他字段其中一个为空且当前字段不为空Field `validate:"required_without=Field1 Field2"
required_without_all其他所有字段为空且当前字段不为空Field validate:"required_without_all=Field1 Field2"
isdefault是默认值Field validate:"isdefault=0"
oneof其中之一Field validate:"oneof=5 7 9"
containsfield字段包含另一个字段Field validate:"containsfield=Field2"
excludesfield字段不包含另一个字段Field validate:"excludesfield=Field2"
unique是否唯一,通常用于切片或结构体Field validate:"unique"
alphanum字符串值是否只包含 ASCII 字母数字字符Field validate:"alphanum"
alphaunicode字符串值是否只包含 unicode 字符Field validate:"alphaunicode"
alphanumunicode字符串值是否只包含 unicode 字母数字字符Field validate:"alphanumunicode"
numeric字符串值是否包含基本的数值Field validate:"numeric"
hexadecimal字符串值是否包含有效的十六进制Field validate:"hexadecimal"
hexcolor字符串值是否包含有效的十六进制颜色Field validate:"hexcolor"
lowercase符串值是否只包含小写字符Field validate:"lowercase"
uppercase符串值是否只包含大写字符Field validate:"uppercase"
email字符串值包含一个有效的电子邮件Field validate:"email"
json字符串值是否为有效的 JSONField validate:"json"
file符串值是否包含有效的文件路径,以及该文件是否存在于计算机上Field validate:"file"
url符串值是否包含有效的 urlField validate:"url"
uri符串值是否包含有效的 uriField validate:"uri"
base64字符串值是否包含有效的 base64值Field validate:"base64"
contains字符串值包含子字符串值Field validate:"contains=@"
containsany字符串值包含子字符串值中的任何字符Field validate:"containsany=abc"
containsrune字符串值包含提供的特殊符号值Field validate:"containsrune=☢"
excludes字符串值不包含子字符串值Field validate:"excludes=@"
excludesall字符串值不包含任何子字符串值Field validate:"excludesall=abc"
excludesrune字符串值不包含提供的特殊符号值Field validate:"containsrune=☢"
startswith字符串以提供的字符串值开始Field validate:"startswith=abc"
endswith字符串以提供的字符串值结束Field validate:"endswith=abc"
ip字符串值是否包含有效的 IP 地址Field validate:"ip"
ipv4字符串值是否包含有效的 ipv4地址Field validate:"ipv4"
datetime字符串值是否包含有效的 日期Field validate:"datetime"

2.安装

import (
    "fmt"
    "github.com/go-playground/locales/zh_Hans_CN"
    unTrans "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zhTrans "github.com/go-playground/validator/v10/translations/zh"
    "reflect"
)

使用 go get 安装 go get github.com/go-playground/validator/v10

3.基本使用

3.1 简单验证

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name string `validate:"min=1,max=3"`
    Age  int    `validate:"min=1,max=2"`
}

func main() {
    // 结构体验证

    // 实例化验证对象
    var validate = validator.New()

    u1 := &User{Name: "11333333333333333"}
    err := validate.Struct(u1)
    if err != nil {
       fmt.Println(err.Error())
    }
    u2 := User{Name: "dj", Age: 101}
    err = validate.Struct(u2)
    fmt.Println(err)
}

3.2 添加中文翻译器

package main

import (
    "fmt"
    "github.com/go-playground/locales/zh_Hans_CN"
    unTrans "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zhTrans "github.com/go-playground/validator/v10/translations/zh"
    "reflect"
)

type User struct {
    Name string `validate:"min=1,max=3"`
    Age  int    `validate:"min=1,max=2"`
}

// 初始化翻译器
func validateInit(data interface{}) (string, int) {
    // 1.初始化一个校验器
    validate := validator.New()
    uni := unTrans.New(zh_Hans_CN.New())
    trans, _ := uni.GetTranslator("zh_Hans_CN")
     // 自定义翻译器
    err := zhTrans.RegisterDefaultTranslations(validate, trans)
    if err != nil {
       fmt.Println("err:", err)
    }

    validate.RegisterTagNameFunc(func(field reflect.StructField) string {
       label := field.Tag.Get("label")
       return label
    })

    // 2. 将待校验的结构体传入校验器struct方法中
    err = validate.Struct(data)
    
    // 3.判断校验结构error是否为nil
    if err != nil {
       for _, v := range err.(validator.ValidationErrors) {
          return v.Translate(trans), 400
       }
    }
    return "", 200
}

func main() {
    user := &User{Name: "11333333333333333", Age: 101}
    msg, success := validateInit(user)
    fmt.Println(msg, success)
}

3.3 使用注意

1、当搜索条件与特殊标记冲突时,如:逗号(,),或操作(|),中横线(-)等则需要使用 UTF-8十六进制表示形式。

type Test struct {
   Field1 string  `validate:"excludesall=|"`    // 错误
   Field2 string `validate:"excludesall=0x7C"` // 正确.
}

2、可通过validationErrors := errs.(validator.ValidationErrors)获取错误对象自定义返回响应错误

3、自定义校验结果翻译

参考链接:juejin.cn/post/684790…