当前位置: 首页 > news >正文

Spring 中的验证、数据绑定和类型转换

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

Spring 中的验证、数据绑定和类型转换

验证在任何时候都非常关键。考虑将数据验证作为业务逻辑开发有利也有弊,Spring 认为,验证不应该只在Web 端进行处理,在服务端也要进行相应的处理,可以防止脏数据存入数据库中,从而避免为运维同学和测试同学造成更大的困扰,因为数据造成的bug会更加难以发现,而且开发人员关注点也不会放在数据本身的问题上,所以做服务端的验证也是非常有必要的。
考虑到上面这些问题,Spring 提供了两种主要类型的验证:

  • 一个是实现Validator 接口来创建自定义验证器,用于服务端数据校验。
  • 一种是通过Spring 对 Bean Validation 支持实现的。

通过使用 Spring Validator 接口进行验证

Spring 提供 Validator 接口用于验证对象。Validator 接口通过使用 Errors 对象来工作,以便在验证时,验证器可以向 Errors 对象报告验证失败。下面是一个简单的 对象示例

public class Person {private String name;private int age;// get and set...
}

下面一个例子为 Person 对象提供了一种验证方式,通过实现了 org.springframework.validation.Validator 接口 的两个方法:

  • supports(Class): 表示此 Validator 是否能够验证提供的类的实例
  • validate(Object, org.springframework.validation.Errors): 验证给定的对象,如果验证错误,则注册具有给定 Errors 对象。

实现一个 Validator 非常简单,而且Spring 也提供了 ValidationUtils 工具类帮助进行验证。下面是一个验证 Person 对象的例子:

@Component
public class PersonValidator implements Validator {// 此 Validator 只验证 Person 实例public boolean supports(Class clazz) {return Person.class.equals(clazz);}public void validate(Object obj, Errors e) {ValidationUtils.rejectIfEmpty(e, "name", "name.empty");}
}

上面代码示例中的静态方法 rejectIfEmpty() 方法用于拒绝name属性,当name 属性是 null 或者是 空串的时候。查看 ValidationUtils 文档关于它能够提供的功能。

然后再来编写配置类 AppConfig:

@Configuration
@ComponentScan("com.spring.validation")
public class AppConfig {}

使用 @Configuration 注解声明此类为配置类(更多 @Configuration 的用法,请参照 原创 | 我被面试官给虐懵了,竟然是因为我不懂Spring中的@Configuration )

配置@ComponentScan 注解用于自动装配,默认是使用 basePackages 扫描指定包,字符串表示。

然后对上面的程序进行验证

public class SpringValidationApplicationTests {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);Person person = new Person();person.setAge(18);person.setName(null);PersonValidator personValidator = applicationContext.getBean("personValidator", PersonValidator.class);BeanPropertyBindingResult result = new BeanPropertyBindingResult(person,"cxuan");ValidationUtils.invokeValidator(personValidator,person,result);List<ObjectError> allErrors = result.getAllErrors();allErrors.forEach(e-> System.out.println(e.getCode()));}
}

因为是基于注解的配置,所以使用 AnnotationConfigApplicationContext上下文启动类,把配置类 AppConfig 当作参数,然后构建一个Person 类,为了测试验证有效性,把 name 设置为 null,然后通过上下问的 getBean 方法获得 personValidator 的实例,通过使用 BeanPropertyBindingResult 把 person 绑定为 cxuan 的名字,然后使用 ValidationUtils 工具类进行验证,最后把验证的结果进行检查。

上面程序经验证后的结果如下:

org.springframework.validation.ValidationUtils - Invoking validator [com.spring.validation.PersonValidator@37918c79]
DEBUG org.springframework.validation.ValidationUtils - Validator found 1 errors
name.empty

使用 Bean Validation 进行验证

从 Spring4 开始,就已经实现对 JSR-349 Bean Validation 的全面支持。Bean Validation API 在 javax.validation.constraints 包中以 Java 注解(例如 @NonNull) 形式定义了一组可用域对象的约束。

通过使用 Bean Validation API ,可以避免耦合到特定的验证服务提供程序。Spring 对 Bean Validation API 提供了无缝支持,主要使用一些注解进行验证,下面一起来看一下

定义对象属性上的验证约束

首先,将验证约束应用于域对象属性。使用maven 配置需要引入对应的依赖

<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>1.1.0.Final</version>
</dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.2.4.Final</version>
</dependency>

之后定义了一些实体类,使用 javax.validation.constraints 包中的注释进行标注

public class Singer {@NotNull@Size(min = 2,max = 60)private String firstName;private String lastName;@NotNullprivate Genre genre;private Gender gender;get and set...
}

对于 firstName ,定义了两个约束,第一个约束由 @NotNull 进行控制,它表示该值不能为空。此外,@Size注解控制着 firstName 的长度在 2 - 60 之间。@NotNull 还用于 genre 属性。下面是GenreGender 的枚举类

public enum Genre {POP("P"),JAZZ("J"),BLUES("B"),COUNTRY("C");private String code;private Genre(String code){this.code = code;}public String toString(){return this.code;}
}public enum Gender {MALE("M"),FEMALE("F");private String code;Gender(String code){this.code = code;}@Overridepublic String toString() {return this.code;}
}

Genre 表示歌手所属的音乐类型,而 Gender 与音乐事业不相关,所以可以为空

在 Spring 中配置 Bean Validation 支持

为了在 Spring 的 ApplicationContext 中配置对 Bean Validation API 的支持,可以在Spring 的配置中定义一个 LocalValidatorFactoryBean 的 bean如下

@Configuration
@ComponentScan("com.spring.validation")
public class ValidationConfig {@BeanLocalValidatorFactoryBean validatorFactoryBean(){return new LocalValidatorFactoryBean();}
}

声明一个 LocalValidatorFactoryBean 的 bean 是必须的。默认情况下,Spring 会在类路径下搜索 Hibernate Validator库,验证它是否存在。

下面我们编写一个为 Singer 类提供验证服务的服务类

@Service
public class SingerValidationService {@Autowiredprivate Validator validator;public Set<ConstraintViolation<Singer>> validateSinger(Singer singer){return validator.validate(singer);}
}

注入一个 javax.validation.Validator 实例(请注意与 Spring 提供的 Validator 接口不同)。一旦定义了 LocalValidatorFactoryBean ,就可以在应用程序中的任意位置创建 Validator 的句柄。要在 POJO 上进行验证,需要调用 validator.validate 方法,验证结果以 ConstraintViolation<T> 接口的集合形式返回。下面是上面例子程序的验证

public class SpringBeanValidationTest {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValidationConfig.class);SingerValidationService singerBean = applicationContext.getBean(SingerValidationService.class);Singer singer = new Singer();singer.setFirstName("c");singer.setLastName("xuan");singer.setGenre(null);singer.setGender(null);validateSinger(singer,singerBean);applicationContext.close();}private static void validateSinger(Singer singer,SingerValidationService singerValidationService){Set<ConstraintViolation<Singer>> violationSet = singerValidationService.validateSinger(singer);listViolations(violationSet);}private static void listViolations(Set<ConstraintViolation<Singer>> violations){System.out.println("violations.size() = " + violations.size());for(ConstraintViolation<Singer> violation : violations){System.out.println("Validation error for property : " + violation.getPropertyPath());System.out.println("with value : " + violation.getInvalidValue());System.out.println("with error message : " + violation.getMessage());}}
}

上述代码构建了一个 Singer 类进行验证,因为 firstname 属性的要求是长度介于 2 - 60 之间并且不能为null,所以这里只用了一个字符验证,genre 属性不能为null,最核心的验证方法就是 singerValidationService.validateSinger(singer).方法,它会调用

public Set<ConstraintViolation<Singer>> validateSinger(Singer singer){return validator.validate(singer);
}

进行验证,验证的结果返回的是 ConstraintViolation<Singler> 类型,然后把对应的错误信息输出,上面的错误信息是

violations.size() = 2
Validation error for property : firstName
with value : c
with error message : 个数必须在2和60之间
Validation error for property : genre
with value : null
with error message : 不能为null

可以打印出两个错误,并输出错误的属性、值以及错误信息。

相关文章:

Spring 中的验证、数据绑定和类型转换

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…...

Github----提交人不是自己

账号用户名都设置对的,但是提交人不是自己 解决 发现是用户名和账号都夹了"号导致 git config --global user.name "Your Name" git config --global user.email "your.emailexample.com"不用引号 git config --global user.name Your Name git …...

常用工具软件

前言 之前汇总过一篇嵌入式开发工具&#xff0c;但是掺杂了一些更偏向于日常使用的软件工具&#xff0c;这里单独提出来分享&#xff0c;都是自己在用的。 1.文件对比工具 BeyondCompare 文件对比利器&#xff0c;添加右键快捷键后。选中两个文件&#xff0c;右键可以直接进…...

Oracle报错ORA-01653: 表xx无法通过 8192在表空间中扩展

向Oracle 19g数据库中批量插入数据&#xff0c;当插入近2亿条数据后&#xff0c;报出如下错误&#xff1a; ORA-01653: 表xx无法通过 8192 (在表空间 xx_data 中) 扩展 查看表空间&#xff0c;发现表空间大小已达到32G&#xff0c;表空间无法进行自动扩展了。&#xff08;初始…...

【C语言】库函数常见的陷阱与缺陷(3):内存分配函数

目录 一、malloc 函数 1.1. 功能与常见用法 1.2. 陷阱与缺陷 1.3. 安全使用建议 1.4. 安全替代和代码示例 二、calloc 函数 2.1. 功能与常见用法 2.2. 陷阱与缺陷 2.3. 安全使用建议 2.4. 安全替代和代码示例 三、realloc 函数 3.1. 功能与常见用法 3.2. 陷阱与缺…...

Vue前端实现预览并打印PDF文档

一. 需求 1. 点击文档列表中的【打印】按钮&#xff0c;获取后台生成的PDF的url&#xff0c;弹窗进行预览&#xff1a; 2. 点击【打印】按钮&#xff0c;进行打印预览和打印&#xff1a; 二. 需求实现 首先后台给的是word文档&#xff0c;研究了一圈后发现暂时无法实现&…...

CSS学习记录07

CSS轮廓 轮廓是在元素周围绘制的一条线&#xff0c;在边框之外&#xff0c;以凸显元素。 CSS拥有如下轮廓属性&#xff1a; outline-styleoutline-coloroutline-widthoutline-offsetoutline 注意&#xff1a;轮廓与边框不同。不同之处在于&#xff1a;轮廓是在元素边框之外…...

喆塔科技携手国家级创新中心,共建高性能集成电路数智化未来

集创新之力成数智之塔 近日&#xff0c;喆塔科技与国家集成电路创新中心携手共建“高性能集成电路数智化联合工程中心”并举行签约揭牌仪式。出席此次活动的领导嘉宾包含&#xff1a;上海市经济和信息化委员会、上海市集成电路行业协会、复旦大学微电子学院、国家集成电路创新中…...

基于单片机的汽车雨刷器装置

摘要 下雨天时道路十分模糊&#xff0c;能见度非常低&#xff0c;司机分散注意力去手动打开雨刷器开关会非常危险。据统计&#xff0c;全世界雨天行车的车祸事故有7&#xff05;是因为司机手动打开雨刷分心导致的。为了减小司机因为手动打开雨刷发生车祸的概率&#xff0c;所以…...

013-SpringBoot 定义优雅的全局异常处理方式

SpringBoot 定义优雅的全局异常处理方式 一、概述二、定义全局异常接口三、定义全局异常枚举四、定义全局基础异常五、定义全局基础业务异常六、定义全局返回七、定义全局返回工厂八、全局异常处理九、实体类十、Controller十一、效果展示一、概述 在日常项目开发中,异常是常…...

nginx 网页正常访问 F5 404

前端打包部署完&#xff0c;无论pc-web或h5-wap&#xff0c;访问正常&#xff0c;一刷新就会404。 解决方案&#xff1a; 在项目的nginx子配置文件中&#xff0c;加上以下代码 try_files $uri $uri/ /index.html;...

Idea Spring Initializr没有 Java 8选项解决办法

问题描述 在使用IDEA中的Spring Initializr创建新项目时&#xff0c;Java 版本近可选择Java17,21 。不能选择Java8;SpringBoot 版本也只有 3.x 问题原因 Spring 官方&#xff08; https://start.spring.io/&#xff09;不再提供旧版本的初始化配置 解决方案 方案 1 使用阿里…...

【Leetcode Top 100】104. 二叉树的最大深度

问题背景 给定一个二叉树 r o o t root root&#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 数据约束 树中节点的数量在 [ 0 , 1 0 4 ] [0, 10 ^ 4] [0,104] 区间内。 − 100 ≤ N o d e . v a l ≤ 100 -100 \le Nod…...

C#实现一个HttpClient集成通义千问-开发前准备

集成一个在线大模型&#xff08;如通义千问&#xff09;&#xff0c;来开发一个chat对话类型的ai应用&#xff0c;我需要先了解OpenAI的API文档&#xff0c;请求和返回的参数都是以相关接口文档的标准进行的 相关文档 OpenAI API文档 https://platform.openai.com/docs/api-…...

使用ssh免密登录实现自动化部署rsync+nfs+lsync(脚本)

单机一键部署sshrsyncnfslsync 执行准备 主机信息 主机角色外网IP内网IP主机名nfs、lsync10.0.0.31176.16.1.31nfs客户端10.0.0.7176.16.1.7web01rsync、nfs10.0.0.41172.16.1.41backup 秘钥信息 #web01可以免密连接nfs和backup [rootweb01 ~]# ssh-keygen [rootweb01 ~]#…...

若依集成更好用的easyexcel

背景 若依使用的是apach poi并在此基础上进行封装apach poi的原生的api是很复杂的&#xff0c;若依简化了了此操作apach poi的上传速率和下载速率都是没有优化的&#xff0c;依赖于文件大小的限制在此前提下&#xff0c;如果没法满足客户的需求&#xff08;超大型文件的上传&am…...

去除背景 学习笔记

目录 rembg rembg 安装&#xff1a; pip install rembg import os from glob import glob from rembg import remove from argparse import ArgumentParser from PIL import Image if __name__ __main__:parser ArgumentParser()parser.add_argument(--path, typestr, re…...

我们来学mysql -- 隔离级别简介(原理篇)

隔离级别 别记题记隔离级别后记系列文章 别记 烧香拜佛要是有用&#xff0c;还需要我们来过吗…从个人情感角度&#xff0c;巴沙尔阿萨德 辜负了东大对他的期望他可是从正门踏进了灵隐寺 俄乌战争即将进入第三年&#xff08;此时202412&#xff09;此时的加沙正成为以色列建国…...

机器学习(4)Kmeans算法

1、简述聚类分析的重要性及其在机器学习中的应用   聚类分析&#xff0c;作为机器学习领域中的一种无监督学习方法&#xff0c;在数据探索与知识发现过程中扮演着举足轻重的角色。它能够在没有先验知识或标签信息的情况下&#xff0c;通过挖掘数据中的内在结构和规律&#xf…...

Oracle之表空间迁移

问题背景&#xff1a;一个数据表随着时间的累积&#xff0c;导致所在表空间占用很高&#xff0c;里面历史数据可以清除&#xff0c;保留近2个月数据即可 首先通过delete删除了2个月以前的数据。 按网上的教程进行空间压缩&#xff0c;以下sql在表所在用户执行: -- 允许表重新…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...