spring 框架实现了一套validation,底层采用hibernate-validator。
1 maven 坐标
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
2 客户端参数校验
2.1 表单
class TestVO {
@NotNull
private String name;
@NotNull
private String password;
@NotNull
private String email;
// getter setter
}
2.2 使用 @Validated
方式一:
@PostMapping("/validation")
public boolean learnValidator(@Validated TestVO vo) {
return true;
}
此方式TestVO如果不符合注解标注的,会抛出异常。
方式二:
@PostMapping("/validation") public boolean learnValidator(@Validated TestVO vo, BindingResult result) { // result 异常自己可以处理。 return true; }
此方式不会抛出异常,会将异常信息存放在BindResult中,可以对BindResult进行解析,进行异常处理。
2.3 将异常统一处理
@RestControllerAdvice
public class GlobalControllerAdvice {
private static final String BAD_REQUEST_MSG = "客户端请求参数错误";
// <1> 处理 form data方式调用接口校验失败抛出的异常
@ExceptionHandler(BindException.class)
public ResultInfo bindExceptionHandler(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
// <2> 处理 json 请求体调用接口校验失败抛出的异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultInfo methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
List<String> collect = fieldErrors.stream()
.map(o -> o.getDefaultMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
// <3> 处理单个参数校验失败抛出的异常
@ExceptionHandler(ConstraintViolationException.class)
public ResultInfo constraintViolationExceptionHandler(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
List<String> collect = constraintViolations.stream()
.map(o -> o.getMessage())
.collect(Collectors.toList());
return new ResultInfo().success(HttpStatus.BAD_REQUEST.value(), BAD_REQUEST_MSG, collect);
}
}
2.4 分组校验
如果同一个参数,需要在不同场景下应用不同的校验规则,就需要用到分组校验了。比如:新注册用户还没起名字,我们允许 name 字段为空,但是不允许将名字更新为空字符。
分组校验有三个步骤:
-
定义一个分组类(或接口)
-
在校验注解上添加groups属性指定分组
-
Controller 方法的 @Validated 注解添加分组类
public interface Update extends Default{
}
public class UserVO {
@NotBlank(message = "name 不能为空",groups = Update.class)
private String name;
// 省略其他代码...
}
@PostMapping("update")
public ResultInfo update(@Validated({Update.class}) UserVO userVO) {
return new ResultInfo().success(userVO);
}
所有不加分组标识的,都默认是Default.class。 如果校验的实体里还有对象,可以加@Valid,进行递归校验。