结构字段验证--validator.v9
官网:https://godoc.org/gopkg.in/go-playground/validator.v9#hdr-Baked_In_Validators_and_Tags
package validator
validator.v9: gopkg.in/go-playground/validator.v9
使用:import "gopkg.in/go-playground/validator.v9"
validator包基于标签实现结构和单个字段的值验证。 它还可以处理嵌套结构的跨场验证和跨结构验证,并且能够深入了解任何类型的数组和映射。
更多例子:https://github.com/go-playground/validator/tree/v9/_examples
验证函数返回类型错误 这样做的方式实际上就是标准库的工作方式,请参见file.Open方法:
https://golang.org/pkg/os/#Open.
作者返回类型“错误”以避免以下讨论的问题,其中 error 总是 != nil:
http://stackoverflow.com/a/29138676/3158232
https://github.com/go-playground/validator/issues/134
验证器仅用于错误验证输入的InvalidValidationError,nil或ValidationErrors作为类型错误;因此,在您的代码中,您需要做的就是检查返回的错误是否为nil,如果不检查错误是否为InvalidValidationError(如果需要,大部分时间不是),请键入类型为ValidationErrors,如此ERR。(validator.ValidationErrors)。
自定义验证功能
可以添加自定义验证功能。例:
// 结构体
func customFunc(fl validator.FieldLevel) bool { if fl.Field().String() == "invalid" {
return false
} return true
} validate.RegisterValidation("custom tag name", customFunc)
// 注意:使用与现有函数相同的标记名称将覆盖现有函数
完整示例:
package main import (
"fmt"
"gopkg.in/go-playground/validator.v9"
) type User struct {
Name string `validate:"is-zhou"`
} func (u *User) userValidator() error {
validate := validator.New()
validate.RegisterValidation("is-zhou", ValidateMyVal)
err := validate.Struct(u)
return err
}
// ValidateMyVal implements validator.Func
func ValidateMyVal(fl validator.FieldLevel) bool {
return fl.Field().String() == "zhou"
} func main() {
user1 := User{
Name:"zhou",
}
if err := user1.userValidator(); err != nil {
fmt.Println("user1", err)
} user2 := User{
Name:"zhou1",
}
if err := user2.userValidator(); err != nil {
fmt.Println("user2", err)
}
}
打印结果:
user2 Key: 'User.Name' Error:Field validation for 'Name' failed on the 'is-zhou' tag
跨字段验证
跨字段验证可以通过以下标签完成:
- eqfield
- nefield
- gtfield
- gtefield
- ltfield
- ltefield
- eqcsfield
- necsfield
- gtcsfield
- gtecsfield
- ltcsfield
- ltecsfield
但是,如果需要某些自定义跨字段验证,则可以使用自定义验证来完成。
为什么不只是有跨字段验证标签(即只有eqcsfield而不是eqfield)?
原因是效率。如果要检查同一结构中的字段“eqfield”,只需在同一结构(1级)上找到该字段。但是,如果我们使用“eqcsfield”,它可能会降低多个级别。例:
type Inner struct {
StartDate time.Time
} type Outer struct {
InnerStructField *Inner
CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"`
} now := time.Now() inner := &Inner{
StartDate: now,
} outer := &Outer{
InnerStructField: inner,
CreatedAt: now,
} errs := validate.Struct(outer)
// 注意:调用validate.Struct(val)时,topStruct将是传递给函数的顶级结构,
// 当调用validate.VarWithValue(val,field,tag)时,val将是你传递的任何东西,比如: struct,field ......
// 当调用validate.Field(field,tag)时,val将为nil
多个验证器
字段上的多个验证器将按定义的顺序处理。例:
ype Test struct {
Field `validate:"max=10,min=1"`
} // 先验证max,然后才验证min
错误的验证不会处理,例如:
type Test struct {
Field `validate:"min=10,max=0"`
} // this definition of min max will never succeed
使用验证器标签:
跨字段验证仅比较同一结构上的字段。如果需要不同结构不同字段比较验证,您应该实现自己的自定义验证器。
逗号(“,”)是验证标记的默认分隔符。如果你希望在参数中包含一个逗号(即excludesall =,),你将需要使用UTF-8十六进制表示0x2C,它在代码中被替换为逗号,因此上面将变为excludesall = 0x2C。
type Test struct {
Field `validate:"excludesall=,"` // 错误用法,不能包含逗号
Field `validate:"excludesall=0x2C"` // 正确用法,使用UTF-8十六进制表示
}
管道(“|”)是'或'验证标签的分隔符。如果您希望在参数中包含管道,即excludesall = |你将需要使用UTF-8十六进制表示0x7C,它在代码中被替换为管道,所以上面将成为excludesall = 0x7C
type Test struct {
Field `validate:"excludesall=|"` // BAD! Do not include a a pipe!
Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation.
}
Baked In Validators and Tags
以下是当前内置验证器的列表:
- //忽略字段,告诉验证跳过这个struct字段;这对于忽略嵌入式结构的验证尤其方便。 (用法: - )
| //这是'or'运算符,允许使用和接受多个验证器。 (用法:rbg | rgba)< - 这将允许接受rgb或rgba颜色。这也可以与'and'结合使用(例如:用法:omitempty,rgb | rgba)
structonly //当遇到嵌套结构的字段并包含此标志时,将运行嵌套结构上的任何验证,但不会验证任何嵌套结构字段。如果您在程序内部知道结构有效,但需要验证它是否已分配,这非常有用。注意:结构本身只能使用“required”和“omitempty”。
nostructlevel //与structonly标记相同,但不会运行任何结构级别验证。
omitempty //允许条件验证,例如,如果字段未设置值(由“required”验证器确定),则其他验证(如min或max)将不会运行,但如果设置了值,则验证将运行。
dive //这告诉验证者潜入切片,数组或映射,并使用后面的验证标记验证切片,数组或映射的该级别。还支持多维嵌套,您希望dive的每个级别都需要另一个dive标签。dive有一些子标签,'keys'和'endkeys',请参阅下面的keys和endkeys部分
----
required //这将验证该值不是数据类型的默认零值。数字不为0,字符串不为 " ", slices, maps, pointers, interfaces, channels and functions 不为 nil
isdefault //这验证了该值是默认值,几乎与所需值相反。
len= //对于数字,长度将确保该值等于给定的参数。对于字符串,它会检查字符串长度是否与字符数完全相同。对于切片,数组和map,验证元素个数。
max= //对于数字,max将确保该值小于或等于给定的参数。对于字符串,它会检查字符串长度是否最多为该字符数。对于切片,数组和map,验证元素个数。
min=
eq= //对于字符串和数字,eq将确保该值等于给定的参数。对于切片,数组和map,验证元素个数。
ne= //和eq相反
oneof=red green (oneof= ) //对于字符串,整数和uint,oneof将确保该值是参数中的值之一。参数应该是由空格分隔的值列表。值可以是字符串或数字。
gt= //对于数字,这将确保该值大于给定的参数。对于字符串,它会检查字符串长度是否大于该字符数。对于切片,数组和map,它会验证元素个数。
gt //对于time.Time确保时间值大于time.Now.UTC()
gte= //大于等于
gte //对于time.Time确保时间值大于或等于time.Now.UTC()
lt= //小于
lt //对于time.Time确保时间值小于time.Now.UTC()
lte= //小于等于
lte //对于time.Time确保时间值小于等于time.Now.UTC()
----
unique //对于数组和切片,unique将确保没有重复项。对于map,unique将确保没有重复值。
alpha //这将验证字符串值是否仅包含ASCII字母字符
alphanum //这将验证字符串值是否仅包含ASCII字母数字字符
alphaunicode //这将验证字符串值是否仅包含unicode字符
alphanumunicode //这将验证字符串值是否仅包含unicode字母数字字符
numeric //这将验证字符串值是否包含基本数值。基本排除指数等...对于整数或浮点数,它返回true。
hexadecimal //这将验证字符串值是否包含有效的十六进制
hexcolor //这验证字符串值包含有效的十六进制颜色,包括#标签(#)
rgb //这将验证字符串值是否包含有效的rgb颜色
rgba //这将验证字符串值是否包含有效的rgba颜色
hsl //这将验证字符串值是否包含有效的hsl颜色
hsla //这将验证字符串值是否包含有效的hsla颜色
email //这验证字符串值包含有效的电子邮件这可能不符合任何rfc标准的所有可能性,但任何电子邮件提供商都不接受所有可能性
file //这将验证字符串值是否包含有效的文件路径,并且该文件存在于计算机上。这是使用os.Stat完成的,它是一个独立于平台的函数。
url //这会验证字符串值是否包含有效的url这将接受golang请求uri接受的任何url,但必须包含一个模式,例如http://或rtmp://
uri //这验证了字符串值包含有效的uri。这将接受uri接受的golang请求的任何uri
base64 //这将验证字符串值是否包含有效的base64值。虽然空字符串是有效的base64,但这会将空字符串报告为错误,如果您希望接受空字符串作为有效字符,则可以将此字符串与omitempty标记一起使用。
base64url //这会根据RFC4648规范验证字符串值是否包含有效的base64 URL安全值。尽管空字符串是有效的base64 URL安全值,但这会将空字符串报告为错误,如果您希望接受空字符串作为有效字符,则可以将此字符串与omitempty标记一起使用。
btc_addr //这将验证字符串值是否包含有效的比特币地址。检查字符串的格式以确保它匹配P2PKH,P2SH三种格式之一并执行校验和验证
btc_addr_bech32 //这验证了字符串值包含bip-0173定义的有效比特币Bech32地址(https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)特别感谢Pieter Wuille提供的参考实现。
eth_addr //这将验证字符串值是否包含有效的以太坊地址。检查字符串的格式以确保它符合标准的以太坊地址格式完全验证被https://github.com/golang/crypto/pull/28阻止
contains=@ //这将验证字符串值是否包含子字符串值
containsany=!@#? //这将验证字符串值是否包含子字符串值中的任何Unicode code points。
containsrune=@ //这将验证字符串值是否包含提供的符文值。
excludes=@ //这验证字符串值不包含子字符串值。
excludesall=!@#? //这将验证字符串值在子字符串值中是否包含任何Unicode code points。
excludesrune=@ //这将验证字符串值是否包含提供的符文值。
-----
isbn //这将验证字符串值是否包含有效的isbn10或isbn13值。
isbn10 //这将验证字符串值是否包含有效的isbn10值。
isbn13 //这将验证字符串值是否包含有效的isbn13值。
uuid //这将验证字符串值是否包含有效的UUID。
uuid3 //这将验证字符串值是否包含有效的版本3 UUID。
uuid4 //这将验证字符串值是否包含有效的版本4 UUID。
uuid5 //这将验证字符串值是否包含有效的版本5 UUID。
-----
ascii //这将验证字符串值是否仅包含ASCII字符。注意:如果字符串为空,则验证为true
printascii //这将验证字符串值是否仅包含可打印的ASCII字符。注意:如果字符串为空,则验证为true。
multibyte //这将验证字符串值是否包含一个或多个多字节字符。注意:如果字符串为空,则验证为true
datauri //这将验证字符串值是否包含有效的DataURI。注意:这也将验证数据部分是否有效base64
latitude //这将验证字符串值是否包含有效的纬度。
longitude //这将验证字符串值是否包含有效经度。
ssn //这将验证字符串值是否包含有效的美国社会安全号码。
ip //这将验证字符串值是否包含有效的IP地址
ipv4 //这将验证字符串值是否包含有效的v4 IP地址
ipv6 //这将验证字符串值是否包含有效的v6 IP地址
cidr //这将验证字符串值是否包含有效的CIDR地址
cidrv4 //这将验证字符串值是否包含有效的v4 CIDR地址
cidrv5 //这将验证字符串值是否包含有效的v5 CIDR地址
tcp_addr //这将验证字符串值是否包含有效的可解析TCP地址
tcp4_addr //这将验证字符串值是否包含有效的可解析v4 TCP地址
tcp6_addr //这将验证字符串值是否包含有效的可解析v6 TCP地址
udp_addr //这将验证字符串值是否包含有效的可解析UDP地址
udp4_addr //这将验证字符串值是否包含有效的可解析v4 UDP地址
udp6_addr //这将验证字符串值是否包含有效的可解析v6 UDP地址
ip_addr //这将验证字符串值是否包含有效的可解析IP地址
ip4_addr //这将验证字符串值是否包含有效的可解析v4 IP地址
ip6_addr //这将验证字符串值是否包含有效的可解析v6 IP地址
unix_addr //这将验证字符串值是否包含有效的Unix地址
------
mac //这将验证字符串值是否包含有效的MAC地址
//注意:有关可接受的格式和类型,请参阅Go的ParseMAC: http://golang.org/src/net/mac.go?s=866:918#L29
hostname //根据RFC 952 https://tools.ietf.org/html/rfc952验证字符串值是否为有效主机名
hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias //根据RFC 1123 https://tools.ietf.org/html/rfc1123验证字符串值是否为有效主机名
fqdn //这将验证字符串值是否包含有效的FQDN (完全合格的有效域名),Full Qualified Domain Name (FQDN)
html //这将验证字符串值是否为HTML元素标记,包括https://developer.mozilla.org/en-US/docs/Web/HTML/Element中描述的标记。
html_encoded //这将验证字符串值是十进制或十六进制格式的正确字符引用
url_encoded //这验证了根据https://tools.ietf.org/html/rfc3986#section-2.1对字符串值进行了百分比编码(URL编码)
dive
例1:
[][]string with validation tag "gt=0,dive,len=1,dive,required"
// gt=0 被用于验证 []
// len=1 被用于验证 []string
// required 被用于验证 string
例2:
[][]string with validation tag "gt=0,dive,dive,required"
// gt=0 被用于验证 []
// []string 将被保留验证
// required 被用于验证 string
Keys & EndKeys
这些将在dive标签之后直接使用,并告诉验证者“keys”和“endkeys”之间的任何内容都适用于map的key而不是value;把它想象成'dive'标签,但是对于map的keys而不是values。
还支持多维嵌套,您希望验证的每个级别都需要另一个“keys”和“endkeys”标记。这些标签仅对map有效。
用法:dive,keys,othertagvalidation(s),endkeys,valuevalidationtags
例1:
map[string]string with validation tag "gt=0,dive,keys,eg=1|eq=2,endkeys,required"
// gt=0 will be applied to the map itself
// eg=1|eq=2 will be applied to the map keys
// required will be applied to map values
例2:
map[[]string]string with validation tag "gt=0,dive,keys,dive,eq=1|eq=2,endkeys,required"
// gt=0 will be applied to the map itself
// eg=1|eq=2 will be applied to each array element in the the map keys
// required will be applied to map values
Field Equals Another Field
这将在结构内或传入字段中针对另一个字段值验证字段值。
例1:
// 使用以下方法验证密码字段:
Usage: eqfield=ConfirmPassword
// 按字段验证:
validate.VarWithValue(password, confirmpassword, "eqfield")
字段等于另一字段(相对)
这与eqfield相同,只是它验证了相对于顶级结构提供的字段。
Usage: eqcsfield=InnerStructField.Field)
字段不等于另一个字段
这将在结构内或传入字段中针对另一个字段值验证字段值。
// 确认两种颜色不一样:
// 对色域进行验证:
Usage: nefield=Color2 // 按字段验证:
validate.VarWithValue(color1, color2, "nefield")
字段不等于另一个字段(相对)
这与nefield相同,只是它验证了相对于顶级结构提供的字段。
Usage: necsfield=InnerStructField.Field
字段大于另一字段
仅对Numbers和time.Time类型有效,这将在结构内或传入字段中针对另一个字段值验证字段值。用法示例用于验证开始日期和结束日期:
例1:
// 用于验证结束字段(对比开始字段):
validate.Struct Usage(gtfield=Start)
例2:
// 按字段验证:
validate.VarWithValue(start, end, "gtfield")
字段大于另一个相对字段
这与gtfield相同,不同之处在于它验证了相对于顶级结构提供的字段。
Usage: gtcsfield=InnerStructField.Field
字段大于或等于另一字段
仅对Numbers和time.Time类型有效,这将在结构内或传入字段中针对另一个字段值验证字段值。用法示例用于验证开始日期和结束日期:
例1:
// 用于验证结束字段(相对开始字段):
validate.Struct Usage(gtefield=Start)
例2:
// 通过字段验证:
validate.VarWithValue(start, end, "gtefield")
字段大于或等于另一个相对字段
这与gtefield相同,只是它验证了相对于顶级结构提供的字段。
Usage: gtecsfield=InnerStructField.Field
小于另一字段
仅对Numbers和time.Time类型有效,这将在结构内或传入字段中针对另一个字段值验证字段值。用法示例用于验证开始日期和结束日期:
例1:
// Validation on End field using:
validate.Struct Usage(ltfield=Start)
例2:
// Validating by field:
validate.VarWithValue(start, end, "ltfield")
小于另一相对字段
这与ltfield相同,只是它验证了相对于顶级结构提供的字段。
Usage: ltcsfield=InnerStructField.Field
小于等于另一字段
仅对Numbers和time.Time类型有效,这将在结构内或传入字段中针对另一个字段值验证字段值。用法示例用于验证开始日期和结束日期:
例1:
// Validation on End field using:
validate.Struct Usage(ltefield=Start)
例2:
// Validating by field:
validate.VarWithValue(start, end, "ltefield")
小于等于另一相对字段
这与ltefield相同,只是它验证了相对于顶级结构提供的字段。
Usage: ltecsfield=InnerStructField.Field
======
Alias Validators and Tags(别名验证器和标签)
注意:返回error时,“FieldError”中返回的tag将是alias tag,除非dive tag是alias的一部分。dive tag之后的所有内容都不会报告为alias tag。此外,前一种情况中的“ActualTag”将是失败的alias中的实际tag。 以下是当前内置 alias tag 的列表:
"iscolor"
alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor)
Validator notes:
regex
a regex validator won't be added because commas and = signs can be part
of a regex which conflict with the validation definitions. Although
workarounds can be made, they take away from using pure regex's.
Furthermore it's quick and dirty but the regex's become harder to
maintain and are not reusable, so it's as much a programming philosophy
as anything. In place of this new validator functions should be created; a regex can
be used within the validator function and even be precompiled for better
efficiency within regexes.go. And the best reason, you can submit a pull request and we can keep on
adding to the validation library of this package!
Panics
This package panics when bad input is provided, this is by design, bad code like that should not make it to production.
type Test struct {
TestField string `validate:"nonexistantfunction=1"`
} t := &Test{
TestField: "Test"
} validate.Struct(t) // this will panic
结构字段验证--validator.v9的更多相关文章
- SpringMVC利用Hibernate validator做字段验证
1.添加Hiberbate validator相关的jar包 2.字需要验证的formbean 上添加验证的注解,内置注解有: dBean Validation 中内置的 constraint @Nu ...
- [原创]java WEB学习笔记71:Struts2 学习之路-- struts2常见的内建验证程序及注意点,短路验证,非字段验证,错误消息的重用
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [ASP.NET MVC]如何定制Numeric属性/字段验证消息
原文:[ASP.NET MVC]如何定制Numeric属性/字段验证消息 对于一个Numeric属性/字段,ASP.NET MVC会自动进行数据类型的验证(客户端验证),以确保输入的是一个有效的数字, ...
- Struts(二十四):短路验证&重写实现转换验证失败时短路&非字段验证
短路验证: 若对一个字段使用多个验证器,默认情况下会执行所有的验证.若希望前面的验证器没有通过,后面的验证器就不再执行,可以使用短路验证. 1.如下拦截器,如果输入字符串,提交表单后,默认是会出现三个 ...
- django 表单验证和字段验证
表单验证和字段验证 表单验证发生在数据验证之后.如果你需要自定义这个过程,有几个不同的地方可以修改,每个地方的目的不一样.表单处理过程中要运行三种类别的验证方法.它们通常在你调用表单的is_valid ...
- Java 通过JDBC查询数据库表结构(字段名称,类型,长度等)
Java 通过JDBC查询数据库表结构(字段名称,类型,长度等) 发布者:唛唛家的豆子 时间:2012-11-20 17:54:02 Java 通过JDBC查询数据库表结构(字段名称,类型,长 ...
- Ext.Net学习笔记21:Ext.Net FormPanel 字段验证(validation)
Ext.Net学习笔记21:Ext.Net FormPanel 字段验证(validation) 作为表单,字段验证当然是不能少的,今天我们来一起看看Ext.Net FormPanel的字段验证功能. ...
- 27)django-form操作示例(动态Select数据,自定义字段验证,全局验证等)
1)普通传递select数据 # -*- coding:utf-8 -*- __author__ = 'shisanjun' from django import forms from django. ...
- JEECG 不同(角色的)人对同样的字段数据,使用不同的字段验证规则
JEECG智能开发平台v3 开发指南http://www.jeecg.org/book/jeecg_v3.html jeecg: JEECG是一款基于代码生成器的J2EE快速开发平台,开源界“小普元” ...
随机推荐
- 前端性能优化:细说JavaScript的加载与执行
本文主要是从性能优化的角度来探讨JavaScript在加载与执行过程中的优化思路与实践方法,既是细说,文中在涉及原理性的地方,不免会多说几句,还望各位读者保持耐心,仔细理解,请相信,您的耐心付出一定会 ...
- Multi Paxos
Multi Paxos [2] 通过basic paxos 以上步骤分布式系统已经能确定一个值,“只确定一个值有什么用?这可解决不了我面临的问题.” 你心中可能有这样的疑问. 原simple paxo ...
- javase(14)_java基础增强
一.Eclipse的使用 1.在eclipse下Java程序的编写和run as,debug as,及java运行环境的配置. 2.快捷键的配置,常用快捷键: •内容提示:Alt + / •快速修复: ...
- 《c++编程思想》关于虚函数在构造函数行为的理解,理解有误,望告知!
<c++编程思想>书上有一段话:在任何构造函数中,可能只是部分形成对象——我们只能知道基类已被初始化,但并不知道哪个类是从这个基类继承来的.然而,虚函数在继承层次上是“向前”和“向外”进行 ...
- UVa-1368-DNA序列
这题的话,我们每次统计的话,是以列为外层循环,以行为内层循环,逐一按列进行比较. 统计完了之后,题目中要求说到要hamming值最小的,那我们就选用该列最多的字母就可以了,如果有数目相等的字母,那就按 ...
- 【Java_多线程并发编程】基础篇—Thread类中start()和run()方法的区别
1. start() 和 run()的区别说明 start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用. run()方法 ...
- MySQL 资料库概论与MySQL 安装
本文来自:https://www.breakyizhan.com/sql/5648.html 1. 储存与管理资料 储存与管理资料一直是资讯应用上最基本.也是最常见的技术.在还没有使用电脑来管理你的资 ...
- Ubuntu 14.04在虚拟机上的桥接模式下设置静态IP
1.虚拟机--->虚拟机设置 将虚拟机设置为桥接模式 2.查看window 网卡以及IP信息 cmd下输入 ipconfig -all 可以看到,我的网卡为Realtek PCIe GBE Fa ...
- appium+python自动化-adb shell按键操作(input keyevent)
前言 接着上篇介绍input里面的按键操作keyevent事件,发送手机上常用的一些按键操作 keyevent 1.keyevent事件有一张对应的表,可以直接发送对应的数字,也可以方式字符串,如下两 ...
- PHP 判断表单提交的file是否为空
echo '<pre>'; var_dump($product_attach_files); echo "</pre>"; echo ];