对于web应用来说,对方法参数的校验是十分重要的,参数校验的是否全面,直接决定整个方法的健壮性。
除了使用麻烦的if判断校验参数,还可以使用@Validated 和 @Valid注解来进行优雅地参数校验,让参数校验和写诗一样优雅。
@Validated 和 @Valid依赖引入
首先,我们来了解一下@Validated 和 @Valid 的区别。
虽然@Validated 和 @Valid 的提供者不同,但是两者都是由hibernate-validator来提供实现的,可以理解为@Validated是Spring对@Valid 的封装,增强了其功能。
所以,如果需要使用@Validated 和 @Valid注解来进行参数校验,则必须引入如下依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
需要注意的是:如果spring-boot版本小于2.3.x,spring-boot-starter-web会自动传入hibernate-validator依赖。否则需要手动引入依赖。
另外,如果写法正确,但是校验机制没有生效,那么可能是hibernate-validator依赖的版本不对,可以百度查询当前Spring的版本适用的hibernate-validator版本号
常用校验注解混个眼熟
注解 | 作用 | 适用类型 |
---|---|---|
@NotNull | 被注解的元素必须不为null | object |
@NotBlank | 验证注解的元素值不为空(不为null、去除首位空格后长度为0) | String |
@Length | 值长度在min和max区间内 | String |
@Pattern | 必须符合指定的正则表达式 | String |
是Email格式 | String | |
---- | ---- | ---- |
@AssertTrue | 必须为true | bool |
@AssertFalse | 必须是false | bool |
---- | ---- | ---- |
@Min | 其值必须大于等于最小值 | int,long,float,double |
@Max | 其值必须小于等于最小值 | int,long,float,double |
@DecimalMin | 其值必须大于等于最小值 | BigDecimal |
@DecimalMax | 其值必须小于等于最小值 | BigDecimal |
@Range | 元素值在最小值和最大值之间 | BigDecimal,BigInteger,CharSequence,byte,short,int,long |
@Digits | 元素值的整数位数和小数位数上限 | float,double,BigDecimal |
---- | ---- | ---- |
@Past | 元素必须为过去的一个时间 | java.util.Date |
@Future | 元素必须为未来的一个时间 | java.util.Date |
---- | ---- | ---- |
@Size | 元素的长度必须在指定范围内 | Array,List,Map |
@NotEmpty | 元素值不为null且不为空 | Array,List,Map |
错误提示语友好化
需要注意的是,SpringBoot2.3及其以上版本,会自动封装由@Validated 和 @Valid注解校验不通过时的异常,比如如下代码:
@RestController
@RequestMapping("/hello")
public class HelloController {
@PostMapping("/requestBodyValid")
public UserDTO requestBodyValid(@RequestBody @Validated UserDTO userDTO){
return userDTO;
}
}
@Data
public class UserDTO {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id最小只能是1")
private Long id;
}
此时请求接口,结果如下:
可见并没有返回校验失败的错误信息,查看应用日志,如下:
可见Spring对于校验发生的异常进行了封装,这使得前端调用方并不能看到具体的错误信息,十分不友好,所以这里我们使用Spring的统一异常处理机制@RestControllerAdvice 注解来统一对controller返回的异常进行友好化展示
@RestControllerAdvice注解的简单使用
@RestControllerAdvice
public class ExceptionHandler {
@org.springframework.web.bind.annotation.ExceptionHandler({MethodArgumentNotValidException.class})
@ResponseStatus(HttpStatus.OK)
public ResultVO validExceptionHandle(MethodArgumentNotValidException exception){
BindingResult bindingResult = exception.getBindingResult();
StringBuilder errorMsg = new StringBuilder("校验失败:");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errorMsg.append(fieldError.getDefaultMessage()).append(";");
}
return new ResultVO()
.setCode(ResultVO.VALID_NOT_PASS)
.setMsg(errorMsg.toString())
;
}
}
@Data
@Accessors(chain = true)
public class ResultVO {
public static final String VALID_NOT_PASS = "40";
public static final String VALID_PASS = "00";
private String msg;
private String code;
}
然后,我们再以相同的入参调用接口,可得到如下的返回值:
可见这样的提示信息就很友好化了。
下面是其他条件校验注解的简单使用:
@Data
public class UserDTO {
@NotNull(message = "notNull校验")
private Object notNull;
@NotBlank(message = "notBlank校验")
private String notBlank;
@Length(min = 1, max = 10, message = "length(1--10)校验")
private String length;
@Pattern(regexp = "^\\d{2}$",message = "pattern(正则表达式匹配两位数字)校验")
private String pattern;
@Email(message = "email校验")
private String email;
@AssertFalse(message = "assertFalse校验")
private Boolean assertFalse;
@AssertTrue(message = "assertTrue校验")
private Boolean assertTrue;
@Min(value = 1, message = "min值是1-校验")
private Integer min;
@Max(value = 10, message = "max值是10-校验")
private Integer max;
@DecimalMin(value = "1.1", message = "decimalMin值是1.1-校验")
private BigDecimal decimalMin;
@DecimalMax(value = "10.1", message = "decimalMax值是10.1-校验")
private BigDecimal decimalMax;
@Range(min = 1, max = 10, message = "range(1--10)-校验")
private Integer range;
@Digits(integer = 2, fraction = 2, message = "digits(2,2)-校验")
private Double digits;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Past(message = "past校验")
private Date past;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Future(message = "future校验")
private Date future;
@Size(min = 1, max = 3, message = "size(1--3)校验")
private List<Integer> size;
@NotEmpty(message = "集合不能为null或者空集合")
private List<Integer> notEmpty;
}
入参:
{
"notBlank": "",
"length": "123456789012",
"pattern": "123",
"email": "456aasd",
"assertFalse": true,
"assertTrue": false,
"min": 0,
"max": 11,
"decimalMin": 1.0,
"decimalMax": 10.2,
"range": -1,
"digits": 99.999,
"past": "2024-06-25 21:04:18",
"future": "2022-06-25 21:04:18",
"size": [
1,2,3,4
],
"notEmpty": [
]
}
出参:
好了,今天就先到这里了,拜拜