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 数据库 Spring
Spring框架在Bean中的管理(第十一课)
Spring框架在Bean中的管理(第十一课)
204 0
|
前端开发 Java 索引
40 个 SpringBoot 常用注解:让生产力爆表! 1
40 个 SpringBoot 常用注解:让生产力爆表!
|
Java Spring 容器
40 个 SpringBoot 常用注解:让生产力爆表! 2
40 个 SpringBoot 常用注解:让生产力爆表!
|
数据可视化 Java
一文详解JavaBean 看这篇就够了
一文详解JavaBean 看这篇就够了
775 0
|
前端开发 Java 索引
40 个 SpringBoot 常用注解:让生产力爆表!(一)
40 个 SpringBoot 常用注解:让生产力爆表!(一)
40 个 SpringBoot 常用注解:让生产力爆表!(一)
|
Java Spring 容器
40 个 SpringBoot 常用注解:让生产力爆表!(二)
40 个 SpringBoot 常用注解:让生产力爆表!(二)
40 个 SpringBoot 常用注解:让生产力爆表!(二)
|
Oracle Java 关系型数据库
1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知(上)
1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知(上)
1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知(上)
|
Java Spring 容器
配置类需要标注@Configuration却不知原因?那这次就不能给你涨薪喽(上)
配置类需要标注@Configuration却不知原因?那这次就不能给你涨薪喽(上)
配置类需要标注@Configuration却不知原因?那这次就不能给你涨薪喽(上)
|
Java Spring
40 个 SpringBoot 常用注解:让生产力爆表!(三)
40 个 SpringBoot 常用注解:让生产力爆表!(三)
|
前端开发 Java Spring
【SSM直击大厂】第八章:SpringMVC拦截器
📋📋 精彩摘要:Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。本文将代码演示和文字描述详解拦截器的使用。
86 0