SpringBoot+HibernateValidator优雅的接口入参校验(代码实例)
HIbernateValidator有效注解详解
* @Null 被注释的元素必须为 null
* @NotNull 被注释的元素必须不为 null
* @AssertTrue 被注释的元素必须为 true
* @AssertFalse 被注释的元素必须为 false
* @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
* @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
* @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
* @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
* @Size(max=, min=) 被注释的元素的大小必须在指定的范围内
* @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
* @Past 被注释的元素必须是一个过去的日期
* @Future 被注释的元素必须是一个将来的日期
* @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
* Hibernate Validator 附加的 constraint
* @NotBlank(message =) 验证字符串非null,且长度必须大于0
* @Email 被注释的元素必须是电子邮箱地址
* @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
* @NotEmpty 被注释的字符串的必须非空
* @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
* @Digits(integer=, fraction=) 限定被注释参数的整数位数和小数位数
HIbernateValidator注释的接口入参类实例
@Data
public class UserRequest {
@NotBlank(message = "interfaceId不能为空")
private String interfaceId;
@NotEmpty(message = "uuid不能为空")
private String uuid;
@Length(min = 10, message = "sign长度必须大于10")
private String sign;
@Valid // 如果不为空,则校验子类数据
private User data;
@NotBlank
@Pattern(regexp = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$]", message = "requestDate时间格式为yyyy-MM-dd")
private String requestDate;
@Max(value = 100, message = "amount的最大值为100")
private Integer amount;
@Digits(integer = 9, fraction=2, message = "price格式不正确")
private BigDecimal price;
}
接口实例
若要使用hibernate validator校验接口入参,在接口的参数上必须加上@Validated注解,否则入参实体内的validator注解不生效。
@PostMapping("/set-value")
public String setValue(@Validated @RequestBody UserRequest request){
logger.info("接收set-value请求[{}]", request);
return "success";
}
测试结果
使用postman测试
结果接收到一堆异常堆栈:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.term.spring_batch.controller.HelloController.setValue(com.term.spring_batch.model.dto.UserRequest) with 2 errors: [Field error in object ‘userRequest’ on field ‘requestDate’: rejected value [null]; codes [NotBlank.userRequest.requestDate,NotBlank.requestDate,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userRequest.requestDate,requestDate]; arguments []; default message [requestDate]]; default message [不能为空]] [Field error in object ‘userRequest’ on field ‘uuid’: rejected value [null]; codes [NotEmpty.userRequest.uuid,NotEmpty.uuid,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userRequest.uuid,uuid]; arguments []; default message [uuid]]; default message [uuid不能为空]] ……
捕获validator抛出的异常,友好展现异常信息
仔细看确实是我们的注解生效了,并给出了一些我们自定义的提示。但是异常堆栈这种报错太不友好了,我们使用Spring的统一异常处理机制(全局异常处理类的写法请参考)捕获一下 MethodArgumentNotValidException异常
代码如下:
// 方法参数校验异常
@ExceptionHandler(value = ConstraintViolationException.class)
public String constraintViolationException(ConstraintViolationException e) {
if (e.getMessage() != null) {
int index = e.getMessage().indexOf(":");
String msg = index != -1 ? e.getMessage().substring(index + 1).trim() : e.getMessage();
logger.info(msg);
return msg;
}
return null;
}
// Bean 校验异常
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public String notValidExceptionHandler(MethodArgumentNotValidException e) throws Exception {
String msg = null;
if (e.getBindingResult() != null && !CollectionUtils.isEmpty(e.getBindingResult().getAllErrors())) {
msg = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
logger.info(msg);
} else {
logger.info(msg = e.getMessage());
}
return msg;
}
再次测试,结果为:
uuid不能为空,requestDate不能为空