本文从本人博客搬运,原文格式更加美观,可以移步原文阅读:SpringBoot后端数据校验实战
一般我们会在Controller的接口中对前端传递的参数做数据校验,这是一个后端开发人员的基本素养
在SpringBoot项目中,为了不让一大堆复杂的校验代码入侵业务逻辑,通常会用校验注解来简化代码
要使用校验注解,首先要引入hibernate-validator
依赖
<!--JSR303数据校验支持-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
如果是Springboot工程,那么引入
spring-boot-starter-web
后就会自动引入hibernate-validator
常用校验注解
可以在需要校验的参数上标注下列校验注解
限制 | 说明 |
---|---|
@Null | 限制只能为null |
@NotNull | 限制必须不为null |
@AssertFalse | 限制必须为false |
@AssertTrue | 限制必须为true |
@DecimalMax(value) | 限制必须为一个不大于指定值的数字 |
@DecimalMin(value) | 限制必须为一个不小于指定值的数字 |
@Digits(integer,fraction) | 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction |
@Future | 限制必须是一个将来的日期 |
@Max(value) | 限制必须为一个不大于指定值的数字 |
@Min(value) | 限制必须为一个不小于指定值的数字 |
@Past | 限制必须是一个过去的日期 |
@Pattern(value) | 限制必须符合指定的正则表达式 |
@Size(max,min) | 限制字符长度必须在min到max之间 |
@Past | 验证注解的元素值(日期类型)比当前时间早 |
@NotEmpty | 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) |
@NotBlank | 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 |
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 |
1.空与非空检查
注解 | 支持Java类型 | 说明 |
---|---|---|
@Null | Object | 为null |
@NotNull | Object | 不为null |
@NotBlank | CharSequence | 不为null,且必须有一个非空格字符 |
@NotEmpty | CharSequence、Collection、Map、Array | 不为null,且不为空(length/size>0) |
2.Boolean值检查
注解 | 支持Java类型 | 说明 | 备注 |
---|---|---|---|
@AssertTrue | boolean、Boolean | 为true | 为null有效 |
@AssertFalse | boolean、Boolean | 为false | 为null有效 |
3.日期检查
注解 | 支持Java类型 | 说明 | 备注 |
---|---|---|---|
@Future | Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate | 验证日期为当前时间之后 | 为null有效 |
@FutureOrPresent | Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate | 验证日期为当前时间或之后 | 为null有效 |
@Past | Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate | 验证日期为当前时间之前 | 为null有效 |
@PastOrPresent | Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate | 验证日期为当前时间或之前 | 为null有效 |
4.数值检查
注解 | 支持Java类型 | 说明 | 备注 |
---|---|---|---|
@Max | BigDecimal、BigInteger,byte、short、int、long以及包装类 | 小于或等于 | 为null有效 |
@Min | BigDecimal、BigInteger,byte、short、int、long以及包装类 | 大于或等于 | 为null有效 |
@DecimalMax | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | 小于或等于 | 为null有效 |
@DecimalMin | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | 大于或等于 | 为null有效 |
@Negative | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | 负数 | 为null有效,0无效 |
@NegativeOrZero | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | 负数或零 | 为null有效 |
@Positive | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | 正数 | 为null有效,0无效 |
@PositiveOrZero | BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类 | 正数或零 | 为null有效 |
@Digits(integer = 3, fraction = 2) | BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类 | 整数位数和小数位数上限 | 为null有效 |
5.其他
注解 | 支持Java类型 | 说明 | 备注 |
---|---|---|---|
@Pattern | CharSequence | 匹配指定的正则表达式 | 为null有效 |
CharSequence | 邮箱地址 | 为null有效,默认正则 '.*' |
|
@Size | CharSequence、Collection、Map、Array | 大小范围(length/size>0) | 为null有效 |
6.hibernate-validator扩展注解
注解 | 支持Java类型 | 说明 |
---|---|---|
@Length | String | 字符串长度范围 |
@Range | 数值类型和String | 指定范围 |
@URL | String | URL地址验证 |
基础校验
1.基本数据类型校验
如果Controller的接口方法中需要校验的参数是基本数据类型,如String
、Integer
等非封装的对象,那么可以按照如下步骤:
- 在Controller上添加
@Validated
- 在Controller的接口方法中给需要校验的参数前面添加校验注解
@RestController
@RequestMapping("validate")
@Validated
public class ValidateController {
@GetMapping("test")
public String test(@NotBlank(message = "名称不能为空") String name) {
return "success";
}
}
请求参数不传name,校验不通过,会抛出javax.validation.ConstraintViolationException
异常
2.javabean校验
如果Controller的接口方法中需要校验的参数是封装的javabean,想要校验bean中的部分属性,那么可以按照如下步骤:
- 给javabean中需要校验属性上添加校验注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
// 字符串长度校验,长度必须在2~5之间
@Length(min = 2, max = 5)
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd")
@Past // 日期校验,日期必须是过去的一个日期
private Date birth;
}
- 在Controller的请求处理方法参数声明中,在需要校验的Bean的形参前面加上
@Valid
注解,并在该Bean的形参后面紧跟着声明一个BindingResult
类型的参数(注意,中间不能夹杂任何其他类型的参数),这样校验的结果就会保存在BindingResult
对象中
@RestController
@RequestMapping("validate")
public class ValidateController {
@PostMapping("test1")
public String testValidate(@RequestBody @Valid User user, BindingResult bindingResult){
System.out.println(user);
System.out.println(bindingResult);
return "success";
}
}
我们故意传入一些校验不通过的数据进行测试
name和birth的校验将会不通过,控制台打印输出如下
User(name=baobao, age=18, birth=Sun Jul 25 08:00:00 CST 2021)
org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'name': rejected value [baobao]; codes [Length.user.name,Length.name,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name],5,2]; default message [长度需要在2和5之间]
Field error in object 'user' on field 'birth': rejected value [Sun Jul 25 08:00:00 CST 2021]; codes [Past.user.birth,Past.birth,Past.java.util.Date,Past]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.birth,birth]; arguments []; default message [birth]]; default message [需要是一个过去的时间]
BindingResult
对象中包含了校验错误信息
注意:
如果我们在Controller方法参数中不加
BindingResult
对象捕获校验失败信息,那么校验失败信息会以org.springframework.web.bind.MethodArgumentNotValidException
异常形式被异常解析器处理2021-07-23 23:27:33.372 WARN 4352 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.baobao.springboot.validate.controller.ValidateController.testValidate(com.baobao.springboot.validate.entity.User) with 2 errors: [Field error in object 'user' on field 'birth': rejected value [Sun Jul 25 08:00:00 CST 2021]; codes [Past.user.birth,Past.birth,Past.java.util.Date,Past]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.birth,birth]; arguments []; default message [birth]]; default message [需要是一个过去的时间]] [Field error in object 'user' on field 'name': rejected value [baobao]; codes [Length.user