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

news/2024/11/6 9:50:35/

当我们将一个接口值传递给一个 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: "test@test.com"}
 
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: "jz@163.com",
        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 := "123@qq.com" //邮箱地址:xx@xx.com
    err := validate.Var(myEmail, "required,email")
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("变量校验通过!")
    }
}

 


http://www.ppmy.cn/news/971335.html

相关文章

某网站瑞数5代环境检测JS逆向分析

1. 写在前面 逆向技术确实很有挑战&#xff0c;经常有看到各种爬虫与逆向群里面五花八门的奇技Y巧。爬虫领域里面就需要更多的分享&#xff0c;才能够成就更好的自己。本期要说的这个网站用到的加密技术相对比较难&#xff01;我在找案例的时候同时也在学习其他大佬的思路与技巧…

有奖征文丨AIGC + Cocos 社区征稿全面开启

AIGC游戏开发&#xff0c;已经发展到何种恐怖地步&#xff1f; 晓衡做了一个视频&#xff0c;介绍了社区大佬&#xff0c;也是晓衡的朋友、老师&#xff08;之一&#xff09;——孙二喵&#xff0c;最近的AIGC研究&#xff0c;真的是让人有种瑟瑟发抖的感觉&#xff01; 视频中…

2023年上半年部分团队的总结

把各个环节连起来 从我加入 CSDN 后不久&#xff0c;我就开始公开地总结我们的工作&#xff0c;我分管的团队留下了不少的总结和思考&#xff1a; 这是 2022 年下半年的汇报 这是 2022 年上半年的汇报 这是 2021 年年底的汇报 经过这些思考改进迭代的团队&#xff0c;是不是…

GitHub Copilot Labs 体验「收手吧,外面全是 ChatGPT」

本文正在参加 ✍&#x1f3fb; 技术视角深入 ChatGPT 征文活动 相信大家或多或少都体验过了 ChatGPT&#xff0c;或者更进一步&#xff0c;在 IDE 中也装上了对应的插件 不过真正在 coding 中用上的频率有多高呢&#xff1f;可能大多数人都只是尝个鲜然后就忘了&#xff0c;至…

【JAVA】云HIS系统功能菜单知识(二)

随着医疗信息化和互联网技术的不断发展&#xff0c;云HIS在大数据管理和应用的优势日益凸显。对于医疗机构而言&#xff0c;云HIS平台可以帮助其实现更高效的医疗服务管理&#xff0c;并提高医疗服务的整体水平和效率。 一、系统管理 1.医院信息 基本信息、法人代表、主要负责…

Unity小游戏——无线滚动的背景的改良

在上文介绍的算法中&#xff0c;背景只在每次调用Update&#xff08;&#xff09;时移动一次。这样一来&#xff0c;如果武士移动的距离很长&#xff0c;即速度很快&#xff0c;就可能出现背景和角色移动不协调的情况.虽然我们这个游戏中不会打到那样快的移动速度&#xff0c;但…

Leetcode 3. 无重复字符的最长子串

题目描述 题目链接&#xff1a;https://leetcode.cn/problems/longest-substring-without-repeating-characters/ 思路 首先想到了双指针控制窗口&#xff0c;无重复的字符又想到Map存储。 遍历一遍字符串初始start指向0&#xff0c;end指向当前遍历字符的下标Map存储每个字…

(笔记)插入排序

插入排序 插入排序是一种简单且常见的排序算法&#xff0c;它通过重复将一个元素插入到已经排好序的一组元素中&#xff0c;来达到排序的目的。在插入排序算法中&#xff0c;将待排序序列分为已排序和未排序两个部分。初始时&#xff0c;已排序部分只包含一个记录&#xff0c;…