脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - golang常用库之字段参数验证库-validator使用详解

golang常用库之字段参数验证库-validator使用详解

2021-01-26 00:57九卷 Golang

这篇文章主要介绍了golang常用库:字段参数验证库-validator使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借价值,需要的朋友可以参考下

golang常用库:gorilla/mux-http路由库使用
golang常用库:配置文件解析库-viper使用
golang常用库:操作数据库的orm框架-gorm基本使用
golang常用库:字段参数验证库-validator使用

一、背景

在平常开发中,特别是在web应用开发中,为了验证输入字段的合法性,都会做一些验证操作。比如对用户提交的表单字段进行验证,或者对请求的API接口字段进行验证,验证字段的合法性,保证输入字段值的安全,防止用户的恶意请求。

一般的做法是用正则表达式,一个字段一个字段的进行验证。一个一个字段验证的话,写起来比较繁琐。那有没更好的方法,进行字段的合法性验证?有, 这就是下面要介绍的 validator 这个验证组件。

代码地址:
https://github.com/go-playground/validator

文档地址:
https://github.com/go-playground/validator/blob/master/README.md

二、功能介绍

这个验证包 github.com/go-playground/validator 验证功能非常多。

标记之间特殊符号说明

  • 逗号( , ):把多个验证标记隔开。注意:隔开逗号之间不能有空格, validate:"lt=0,gt=100",逗号那里不能有空格,否则panic
  • 横线( - ):跳过该字段不验证
  • 竖线( | ):使用多个验证标记,但是只需满足其中一个即可
  • required:表示该字段值必输设置,且不能为默认值
  • omitempty:如果字段未设置,则忽略它

范围比较验证

doc: https://github.com/go-playground/validator/blob/master/README.md#comparisons

范围验证: 切片、数组和map、字符串,验证其长度;数值,验证大小范围

  • lte:小于等于参数值,validate:"lte=3" (小于等于3)
  • gte:大于等于参数值,validate:"lte=0,gte=120" (大于等于0小于等于120)
  • lt:小于参数值,validate:"lt=3" (小于3)
  • gt:大于参数值,validate:"lt=0,gt=120" (大于0小于120)
  • len:等于参数值,validate:"len=2"
  • max:大于等于参数值,validate:"max=2" (大于等于2)
  • min:小于等于参数值,validate:"min=2,max=10" (大于等于2小于等于10)
  • ne:不等于,validate:"ne=2" (不等于2)
  • oneof:只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,validate:"oneof=red green"

例子:

?
1
2
3
4
type User struct {
 Name string `json:"name" validate:"min=0,max=35"`
 Age unit8 `json:"age" validate:"lte=0,gte=90"`
}

更多功能请参看文档 validator comparisons doc

字符串验证

doc: https://github.com/go-playground/validator/blob/master/README.md#strings

  • contains:包含参数子串,validate:"contains=tom" (字段的字符串值包含tom)
  • excludes:包含参数子串,validate:"excludes=tom" (字段的字符串值不包含tom)
  • startswith:以参数子串为前缀,validate:"startswith=golang"
  • endswith:以参数子串为后缀,validate:"startswith=world"

例子:

?
1
2
3
4
type User struct {
 Name string `validate:"contains=tom"`
 Age int `validate:"min=1"`
}

更多功能请参看文档 validator strings doc

字段验证

doc: https://github.com/go-playground/validator/blob/master/README.md#fields

eqcsfield:跨不同结构体字段验证,比如说 Struct1 Filed1,与结构体Struct2 Field2相等,

?
1
2
3
4
5
6
type Struct1 struct {
 Field1 string `validate:eqcsfield=Struct2.Field2`
 Struct2 struct {
 Field2 string
 }
}
  • necsfield:跨不同结构体字段不相等
  • eqfield:同一结构体字段验证相等,最常见的就是输入2次密码验证
?
1
2
3
4
5
6
type User struct {
 Name string `validate:"lte=4"`
 Age int `validate:"min=20"`
 Password string `validate:"min=10"`
 Password2 string `validate:"eqfield=Password"`
}

nefield:同一结构体字段验证不相等

?
1
2
3
4
5
type User struct {
 Name string `validate:"lte=4"`
 Age int `validate:"min=20"`
 Password string `validate:"min=10,nefield=Name"`
}
  • gtefield:大于等于同一结构体字段,validate:"gtefiled=Field2"
  • ltefield:小于等于同一结构体字段

更多功能请参看文档:validator Fields DOC

网络验证

doc: https://github.com/go-playground/validator/blob/master/README.md#network

  • ip:字段值是否包含有效的IP地址,validate:"ip"
  • ipv4:字段值是否包含有效的ipv4地址,validate:"ipv4"
  • ipv6:字段值是否包含有效的ipv6地址,validate:"ipv6"
  • uri:字段值是否包含有效的uri,validate:"uri"
  • url:字段值是否包含有效的uri,validate:"url"

更多功能请参看文档:validator network DOC

Format

doc: https://github.com/go-playground/validator/blob/master/README.md#format

base64:字段值是否包含有效的base64值

更多功能请参看文档 validator strings doc

其他

请参看文档: https://github.com/go-playground/validator/blob/master/README.md#other

三、安装

go get:

go get github.com/go-playground/validator/v10

在文件中引用validator包:

import "github.com/go-playground/validator/v10"

四、validator使用

文档:https://github.com/go-playground/validator/blob/master/README.md#examples

例子1:验证单个字段变量值

validation1.go

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main
 
import (
    "fmt"
 
    "github.com/go-playground/validator/v10"
)
 
func main() {
    validate := validator.New()
 
    var boolTest bool
    err := validate.Var(boolTest, "required")
    if err != nil {
        fmt.Println(err)
    }
    var stringTest string = ""
    err = validate.Var(stringTest, "required")
    if err != nil {
        fmt.Println(err)
    }
 
    var emailTest string = "test@126.com"
    err = validate.Var(emailTest, "email")
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("success") // 输出: success。 说明验证成功
    }
 
    emailTest2 := "test.126.com"
    errs := validate.Var(emailTest2, "required,email")
    if errs != nil {
        fmt.Println(errs) // 输出: Key: "" Error:Field validation for "" failed on the "email" tag。验证失败
    }
 
    fmt.Println("\r\nEnd!!")
 
}

运行输出:

go run simple1.go
Key: '' Error:Field validation for '' failed on the 'required' tag
Key: '' Error:Field validation for '' failed on the 'required' tag
success
Key: '' Error:Field validation for '' failed on the 'email' tag

End!!

例子2:验证结构体struct

from:struct validate

validation_struct.go,这个程序还列出了效验出错字段的一些信息,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package main
 
import (
    "fmt"
 
    "github.com/go-playground/validator/v10"
)
 
type User struct {
    FirstName string `validate:"required"`
    LastName string `validate:"required"`
    Age uint8 `validate:"gte=0,lte=130"`
    Email string `validate:"required,email"`
    Addresses []*Address `validate:"required,dive,required"`
}
 
type Address struct {
    Street string `validate:"required"`
    City string `validate:"required"`
    Planet string `validate:"required"`
    Phone string `validate:"required"`
}
 
func main() {
    address := &Address{
        Street: "Eavesdown Docks",
        Planet: "Persphone",
        Phone: "none",
    }
 
    user := &User{
        FirstName: "Badger",
        LastName: "Smith",
        Age: 135,
        Email: "Badger.Smith@gmail.com",
        Addresses: []*Address{address},
    }
 
    validate := validator.New()
    err := validate.Struct(user)
    if err != nil {
        fmt.Println("=== error msg ====")
        fmt.Println(err)
 
        if _, ok := err.(*validator.InvalidValidationError); ok {
            fmt.Println(err)
            return
        }
 
        fmt.Println("\r\n=========== error field info ====================")
        for _, err := range err.(validator.ValidationErrors) {
 // 列出效验出错字段的信息
            fmt.Println("Namespace: ", err.Namespace())
            fmt.Println("Fild: ", err.Field())
            fmt.Println("StructNamespace: ", err.StructNamespace())
            fmt.Println("StructField: ", err.StructField())
            fmt.Println("Tag: ", err.Tag())
            fmt.Println("ActualTag: ", err.ActualTag())
            fmt.Println("Kind: ", err.Kind())
            fmt.Println("Type: ", err.Type())
            fmt.Println("Value: ", err.Value())
            fmt.Println("Param: ", err.Param())
            fmt.Println()
        }
 
        // from here you can create your own error messages in whatever language you wish
        return
    }
}

运行 输出:

$ go run validation_struct.go
=== error msg ====
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
Key: 'User.Addresses[0].City' Error:Field validation for 'City' failed on the 'required' tag

=========== error field info ====================
Namespace: User.Age
Fild: Age
StructNamespace: User.Age
StructField: Age
Tag: lte
ActualTag: lte
Kind: uint8
Type: uint8
Value: 135
Param: 130

Namespace: User.Addresses[0].City
Fild: City
StructNamespace: User.Addresses[0].City
StructField: City
Tag: required
ActualTag: required
Kind: string
Type: string
Value:
Param:

还可以给字段加一些其他tag信息,方面form,json的解析,如下:

?
1
2
3
4
5
6
type User struct {
 FirstName string `form:"firstname" json:"firstname" validate:"required"`
    LastName string `form:"lastname" json:"lastname" validate:"required"`
    Age uint8 ` form:"age" json:"age"validate:"gte=0,lte=130"`
    Email string ` form:"email" json:"email" validate:"required,email"`
}

用户自定义函数验证

用户自定义函数验证字段是否合法,效验是否正确。

例子3: 通过字段tag自定义函数

validate.RegisterValidation

customer_tag.go:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main
 
import (
    "fmt"
 
    "github.com/go-playground/validator/v10"
)
 
type User struct {
    Name string `form:"name" json:"name" validate:"required,CustomerValidation"` //注意:required和CustomerValidation之间不能有空格,否则panic。CustomerValidation:自定义tag-函数标签
    Age uint8 ` form:"age" json:"age" validate:"gte=0,lte=80"` //注意:gte=0和lte=80之间不能有空格,否则panic
}
 
var validate *validator.Validate
 
func main() {
    validate = validator.New()
    validate.RegisterValidation("CustomerValidation", CustomerValidationFunc) //注册自定义函数,前一个参数是struct里tag自定义,后一个参数是自定义的函数
 
    user := &User{
        Name: "jimmy",
        Age: 86,
    }
 
    fmt.Println("first value: ", user)
    err := validate.Struct(user)
    if err != nil {
        fmt.Printf("Err(s):\n%+v\n", err)
    }
 
    user.Name = "tom"
    user.Age = 29
    fmt.Println("second value: ", user)
    err = validate.Struct(user)
    if err != nil {
        fmt.Printf("Err(s):\n%+v\n", err)
    }
}
 
// 自定义函数
func CustomerValidationFunc(f1 validator.FieldLevel) bool {
 // f1 包含了字段相关信息
 // f1.Field() 获取当前字段信息
 // f1.Param() 获取tag对应的参数
 // f1.FieldName() 获取字段名称
 
    return f1.Field().String() == "jimmy"
}

运行输出:

$ go run customer.go
first value: &{jimmy 86}
Err(s):
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
second value: &{tom 29}
Err(s):
Key: 'User.Name' Error:Field validation for 'Name' failed on the 'CustomerValidation' tag

**注意

上面代码user struct定义中 ,validate里的required和CustomerValidation之间不能有空格,否则运行时报panic错误:panic: Undefined validation function ' CustomerValidation' on field 'Name'

例子4:自定义函数-直接注册函数1

不通过字段tag自定义函数,直接注册函数。

RegisterStructValidation

https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go

customer1.go

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main
 
import (
    "fmt"
 
    "github.com/go-playground/validator/v10"
)
 
type User struct {
    FirstName string `json:firstname`
    LastName string `json:lastname`
    Age uint8 `validate:"gte=0,lte=130"`
    Email string `validate:"required,email"`
    FavouriteColor string `validate:"hexcolor|rgb|rgba"`
}
 
var validate *validator.Validate
 
func main() {
    validate = validator.New()
 
    validate.RegisterStructValidation(UserStructLevelValidation, User{})
 
    user := &User{
        FirstName: "",
        LastName: "",
        Age: 30,
        Email: "TestFunc@126.com",
        FavouriteColor: "#000",
    }
 
    err := validate.Struct(user)
    if err != nil {
        fmt.Println(err)
    }
}
 
func UserStructLevelValidation(sl validator.StructLevel) {
    user := sl.Current().Interface().(User)
 
    if len(user.FirstName) == 0 && len(user.LastName) == 0 {
        sl.ReportError(user.FirstName, "FirstName", "firstname", "firstname", "")
        sl.ReportError(user.LastName, "LastName", "lastname", "lastname", "")
    }
}

运行输出:

$ go run customer1.go
Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'firstname' tag
Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'lastname' tag

例子5:自定义函数-直接注册函数2

RegisterCustomTypeFunc

https://github.com/go-playground/validator/blob/master/_examples/custom/main.go

validate.RegisterCustomTypeFunc:验证类型的自定义函数

customer2.go:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main
 
import (
    "database/sql"
    "database/sql/driver"
    "fmt"
    "reflect"
 
    "github.com/go-playground/validator/v10"
)
 
type DbBackedUser struct {
    Name sql.NullString `validate:"required"`
    Age sql.NullInt64 `validate:"required"`
}
 
var validate *validator.Validate
 
func main() {
    validate = validator.New()
 
    validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
 
    // build object for validation
    x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
 
    err := validate.Struct(x)
    if err != nil {
        fmt.Printf("Err(s):\n%+v\n", err)
    }
}
 
func ValidateValuer(field reflect.Value) interface{} {
    if valuer, ok := field.Interface().(driver.Valuer); ok {
        val, err := valuer.Value()
        if err == nil {
            return val
        }
        // handle the error how you want
    }
    return nil
}

运行输出:

$ go run customer.go
Err(s):
Key: 'DbBackedUser.Name' Error:Field validation for 'Name' failed on the 'required' tag
Key: 'DbBackedUser.Age' Error:Field validation for 'Age' failed on the 'required' tag

注意,这个函数
RegisterCustomTypeFunc,它上面有2行注释:

// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
//
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation

它是一个验证数据类型自定义函数,NOTE:这个方法不是线程安全的

五、参考

https://github.com/go-playground/validator/blob/master/README.mdhttps://github.com/go-playground/validator/tree/master/_examples

总结

到此这篇关于golang常用库:字段参数验证库-validator使用的文章就介绍到这了,更多相关golang字段参数验证库validator内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/jiujuan/p/13823864.html

延伸 · 阅读

精彩推荐
  • Golanggolang的httpserver优雅重启方法详解

    golang的httpserver优雅重启方法详解

    这篇文章主要给大家介绍了关于golang的httpserver优雅重启的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    helight2992020-05-14
  • GolangGolang中Bit数组的实现方式

    Golang中Bit数组的实现方式

    这篇文章主要介绍了Golang中Bit数组的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    天易独尊11682021-06-09
  • Golanggo日志系统logrus显示文件和行号的操作

    go日志系统logrus显示文件和行号的操作

    这篇文章主要介绍了go日志系统logrus显示文件和行号的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang json.Marshal 特殊html字符被转义的解决方法

    golang json.Marshal 特殊html字符被转义的解决方法

    今天小编就为大家分享一篇golang json.Marshal 特殊html字符被转义的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    李浩的life12792020-05-27
  • Golanggo语言制作端口扫描器

    go语言制作端口扫描器

    本文给大家分享的是使用go语言编写的TCP端口扫描器,可以选择IP范围,扫描的端口,以及多线程,有需要的小伙伴可以参考下。 ...

    脚本之家3642020-04-25
  • Golanggolang如何使用struct的tag属性的详细介绍

    golang如何使用struct的tag属性的详细介绍

    这篇文章主要介绍了golang如何使用struct的tag属性的详细介绍,从例子说起,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看...

    Go语言中文网11352020-05-21
  • GolangGolang通脉之数据类型详情

    Golang通脉之数据类型详情

    这篇文章主要介绍了Golang通脉之数据类型,在编程语言中标识符就是定义的具有某种意义的词,比如变量名、常量名、函数名等等,Go语言中标识符允许由...

    4272021-11-24
  • Golanggolang 通过ssh代理连接mysql的操作

    golang 通过ssh代理连接mysql的操作

    这篇文章主要介绍了golang 通过ssh代理连接mysql的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    a165861639710342021-03-08