七月第一文
一、简述
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。Bean Validation 为 Java Bean 验证定义了相应的元数据模型和 API。用于对Java Bean 中的字段的值进行验证,使得基本的验证逻辑可以从业务代码中脱离出来。
常用的注解:
Constraint | 详细信息 | 作用类型 |
---|---|---|
@Null | 被注释的元素必须为 null | 引用类型 |
@NotNull | 被注释的元素必须不为 null | 引用类型 |
@AssertTrue | 被注释的元素必须为 true | boolean |
@AssertFalse | 被注释的元素必须为 false | boolean |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger、String |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | byte、short、int、long及对应的包装类型以及BigDecimal、BigInteger、String |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 | String、Collection、Map和数组 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 | byte、short、int、long及各自的包装类型以及BigDecimal、BigInteger、String |
@Past | 被注释的元素必须是一个过去的日期 | java.util.Date,java.util.Calendar |
@Future | 被注释的元素必须是一个将来的日期 | java.util.Date,java.util.Calendar |
@Pattern(regex=) | 被注释的元素必须符合指定的正则表达式 | String |
@Valid | 被注释的元素需要递归验证 | 引用对象 |
还有hibernate Validator新增的注解
Constraint | 详细信息 | 作用类型 |
---|---|---|
被注释的元素必须是电子邮箱地址 | String | |
@Length(min=下限, max=上限) | 被注释的字符串的大小必须在指定的范围内 | String |
@NotEmpty | 被注释的元素的必须非空并且size大于0 | String、Collection、Map和数组 |
@NotBlank | 被注释的元素必须不为空且不能全部为’ ‘(空字符串) | String |
@Range(min=最小值, max=最大值) | 被注释的元素必须在合适的范围内 | byte、short、int、long及各自的包装类型以及BigDecimal、BigInteger、String |
二、开始使用Bean Validation
使用到的依赖
1 | xml复制代码 <dependencies> |
假如有一个文章的实体类,用于接收前端的传来的数据。使用了校验注解@Size
和@NotBlank
来校验文章标题是否为空,且长度是都在允许的范围内;使用了校验注解@Email
来校验是否符合邮箱格式;使用校验注解@URL
来校验封面是否是一个url。
1 | java复制代码@Data |
编写controller,一个Valid对应一个BindingResult。
1 | java复制代码@RestController |
测试结果:
三、统一异常处理和分组校验
3.1 使用统一异常处理
如果是按照在上面的示例来写,那么每个方法都要去处理BindingResult这会显得很麻烦和很low,使得代码很冗余。
在Spring Boot中可以使用ControllerAdvicd
来做统一异常处理。如下:
1 | java复制代码@RestControllerAdvice |
3.2 使用分组校验
可能会有这种情况,文章在添加的时候是不能带Id使用数据库自增Id或者自定义的Id,但是在更新的时候就必须带上Id。又例如在更新文章状态的时候参数是有文章的状态改变了,只需要校验文章状态。所以引入分组校验的概念,来解决。
1 | java复制代码public class ValidateGroup { |
实体类,这些校验注解都有一个groups属性,指定该校验注解在那些分组上生效。
1 | java复制代码@Data |
编写controller演示方法,这时候校验注解里面就需要添加校验组了,@Valid
是没有这个属性的,需要使用@Validated
注解,在value属性中填写要生效的校验分组,该属性是个数组可以填写多个校验分组。
1 | java复制代码@RestController |
使用Postman测试一下:
调用添加接口时,文章id必须为空。
调用更新接口时,必须带上文章id。
如果Bean的一些校验注解上没有指定分组,但是在controller的校验参数上指定了校验分组@Validated
,那么这些没有指定分组的属性是不会生效的。
四、自定义校验器
假如文章的状态只有0(审核中)、1(已通过)和2(删除)三种状态,所以前端传过来的参数只能是这三个,传过来是其他的那就提示参数有问题。但是看了一下提供的校验注解并没有我们符合我们需求的注解。所以我们需要自己动手自己实现。看下面代码:
1 | java复制代码@Documented |
在使用校验注解时,当我没有指定message属性,它是会有一个默认的。这些默认的提示写在一个ValidationMessages.properties
属性文件中,所以在resources文件夹下创建一个ValidationMessages.properties
文件,内容如下:
1 | properties复制代码com.msr.better.annotation.ListValue.message=必须提交指定值 |
这个默认的属性文件在hibernate-validator
这个依赖里面,有各种语言的版本。
在SpringBoot的配置文件中配置一下,防止ValidationMessages.properties
属性文件内容中文乱码
1 | yaml复制代码spring: |
现在编写自定义校验器:
1 | java复制代码public class ListValueValidator implements ConstraintValidator<ListValue, Integer> { |
新增一个更新文章状态的校验分组:
1 | java复制代码public class ValidateGroup { |
使用自定义的校验注解:
1 | java复制代码@Data |
编写一个controller的方法来演示:
1 | java复制代码 @PutMapping("update/status") |
使用Postman测试:
五、总结
有些参数校验通过提供的注解来实现,可以减少手动编写校验代码,让整个项目更加的整洁。
本文转载自: 掘金