站长博客
站长博客随手笔记
Toggle navigation
站长博客
Home
MacOS
Database
Linux
PHP
Git
Golang
About Me
Archives
Tags
Go 使用validator进行后端数据校验
2021-01-30 19:16:55
1222
0
0
admin
<strong>包下载:go get github.com/go-playground/validator/v10</strong></p> <h2 class="heading" data-id="heading-0">一、概述</h2> <p>在接口开发经常会遇到一个问题是后端需要写大量的繁琐代码进行数据校验,所以就想着有没有像前端校验一样写规则进行匹配校验,然后就发现了validator包,一个比较强大的校验工具包下面是一些学习总结,详细内容可以查看<a target="_blank" href="https://github.com/go-playground/validator" rel="nofollow noopener noreferrer">validator</a></p> <h2 class="heading" data-id="heading-1">二、操作符说明</h2> <table> <thead> <tr> <th>标记</th> <th>标记说明</th> </tr> </thead> <tbody> <tr> <td>,</td> <td>多操作符分割</td> </tr> <tr> <td>|</td> <td>或操作。使用多个约束,只需要满足其中一个,例如<code>rgb|rgba</code></td> </tr> <tr> <td>-</td> <td>跳过字段验证</td> </tr> </tbody> </table> <h2 class="heading" data-id="heading-2">三、常用标记说明</h2> <table> <thead> <tr> <th>标记</th> <th>标记说明</th> <th>例</th> </tr> </thead> <tbody> <tr> <td>required</td> <td>必填。表示此项是必填的,不能为0值</td> <td>Field或Struct <code>validate:"required"</code></td> </tr> <tr> <td>omitempty</td> <td>空时忽略</td> <td>Field或Struct <code>validate:"omitempty"</code></td> </tr> <tr> <td>len</td> <td>长度</td> <td>Field <code>validate:"len=0"</code></td> </tr> <tr> <td>eq</td> <td>等于</td> <td>Field <code>validate:"eq=0"</code></td> </tr> <tr> <td>gt</td> <td>大于</td> <td>Field <code>validate:"gt=0"</code></td> </tr> <tr> <td>gte</td> <td>大于等于</td> <td>Field <code>validate:"gte=0"</code></td> </tr> <tr> <td>lt</td> <td>小于</td> <td>Field <code>validate:"lt=0"</code></td> </tr> <tr> <td>lte</td> <td>小于等于</td> <td>Field <code>validate:"lte=0"</code></td> </tr> <tr> <td>eqfield</td> <td>同一结构体字段相等</td> <td>Field <code>validate:"eqfield=Field2"</code></td> </tr> <tr> <td>nefield</td> <td>同一结构体字段不相等</td> <td>Field <code>validate:"nefield=Field2"</code></td> </tr> <tr> <td>gtfield</td> <td>大于同一结构体字段</td> <td>Field <code>validate:"gtfield=Field2"</code></td> </tr> <tr> <td>gtefield</td> <td>大于等于同一结构体字段</td> <td>Field <code>validate:"gtefield=Field2"</code></td> </tr> <tr> <td>ltfield</td> <td>小于同一结构体字段</td> <td>Field <code>validate:"ltfield=Field2"</code></td> </tr> <tr> <td>ltefield</td> <td>小于等于同一结构体字段</td> <td>Field <code>validate:"ltefield=Field2"</code></td> </tr> <tr> <td>eqcsfield</td> <td>跨不同结构体字段相等</td> <td>Struct1.Field <code>validate:"eqcsfield=Struct2.Field2"</code></td> </tr> <tr> <td>necsfield</td> <td>跨不同结构体字段不相等</td> <td>Struct1.Field <code>validate:"necsfield=Struct2.Field2"</code></td> </tr> <tr> <td>gtcsfield</td> <td>大于跨不同结构体字段</td> <td>Struct1.Field <code>validate:"gtcsfield=Struct2.Field2"</code></td> </tr> <tr> <td>gtecsfield</td> <td>大于等于跨不同结构体字段</td> <td>Struct1.Field <code>validate:"gtecsfield=Struct2.Field2"</code></td> </tr> <tr> <td>ltcsfield</td> <td>小于跨不同结构体字段</td> <td>Struct1.Field <code>validate:"ltcsfield=Struct2.Field2"</code></td> </tr> <tr> <td>ltecsfield</td> <td>小于等于跨不同结构体字段</td> <td>Struct1.Field <code>validate:"ltecsfield=Struct2.Field2"</code></td> </tr> <tr> <td>min</td> <td>最大值</td> <td>Field <code>validate:"min=1"</code></td> </tr> <tr> <td>max</td> <td>最小值</td> <td>Field <code>validate:"max=2"</code></td> </tr> <tr> <td>structonly</td> <td>仅验证结构体,不验证任何结构体字段</td> <td>Struct <code>validate:"structonly"</code></td> </tr> <tr> <td>nostructlevel</td> <td>不运行任何结构级别的验证</td> <td>Struct <code>validate:"nostructlevel"</code></td> </tr> <tr> <td>dive</td> <td>向下延伸验证,多层向下需要多个dive标记</td> <td>[][]string <code>validate:"gt=0,dive,len=1,dive,required"</code></td> </tr> <tr> <td>dive Keys & EndKeys</td> <td>与dive同时使用,用于对map对象的键的和值的验证,keys为键,endkeys为值</td> <td>map[string]string <code>validate:"gt=0,dive,keys,eq=1\|eq=2,endkeys,required"</code></td> </tr> <tr> <td>required_with</td> <td>其他字段其中一个不为空且当前字段不为空</td> <td>Field <code>validate:"required_with=Field1 Field2"</code></td> </tr> <tr> <td>required_with_all</td> <td>其他所有字段不为空且当前字段不为空</td> <td>Field <code>validate:"required_with_all=Field1 Field2"</code></td> </tr> <tr> <td>required_without</td> <td>其他字段其中一个为空且当前字段不为空</td> <td>Field `validate:"required_without=Field1 Field2"</td> </tr> <tr> <td>required_without_all</td> <td>其他所有字段为空且当前字段不为空</td> <td>Field <code>validate:"required_without_all=Field1 Field2"</code></td> </tr> <tr> <td>isdefault</td> <td>是默认值</td> <td>Field <code>validate:"isdefault=0"</code></td> </tr> <tr> <td>oneof</td> <td>其中之一。只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围</td> <td>Field <code>validate:"oneof=5 7 9"</code><br /> Field <code>validate:"oneof='red green' 'blue yellow'"</code><br /> Field <code>validate:"oneof=5 7 9"</code> </td> </tr> <tr> <td>containsfield</td> <td>字段包含另一个字段</td> <td>Field <code>validate:"containsfield=Field2"</code></td> </tr> <tr> <td>excludesfield</td> <td>字段不包含另一个字段</td> <td>Field <code>validate:"excludesfield=Field2"</code></td> </tr> <tr> <td>unique</td> <td>是否唯一,通常用于切片或结构体</td> <td>Field <code>validate:"unique"</code></td> </tr> <tr> <td>alphanum</td> <td>字符串值是否只包含 ASCII 字母数字字符</td> <td>Field <code>validate:"alphanum"</code></td> </tr> <tr> <td>alphaunicode</td> <td>字符串值是否只包含 unicode 字符</td> <td>Field <code>validate:"alphaunicode"</code></td> </tr> <tr> <td>alphanumunicode</td> <td>字符串值是否只包含 unicode 字母数字字符</td> <td>Field <code>validate:"alphanumunicode"</code></td> </tr> <tr> <td>numeric</td> <td>字符串值是否包含基本的数值</td> <td>Field <code>validate:"numeric"</code></td> </tr> <tr> <td>hexadecimal</td> <td>字符串值是否包含有效的十六进制</td> <td>Field <code>validate:"hexadecimal"</code></td> </tr> <tr> <td>hexcolor</td> <td>字符串值是否包含有效的十六进制颜色</td> <td>Field <code>validate:"hexcolor"</code></td> </tr> <tr> <td>lowercase</td> <td>符串值是否只包含小写字符</td> <td>Field <code>validate:"lowercase"</code></td> </tr> <tr> <td>uppercase</td> <td>符串值是否只包含大写字符</td> <td>Field <code>validate:"uppercase"</code></td> </tr> <tr> <td>email</td> <td>字符串值包含一个有效的电子邮件</td> <td>Field <code>validate:"email"</code></td> </tr> <tr> <td>json</td> <td>字符串值是否为有效的 JSON</td> <td>Field <code>validate:"json"</code></td> </tr> <tr> <td>file</td> <td>符串值是否包含有效的文件路径,以及该文件是否存在于计算机上</td> <td>Field <code>validate:"file"</code></td> </tr> <tr> <td>url</td> <td>符串值是否包含有效的 url</td> <td>Field <code>validate:"url"</code></td> </tr> <tr> <td>uri</td> <td>符串值是否包含有效的 uri</td> <td>Field <code>validate:"uri"</code></td> </tr> <tr> <td>base64</td> <td>字符串值是否包含有效的 base64值</td> <td>Field <code>validate:"base64"</code></td> </tr> <tr> <td>contains</td> <td>字符串值包含子字符串值</td> <td>Field <code>validate:"contains=@"</code></td> </tr> <tr> <td>containsany</td> <td>字符串值包含子字符串值中的任何字符</td> <td>Field <code>validate:"containsany=abc"</code></td> </tr> <tr> <td>containsrune</td> <td>字符串值包含提供的特殊符号值</td> <td>Field <code>validate:"containsrune=☢"</code></td> </tr> <tr> <td>excludes</td> <td>字符串值不包含子字符串值</td> <td>Field <code>validate:"excludes=@"</code></td> </tr> <tr> <td>excludesall</td> <td>字符串值不包含任何子字符串值</td> <td>Field <code>validate:"excludesall=abc"</code></td> </tr> <tr> <td>excludesrune</td> <td>字符串值不包含提供的特殊符号值</td> <td>Field <code>validate:"containsrune=☢"</code></td> </tr> <tr> <td>startswith</td> <td>字符串以提供的字符串值开始</td> <td>Field <code>validate:"startswith=abc"</code></td> </tr> <tr> <td>endswith</td> <td>字符串以提供的字符串值结束</td> <td>Field <code>validate:"endswith=abc"</code></td> </tr> <tr> <td>ip</td> <td>字符串值是否包含有效的 IP 地址</td> <td>Field <code>validate:"ip"</code></td> </tr> <tr> <td>ipv4</td> <td>字符串值是否包含有效的 ipv4地址</td> <td>Field <code>validate:"ipv4"</code></td> </tr> <tr> <td>ipv6</td> <td>字符串值是否包含有效的 ipv6地址</td> <td>Field <code>validate:"ipv6"</code></td> </tr> <tr> <td>datetime</td> <td>字符串值是否包含有效的日期</td> <td> Field <code>validate:"datetime"</code><br /> Field <code>validate:"datetime=2006-01-02"</code> 表示是否是这种格式的日期字符串 </td> </tr> <tr> <td>latitude</td> <td>表示是否是纬度</td> <td> Field <code>validate:"latitude"</code> </td> </tr> <tr> <td>longitude</td> <td>表示是否是经度</td> <td> Field <code>validate:"longitude"</code> </td> </tr> </tbody> </table> <h2 class="heading" data-id="heading-3">四、标记使用注意</h2> <p>1、当搜索条件与特殊标记冲突时,如:逗号(,),或操作(|),中横线(-)等则需要使用 UTF-8十六进制表示形式</p> <p>例:</p> ``` type Test struct { Field1 string `validate:"excludesall=|"` // 错误 Field2 string `validate:"excludesall=0x7C"` // 正确. } ``` 2、可通过validationErrors := errs.(validator.ValidationErrors)获取错误对象自定义返回响应错误 3、自定义校验结果翻译 <pre><code class="hljs bash copyable" lang="bash">// 初始化翻译器 func <span class="hljs-function"><span class="hljs-title">validateInit</span></span>() { zh_ch := zh.New() uni := ut.New(zh_ch) // 万能翻译器,保存所有的语言环境和翻译数据 Trans, _ = uni.GetTranslator(<span class="hljs-string">"zh"</span>) // 翻译器 Validate = validator.New() _ = zh_translations.RegisterDefaultTranslations(Validate, Trans) // 添加额外翻译 _ = Validate.RegisterTranslation(<span class="hljs-string">"required_without"</span>, Trans, func(ut ut.Translator) error { <span class="hljs-built_in">return</span> ut.Add(<span class="hljs-string">"required_without"</span>, <span class="hljs-string">"{0} 为必填字段!"</span>, <span class="hljs-literal">true</span>) }, func(ut ut.Translator, fe validator.FieldError) string { t, _ := ut.T(<span class="hljs-string">"required_without"</span>, fe.Field()) <span class="hljs-built_in">return</span> t }) } <span class="copy-code-btn">复制代码</span></code></pre><h2 class="heading" data-id="heading-4">五、使用示例</h2> ```go package main import ( "fmt" "github.com/go-playground/validator/v10" ) // 实例化验证对象 var validate = validator.New() func main() { // 结构体验证 type Inner struct { String string `validate:"contains=111"` } inner := &Inner{String: "11@"} errs := validate.Struct(inner) if errs != nil { fmt.Println(errs.Error()) } // 变量验证 m := map[string]string{"": "", "val3": "val3"} errs = validate.Var(m, "required,dive,keys,required,endkeys,required") if errs != nil { fmt.Println(errs.Error()) } } ``` 除了 <code>v.Struct</code> 之外,还有好几个: <ul> <li><code>func (v *Validate) Struct(s interface{}) error</code> 接收的参数为一个struct</li> <li><code>func (v *Validate) StructExcept(s interface{}, fields ...string) error</code> 校验struct中的选项,不过除了fields里所给的字段</li> <li><code>func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error</code> 接收一个struct和一个函数,这个函数的返回值为bool,决定是否跳过该选项</li> <li><code>func (v *Validate) StructPartial(s interface{}, fields ...string) error</code> 接收一个struct和fields,仅校验在fields里的值</li> <li><code>func (v *Validate) Var(field interface{}, tag string) error</code> 接收一个变量和一个tag的值,比如 <code>validate.Var(i, "gt=1,lt=10")</code></li> <li><code>func (v *Validate) VarWithValue(field interface{}, other interface{}, tag string) error</code> 将两个变量进行对比,比如 <code>validate.VarWithValue(s1, s2, "eqcsfield")</code></li> </ul> <blockquote> 上述方法均有另外一种形式,就是带上context的那种,函数名字就是上述函数名,最后加一个 <code>Ctx</code>。 </blockquote> <p>了解了这些之后,我们还需要了解的一个东西就是,在Golang中,我们用 <code>struct tag</code> 来定义表单合法的值。比如如果我们希望某个字段是邮件,那么可以这样定义:</p> ```go type MyStruct struct { Email string `validate:"email"` } ``` <p>如果有多个校验条件,可以用英文逗号 <code>,</code> 来进行连接,他们是 <code>AND</code> 的关系,如果想要 <code>OR</code> 的关系,那么使用 <code>|</code>,比如:</p>
Prev:
使用 n 命令切换 node/npm 版本
Next:
git 获取某个文件第一次 commit 的时间
0
likes
1222
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
Table of content