golang 验证器库go-playground/validator实践

golang 验证器库go-playground/validator实践_第1张图片

当我们将一个接口值传递给一个 reflect.ValueOf 函数调用时,此调用返回的是代表着此接口值的动态值的一个 reflect.Value 值。我们必须通过间接的途径获得一个代表一个接口值的 reflect.Value 值。

reflect.Value 类型有很多方法(Package reflect - The Go Programming Language)。我们可以调用这些方法来观察和操纵一个 reflect.Value 属主值表示的 Go 值。这些方法中的有些适用于所有种类类型的值,有些只适用于一种或几种类型的值。

通过不合适的 reflect.Value 属主值调用某个方法将在运行时产生一个恐慌。请阅读 reflect 代码库中各个方法的文档来获取如何正确地使用这些方法。

一个 reflect.Value 值的 CanSet 方法将返回此 reflect.Value 值代表的 Go 值是否可以被修改(可以被赋值)。如果一个 Go 值可以被修改,则我们可以调用对应的 reflect.Value 值的 Set 方法来修改此 Go 值。注意:reflect.ValueOf 函数直接返回的 reflect.Value 值都是不可修改的。

反射不仅可以获取值的类型信息,还可以动态地获取或者设置变量的值。Go语言中使用 reflect.Value 获取和设置变量的值。

使用反射值对象包装任意值

Go语言中,使用 reflect.ValueOf() 函数获得值的反射值对象(reflect.Value)。书写格式如下:

value := reflect.ValueOf(rawValue)

reflect.ValueOf 返回 reflect.Value 类型,包含有 rawValue 的值信息。reflect.Value 与原值间可以通过值包装和值获取互相转化。reflect.Value 是一些反射操作的重要类型,如反射调用函数。

从反射值对象获取被包装的值

Go语言中可以通过 reflect.Value 重新获得原始值。

1) 从反射值对象(reflect.Value)中获取值的方法

可以通过下面几种方法从反射值对象 reflect.Value 中获取原值,如下表所示。
 

反射值获取原始值的方法
方法名 说  明
Interface() interface {} 将值以 interface{} 类型返回,可以通过类型断言转换为指定类型
Int() int64 将值以 int 类型返回,所有有符号整型均可以此方式返回
Uint() uint64 将值以 uint 类型返回,所有无符号整型均可以此方式返回
Float() float64 将值以双精度(float64)类型返回,所有浮点数(float32、float64)均可以此方式返回
Bool() bool 将值以 bool 类型返回
Bytes() []bytes 将值以字节数组 []bytes 类型返回
String() string 将值以字符串类型返回

2) 从反射值对象(reflect.Value)中获取值的例子

下面代码中,将整型变量中的值使用 reflect.Value 获取反射值对象(reflect.Value)。再通过 reflect.Value 的 Interface() 方法获得 interface{} 类型的原值,通过 int 类型对应的 reflect.Value 的 Int() 方法获得整型值。

 
  
  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. // 声明整型变量a并赋初值
  8. var a int = 1024
  9. // 获取变量a的反射值对象
  10. valueOfA := reflect.ValueOf(a)
  11. // 获取interface{}类型的值, 通过类型断言转换
  12. var getA int = valueOfA.Interface().(int)
  13. // 获取64位的值, 强制类型转换为int类型
  14. var getA2 int = int(valueOfA.Int())
  15. fmt.Println(getA, getA2)
  16. }

代码输出如下:

1024 1024

代码说明如下:

  • 第 11 行,声明一个变量,类型为 int,设置初值为 1024。
  • 第 14 行,获取变量 a 的反射值对象,类型为 reflect.Value,这个过程和 reflect.TypeOf() 类似。
  • 第 17 行,将 valueOfA 反射值对象以 interface{} 类型取出,通过类型断言转换为 int 类型并赋值给 getA。
  • 第 20 行,将 valueOfA 反射值对象通过 Int 方法,以 int64 类型取出,通过强制类型转换,转换为原本的 int 类型。

/****************************************************************************************/

一、概述

随着Golang在近年来的快速发展,很多开发者选择了它作为自己的首选编程语言。而在实际开发中,我们通常需要对数据进行一定的验证,以确保系统的稳定性和安全性。这时候,一个好用的字段验证器就显得尤为重要了。本文将详细介绍Golang工程组件之一的字段验证器validator的使用方法。

二、什么是validator

Validator是一个Golang的开源库,主要用于验证数据的合法性。它提供了丰富的验证规则,可以满足大部分场景下的需求。同时,Validator还支持自定义验证规则,你可以根据具体需求添加自己的验证规则。Validator已经被广泛应用于各种Golang项目中。

三、Validator的安装

在使用Validator之前,需要先安装它。在Golang中,可以使用go get命令轻松安装Validator:

go get -u github.com/go-playground/validator/v10
四、使用Validator

4.1 基本用法

Validator的使用非常简单,只需要引入包并创建一个新的验证器对象即可:

import "github.com/go-playground/validator/v10"
 
validate := validator.New()
接下来,就可以使用验证器对象的ValidateStruct方法验证结构体是否合法:

type User struct {
    Name  string `validate:"required"`
    Email string `validate:"required,email"`
}
 
user := &User{Name: "test", Email: "[email protected]"}
 
err := validate.Struct(user)
if err != nil {
    // 验证失败
}
在上面的例子中,我们定义了一个名为User的结构体,并为它的Name和Email字段设置了验证规则。其中,validate:"required"表示该字段必须存在且不能为空;validate:"email"表示该字段必须是一个合法的邮箱地址。最后,我们使用验证器对象的Struct方法进行验证。

如果验证失败,会返回错误信息。否则,表示数据合法。

4.2 自定义验证规则

有时候,Validator提供的默认验证规则并不能满足我们的需求。这时候,我们就需要自定义验证规则了。Validator支持自定义验证规则,只需要实现validator.Func接口即可:

func myFunc(fl validator.FieldLevel) bool {
    // 验证逻辑
    return true
}
 
validate.RegisterValidation("my_rule", myFunc)
 
type User struct {
    Age int `validate:"my_rule"`
}
 
user := &User{Age: 18}
 
err := validate.Struct(user)
if err != nil {
    // 验证失败
}
在上面的例子中,我们定义了一个名为myFunc的函数作为自定义验证规则。这个函数需要实现validator.FieldLevel接口,接收一个参数fl,它包含了字段的相关信息,如字段名、值等。在函数中,我们可以编写自己的验证逻辑,并返回一个bool值表示验证结果。

接着,我们使用验证器对象的RegisterValidation方法注册我们定义的验证规则。"my_rule"是我们给这个规则起的名字。

最后,我们定义了一个User结构体,并为它的Age字段设置了我们自定义的验证规则。最终,我们在验证器对象上调用Struct方法进行验证即可。

4.3 错误处理

当数据验证失败时,Validator会返回一个ValidationError类型的错误。其中,Errors()方法可以返回所有验证失败的字段及其相关信息:

type User struct {
    Name  string `validate:"required"`
    Email string `validate:"required,email"`
}
 
user := &User{Name: "test", Email: "test"}
 
if err := validate.Struct(user); err != nil {
    for _, err := range err.(validator.ValidationErrors) {
        // 输出错误信息
        fmt.Println(err.Field(), err.Tag())
    }
}
在上面的例子中,数据验证失败了,我们使用for循环遍历所有的错误信息,并输出它们的字段名和相关规则(Tag)。

五、总结

本文简单介绍了Golang工程组件之一的字段验证器Validator的基本用法、自定义验证规则以及错误处理。Validator提供了丰富的验证规则,能够满足大部分场景下的需求,并支持自定义验证规则。同时,Validator还能够输出详细的错误信息,便于我们快速定位问题并解决。无疑,Validator是一个非常实用的工具,也是Golang开发过程中不可或缺的一部分。

/***************************************************************************************/

添加依赖
go get github.com/go-playground/validator
代码
package main
 
import (
    "fmt"
    "github.com/go-playground/validator"
)
 
var validate *validator.Validate //定义
 
type User struct {
    Name  string `validate:"required"` //非空
    Age   uint8  `validate:"gte=0,lte=130"` //  0<=Age<=130
    Email string `validate:"required,email"` //非空,email格式
    //dive关键字代表 进入到嵌套结构体进行判断
    Address []*Address `validate:"dive"` //  可以拥有多个地址
}
type Address struct {
    Province string `validate:"required"` //非空
    City     string `validate:"required"` //非空
    Phone    string `validate:"numeric,len=11"` //数字类型,长度为11
}
 
func main() {
    validate = validator.New() //初始化(赋值)
    validateStruct()           //结构体校验
    validateVariable()         //变量校验
}
func validateStruct() {
    address := Address{
        Province: "重庆",
        City:     "重庆",
        Phone:    "13366663333x",
    }
    user := User{
        Name:  "江洲",
        Age:   23,
        Email: "[email protected]",
        Address: []*Address{&address},
    }
    err := validate.Struct(user)
    if err != nil {
        //断言为:validator.ValidationErrors,类型为:[]FieldError
        for _, e := range err.(validator.ValidationErrors) {
            fmt.Println("Namespace:", e.Namespace())
            fmt.Println("Field:", e.Field())
            fmt.Println("StructNamespace:", e.StructNamespace())
            fmt.Println("StructField:", e.StructField())
            fmt.Println("Tag:", e.Tag())
            fmt.Println("ActualTag:", e.ActualTag())
            fmt.Println("Kind:", e.Kind())
            fmt.Println("Type:", e.Type())
            fmt.Println("Value:", e.Value())
            fmt.Println("Param:", e.Param())
            fmt.Println()
        }
 
        fmt.Println("结构体输入数据类型错误!")
        return
    } else {
        fmt.Println("结构体校验通过")
    }
}
//变量校验
func validateVariable() {
    myEmail := "[email protected]" //邮箱地址:[email protected]
    err := validate.Var(myEmail, "required,email")
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("变量校验通过!")
    }
}

 

你可能感兴趣的:(golang)