1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知(下)

简介: 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知(下)

JSR349


该规范是2013年完成的,伴随着Java EE 7一起发布,它就是我们比较熟悉的Bean Validation 1.1。


<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>


相较于1.0版本,它主要的改进/优化有如下几点:


  1. 标准化了Java平台的约束定义、描述、和验证
  2. 支持方法级验证(入参或返回值的验证)
  3. Bean验证组件的依赖注入
  4. 与上下文和DI依赖注入集成
  5. 使用EL表达式的错误消息插值,让错误消息动态化起来(强依赖于ElManager)
  6. 跨参数验证。比如密码和验证密码必须相同


小贴士:注解个数上,相较于1.0版本并没新增~


它的官方参考实现如下:


image.png


可以看到,Java Bean Validation 1.1版本实现对应的是Hibernate Validator 5.x(1.0版本对应的是4.x)

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.3.Final</version>
</dependency>




当你导入了hibernate-validator后,无需再显示导入javax.validation。hibernate-validator 5.x版本基本已停更,只有严重bug才会修复。因此若非特殊情况,不再建议你使用此版本,也就是不建议再使用Bean Validation 1.1版本,更别谈1.0版本喽。


小贴士:Spring Boot1.5.x默认集成的还是Bean Validation 1.1哦,但到了Boot 2.x后就彻底摒弃了老旧版本


JSR380


当下主流版本,也就是我们所说的Java Bean Validation 2.0和Jakarta Bean Validation 2.0版本。关于这两种版本的差异,官方做出了解释:


image.png


他俩除了叫法不一样、除了GAV上有变化,其它地方没任何改变。它们各自的GAV如下:


<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>2.0.1</version>
</dependency>


现在应该不能再叫Java EE了,而应该是Jakarta EE。两者是一样的意思,你懂的。Jakarta Bean Validation 2.0是在2019年8月发布的,属于Jakarta EE 8的一部分。它的官方参考实现只有唯一的Hibernate validator了:


image.png


此版本具有很重要的现实意义,它主要提供如下亮点:


1.支持通过注解参数化类型(泛型类型)参数来验证容器内的元素,如:List<@Positive Integer> positiveNumbers

   1.更灵活的集合类型级联验证;例如,现在可以验证映射的值和键,如:Map<@Valid CustomerType, @Valid Customer> customersByType

   2.支持java.util.Optional类型,并且支持通过插入额外的值提取器来支持自定义容器类型


2.让@Past/@Future注解支持注解在JSR310时间上


3.新增内建的注解类型(共9个):@Email, @NotEmpty, @NotBlank, @Positive, @PositiveOrZero, @Negative, @NegativeOrZero, @PastOrPresent和@FutureOrPresent


4.所有内置的约束现在都支持重复标记


5.使用反射检索参数名称,也就是入参名,详见这个API:ParameterNameProvider

   1.很明显这是需要Java 8的启动参数支持的


6.Bean验证XML描述符的名称空间已更改为:

   1.META-INF/validation.xml -> http://xmlns.jcp.org/xml/ns/validation/configuration

   2.mapping files -> http://xmlns.jcp.org/xml/ns/validation/mapping


7.JDK最低版本要求:JDK 8


Hibernate Validator自6.x版本开始对JSR 380规范提供完整支持,除了支持标准外,自己也做了相应的优化,比如性能改进、减少内存占用等等,因此用最新的版本肯定是没错的,毕竟只会越来越好嘛。


新增注解


相较于1.x版本,2.0版本在其基础上新增了9个实用注解,总数到了22个。现对新增的9个注解解释如下:


image.png


@Email、@NotEmpty、@NotBlank之前是Hibernate额外提供的,2.0标准后hibernate自动退位让贤并且标注为过期了。Bean Validation 2.0的JSR规范制定负责人就职于Hibernate,所以这么做就很自然了。就是他:


image.png


小贴士:除了JSR标准提供的这22个注解外,Hibernate Validator还提供了一些非常实用的注解,这在后面讲述Hibernate Validator时再解释吧


使用示例


导入实现包:

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.5.Final</version>
</dependency>


校验Java Bean


书写JavaBean和校验程序(全部使用JSR标准API哦):

@ToString
@Setter
@Getter
public class Person {
    @NotNull
    public String name;
    @NotNull
    @Min(0)
    public Integer age;
}
public static void main(String[] args) {
    Person person = new Person();
    person.setAge(-1);
    // 1、使用【默认配置】得到一个校验工厂  这个配置可以来自于provider、SPI提供
    ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
    // 2、得到一个校验器
    Validator validator = validatorFactory.getValidator();
    // 3、校验Java Bean(解析注解) 返回校验结果
    Set<ConstraintViolation<Person>> result = validator.validate(person);
    // 输出校验结果
    result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue()).forEach(System.out::println);
}

运行程序,不幸抛错:


Caused by: java.lang.ClassNotFoundException: javax.el.ELManager
  at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
  at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
  ...


上面说了,从1.1版本起就需要El管理器支持用于错误消息动态插值,因此需要自己额外导入EL的实现。


小贴士:EL也属于Java EE标准技术,可认为是一种表达式语言工具,它并不仅仅是只能用于Web(即使你绝大部分情况下都是用于web的jsp里),可以用于任意地方(类比Spring的SpEL)


这是EL技术规范的API:


<!-- 规范API -->
<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>3.0.0</version>
</dependency>


Expression Language 3.0表达式语言规范发版于2013-4-29发布的,Tomcat 8、Jetty 9、GlasshFish 4都已经支持实现了EL 3.0,因此随意导入一个都可(如果你是web环境,根本就不用自己手动导入这玩意了)。


<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-el</artifactId>
    <version>9.0.22</version>
</dependency>


添加好后,再次运行程序,控制台正常输出校验失败的消息:

age 最小不能小于0: -1
name 不能为null: null


校验方法/校验构造器


请移步下文详解。


加餐:Bean Validation 3.0


伴随着Jakarta EE 9的发布,Jakarta Bean Validation 3.0也正式公诸于世。

<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>3.0.0</version>
</dependency>


它最大的改变,甚至可以说唯一的改变就是包名的变化:


image.png


至此不仅GAV上实现了更名,对代码执行有重要影响的包名也彻彻底底的去javax.*化了。因为实际的类并没有改变,因此仍旧可以认为它是JSR380的实现(虽然不再由JCP组织制定标准了)。


参考实现


毫无疑问,参考实现那必然是Hibernate Validator。它的步伐也跟得非常的紧,退出了7.x版本用于支持Jakarta Bean Validation 3.0。虽然是大版本号的升级,但是在新特性方面你可认为是无:


image.png

✍总结


本文着眼于讲解JSR规范、Bean Validation校验标准、官方参考实现Hibernate Validator,把它们之间的关系进行了关联,并且对差异进行了鉴别。我认为这篇文章对一般读者来说是能够刷新对数据校验的认知的。


wow,数据校验背后还有这么广阔的天地


数据校验是日常工组中接触非常非常频繁的一块知识点,我认为掌握它并且熟练运用于实际工作中,能起到事半功倍的效果,让代码更加的优雅,甚至还能实现别人加班你加薪呢。所以又是一个投出产出比颇高的小而美专栏在路上…


作为本专栏的第一篇文章以JSR标准作为切入点进行讲解,是希望理论和实践能结合起来学习,毕竟理论的指导作用不可或缺。有了理论铺垫的基石,后面实践将更加流畅,正所谓着地走路更加踏实嘛。

相关文章
|
Java 数据库连接
后端校验(hibernate-validator)
后端校验(hibernate-validator)
379 0
|
应用服务中间件 Linux
Tomcat不定期close_wait过多
Tomcat不定期close_wait过多
573 0
|
存储 消息中间件 JSON
DDD基础教程:一文带你读懂DDD分层架构
DDD基础教程:一文带你读懂DDD分层架构
|
4月前
|
druid Java 关系型数据库
Spring Boot与Druid升级解决方案
好的,我需要帮助用户解决他们遇到的数据库连接问题,并升级项目的依赖。首先,用户提供的错误信息是关于Spring Boot应用在初始化数据源时抛出的异常,具体是Druid连接池验证连接失败。同时,用户希望升级项目的依赖版本。
431 10
|
编解码 数据可视化 数据挖掘
【办公自动化】用Python将PDF文件转存为图片
【办公自动化】用Python将PDF文件转存为图片
359 1
|
6月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
672 0
|
缓存 监控 Android开发
探索iOS与安卓开发中的性能优化策略
在移动应用开发的竞技场上,iOS和安卓这两大操作系统不断推动着技术的边界。性能优化,作为提升用户体验的关键因素,已成为开发者们关注的焦点。本文将深入探讨两大平台上的性能优化实践,揭示如何通过工具、技术和策略来提升应用的响应速度和流畅度,同时考虑到电池寿命和内存管理等关键指标。
|
搜索推荐 Java 开发者
Java异常处理新高度:自定义异常,打造个性化的错误管理体系!
Java异常处理新高度:自定义异常,打造个性化的错误管理体系!
183 1
|
10月前
|
UED
em/px/rem/vh/vw区别
【10月更文挑战第24天】理解和掌握 em、px、rem、vh、vw 这几种单位的特点和应用,能够帮助我们更好地进行网页设计和布局,实现更优秀的用户体验和适应不同屏幕尺寸的能力。
|
Java Spring
【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连接使用 ConnectionString 方式
【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连接使用 ConnectionString 方式
125 0