Spring 中的验证、数据绑定和类型转换
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,
15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生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 属性。下面是Genre 和 Gender 的枚举类
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 中的验证、数据绑定和类型转换
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...
Github----提交人不是自己
账号用户名都设置对的,但是提交人不是自己 解决 发现是用户名和账号都夹了"号导致 git config --global user.name "Your Name" git config --global user.email "your.emailexample.com"不用引号 git config --global user.name Your Name git …...
常用工具软件
前言 之前汇总过一篇嵌入式开发工具,但是掺杂了一些更偏向于日常使用的软件工具,这里单独提出来分享,都是自己在用的。 1.文件对比工具 BeyondCompare 文件对比利器,添加右键快捷键后。选中两个文件,右键可以直接进…...
Oracle报错ORA-01653: 表xx无法通过 8192在表空间中扩展
向Oracle 19g数据库中批量插入数据,当插入近2亿条数据后,报出如下错误: ORA-01653: 表xx无法通过 8192 (在表空间 xx_data 中) 扩展 查看表空间,发现表空间大小已达到32G,表空间无法进行自动扩展了。(初始…...
【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. 点击文档列表中的【打印】按钮,获取后台生成的PDF的url,弹窗进行预览: 2. 点击【打印】按钮,进行打印预览和打印: 二. 需求实现 首先后台给的是word文档,研究了一圈后发现暂时无法实现&…...
CSS学习记录07
CSS轮廓 轮廓是在元素周围绘制的一条线,在边框之外,以凸显元素。 CSS拥有如下轮廓属性: outline-styleoutline-coloroutline-widthoutline-offsetoutline 注意:轮廓与边框不同。不同之处在于:轮廓是在元素边框之外…...
喆塔科技携手国家级创新中心,共建高性能集成电路数智化未来
集创新之力成数智之塔 近日,喆塔科技与国家集成电路创新中心携手共建“高性能集成电路数智化联合工程中心”并举行签约揭牌仪式。出席此次活动的领导嘉宾包含:上海市经济和信息化委员会、上海市集成电路行业协会、复旦大学微电子学院、国家集成电路创新中…...
基于单片机的汽车雨刷器装置
摘要 下雨天时道路十分模糊,能见度非常低,司机分散注意力去手动打开雨刷器开关会非常危险。据统计,全世界雨天行车的车祸事故有7%是因为司机手动打开雨刷分心导致的。为了减小司机因为手动打开雨刷发生车祸的概率,所以…...
013-SpringBoot 定义优雅的全局异常处理方式
SpringBoot 定义优雅的全局异常处理方式 一、概述二、定义全局异常接口三、定义全局异常枚举四、定义全局基础异常五、定义全局基础业务异常六、定义全局返回七、定义全局返回工厂八、全局异常处理九、实体类十、Controller十一、效果展示一、概述 在日常项目开发中,异常是常…...
nginx 网页正常访问 F5 404
前端打包部署完,无论pc-web或h5-wap,访问正常,一刷新就会404。 解决方案: 在项目的nginx子配置文件中,加上以下代码 try_files $uri $uri/ /index.html;...
Idea Spring Initializr没有 Java 8选项解决办法
问题描述 在使用IDEA中的Spring Initializr创建新项目时,Java 版本近可选择Java17,21 。不能选择Java8;SpringBoot 版本也只有 3.x 问题原因 Spring 官方( https://start.spring.io/)不再提供旧版本的初始化配置 解决方案 方案 1 使用阿里…...
【Leetcode Top 100】104. 二叉树的最大深度
问题背景 给定一个二叉树 r o o t root root,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 数据约束 树中节点的数量在 [ 0 , 1 0 4 ] [0, 10 ^ 4] [0,104] 区间内。 − 100 ≤ N o d e . v a l ≤ 100 -100 \le Nod…...
C#实现一个HttpClient集成通义千问-开发前准备
集成一个在线大模型(如通义千问),来开发一个chat对话类型的ai应用,我需要先了解OpenAI的API文档,请求和返回的参数都是以相关接口文档的标准进行的 相关文档 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是很复杂的,若依简化了了此操作apach poi的上传速率和下载速率都是没有优化的,依赖于文件大小的限制在此前提下,如果没法满足客户的需求(超大型文件的上传&am…...
去除背景 学习笔记
目录 rembg rembg 安装: 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 -- 隔离级别简介(原理篇)
隔离级别 别记题记隔离级别后记系列文章 别记 烧香拜佛要是有用,还需要我们来过吗…从个人情感角度,巴沙尔阿萨德 辜负了东大对他的期望他可是从正门踏进了灵隐寺 俄乌战争即将进入第三年(此时202412)此时的加沙正成为以色列建国…...
机器学习(4)Kmeans算法
1、简述聚类分析的重要性及其在机器学习中的应用 聚类分析,作为机器学习领域中的一种无监督学习方法,在数据探索与知识发现过程中扮演着举足轻重的角色。它能够在没有先验知识或标签信息的情况下,通过挖掘数据中的内在结构和规律…...
Oracle之表空间迁移
问题背景:一个数据表随着时间的累积,导致所在表空间占用很高,里面历史数据可以清除,保留近2个月数据即可 首先通过delete删除了2个月以前的数据。 按网上的教程进行空间压缩,以下sql在表所在用户执行: -- 允许表重新…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
Qt Quick Dialogs模块功能及架构
Qt Quick Dialogs 是 Qt Quick 的一个附加模块,提供了一套用于创建和使用系统对话框的 QML 类型。在 Qt 6.0 中,这个模块经过了重构和增强。 一、主要功能和特点 1. 对话框类型 Qt Quick Dialogs 在 Qt 6.0 中提供了以下标准对话框类型: …...
