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

news2024/12/25 1:36:06

当我们将一个接口值传递给一个 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.coloradmin.cn/o/777514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【字符流】编码解码问题

字符流中编码解码问题 字符流抽象基类&#xff1a; Reader&#xff1a;字符输入流的抽象类Writer&#xff1a;字符输出流的抽象类 字符流中和编码和解码问题相关的两个类&#xff1a; InputStreamReader&#xff1a;是从字节流到字符流的桥梁&#xff0c;它读取字节并使用指…

Jupyter Notebook 后台启动

进入用户目录 cd 指定目录 激活环境 conda activate 环境名 Note&#xff1a; 注意&#xff1a;无法导入依赖包&#xff0c;查看是否激活对应环境。 后台启动 jupyter notebook&#xff0c;或者服务器上启动 可通过浏览器访问 nohup jupyter notebook --allow-root& …

C语言——通讯录的实现

前面的文章介绍了C语言中的 指针、自定义类型等模块&#xff0c;这篇文章将通过编写实现通讯录的代码对这些模块进行应用和进一步加深理解&#xff1a; 目录 1. 通讯录主要功能设计&#xff1a; 2. 通讯录的实现——主页面&#xff1a; 3. 通讯录的实现——保存个人信息&am…

CS 144 Lab Three-- the TCP sender

CS 144 Lab Three -- the TCP sender TCPSender 功能如何检测丢包TCPSender 要求TCPSender 状态转换图TCPSender 实现测试 对应课程视频: 【计算机网络】 斯坦福大学CS144课程 Lab Three 对应的PDF: Lab Checkpoint 3: the TCP sender TCPSender 功能 TCP Sender 负责将数据以…

27 Deep Belief Network

文章目录 27 Deep Belief Network——深度信念网络27.1 DBN是什么&#xff1f;27.2 为什么要使用DBN27.2.1 DBN的思想是怎么来的&#xff1f;27.2.2 RBM的叠加可以提高ELBO 27.3 训练方式 27 Deep Belief Network——深度信念网络 27.1 DBN是什么&#xff1f; DBN(Deep Belie…

【机器学习】分类算法 - KNN算法(K-近邻算法)KNeighborsClassifier

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 K-近邻算法 1、什么是K-近邻算法&#xff1f;2、K-近邻算法API3、…

FastDFS与Springboot集成

&#x1f680; FastDFS与Springboot集成 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风…

139、仿真-基于51单片机一氧化碳(CO)气体检测仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、设计功能 二、Proteus仿真图​编辑 三、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&#xff1…

【K8S系列】深入解析k8s网络插件—Calico

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 Kubernetes (k8s) 是一个容器编…

视频理解多模态大模型(大模型基础、微调、视频理解基础)

转眼就要博0了&#xff0c;导师开始让我看视频理解多模态方向的内容&#xff0c;重新一遍打基础吧&#xff0c;从Python&#xff0c;到NLP&#xff0c;再到视频理解&#xff0c;最后加上凸优化&#xff0c;一步一步来&#xff0c;疯学一个暑假。写这个博客作为我的笔记以及好文…

代码随想录算法训练营第55天|392 115

392 双指针法很简单 class Solution { public:bool isSubsequence(string s, string t) {int i0;for (int j0; j<t.size() && i<s.size(); j) {if (t[j]s[i]) {i;}}return is.size();} }; 用动态规划来写的话 逻辑其实跟1143 1035是一样的 最后返回看dp[s.size…

Vue element el-input输入框 实现 ’空格+enter’组合键:换行,enter:发送,使用keydown和keyup键盘事件来实现

需求 输入框 &#xff0c;输入内容后 &#xff0c;按enter空格键 换行&#xff0c;按enter键 发送调取接口 思路 jquery的也分为三个过程&#xff0c;在事件名称上有所不同 1、某个键盘的键被松开&#xff1a;keyup 2、某个键被按下&#xff1a;keydown 3、某个键盘的键被按…

基于查找表(lookup table,LUT)方法反演植被参数

LUT指显示查找表&#xff08;Look-Up-Table)&#xff0c;本质上就是一个RAM。它把数据事先写入RAM后&#xff0c;每当输入一个信号就等于输入一个地址进行查表&#xff0c;找出地址对应的内容&#xff0c;然后输出。 LUT的应用范围比较广泛&#xff0c;例如&#xff1a;LUT(Lo…

机器学习:Self-supervised Learning for Speech and image

review : self-supervised learning for text Self-supervised learning for speech 使用Speech版本的bert能比较好的作用于语音任务上&#xff0c;如果没有self-supervised的话&#xff0c;别的模型可能需要上万小时的数据。 Superb ytb课程&#xff1a;MpsVE60iRLM工具&…

vulnhub打靶--lampiao

目录 vulnhub--lampiao1.扫描主机端口&#xff0c;发现1898端口部署web2.打开robots.txt发现CHANGELOG.txt文件3.发现drupal更新日志&#xff0c;drupal这个版本有公开exp。利用msf打下4.执行uname -a 或者上传漏洞suggest脚本&#xff0c;可以发现有脏牛提权5.上传脚本到目标&…

2023年7月19日,锁升级,网络编程

锁升级 锁的四种状态&#xff1a;无锁、偏向锁、轻量级锁、重量级锁&#xff08;JDK1.6&#xff09; 无锁&#xff1a;操作数据时不会上锁 偏向锁&#xff1a;会偏向于第一个访问锁的线程&#xff0c; 如果在运行过程中&#xff0c;只有一个线程访问加锁的资源&#xff0c;不存…

JavaWeb+Vue分离项目实现增删改查

文章目录 前言数据库后端代码util 代码listener 代码filter 代码po 代码dao 层增删改查代码service 层增删改查代码controller 层增删改查代码 前端代码查询操作删除功能增加功能修改方法路由传参修改会话存储修改 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&…

Java037——多线程

当涉及到计算机操作系统中的并发执行时&#xff0c;进程和线程是两个核心概念。 一、程序(program) 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一 段静态的代码&#xff0c;静态对象。 二、进程&#xff08;Process&#xff09; 进程&#xff0…

MD5数据加密方法

什么场景需要使用数据加密呢&#xff1f;比如秘密数据传输、用户密码加密存储等等 数据传输可使用密钥对的方式进行加密解密&#xff0c;使用签名方式验证数据是否可靠&#xff0c;而密码加密存储可使用MD5等一些算法对数据进行单向加密 一、MD5单向加密 1、百度说法&#x…

【基础统计学】带重叠差分置信区间的检验

一、说明 对于统计模式识别&#xff0c;需要从基本的检验入手进行学习掌握&#xff0c;本篇是对统计中存在问题的探讨&#xff1a;如果两个分布有重叠该怎么做。具体的统计学原理&#xff0c;将在本人专栏中系统阐述。 二、几个重要概念 2.1 什么是假设检验 假设检验是一种统计…