SpringBoot整合Hibernate validator校验框架
作用:
- 将验证逻辑与业务逻辑之间进行了分离,降低了程序耦合度
1.引入jar包
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
<scope>compile</scope>
</dependency>
2.配置校验配置类
/**
* @program: hibrenate_validator_demo
* @description: ValidatorConfiguration
* @author: Z_R
* @create: 2020-11-22 20:53
*/
@Configuration
public class ValidatorConfiguration {
// @Bean
// public MethodValidationPostProcessor methodValidationPostProcessor() {
// 如下直接配置bean 会校验所有 参数,返回所有错误提示
// return new MethodValidationPostProcessor();
// }
// spring 对 validator 的封装,如果当前bean不做配置,那么 spring的 @Validated 作用下的 快速失败 不会生效
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
/**设置validator模式为快速失败返回*/
postProcessor.setValidator(this.validator());
return postProcessor;
}
// 配置 Validator 快速失效
@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
//设置为true 开启快速校验--默认校验所有参数,false校验全部
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
return validator;
}
}
3.添加POJO对象添加约束注解
/**
* @program: hibrenate_validator_demo
* @description:
* @author: Z_R
* @create: 2020-11-22 20:01
*/
@Data
@AllArgsConstructor
public class TestRequestVO implements Serializable {
@NotNull(message = "id不能为空")
private Integer id;
/**
* "" 加强版 的 NotNull "" 也可以捕获
*/
@NotBlank(message = "name不能为空")
private String name;
@Max(150)
@Min(0)
private Integer age;
/**
* @AssertTrue(message="必须为true")
*/
@AssertFalse(message = "必须为false")
private Boolean flag;
/**
* regexp 正则表达式
*/
@Pattern(regexp = "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", message = "出生日期格式不正确")
private String birthday;
@NotNull(message = "list不能为空")
List<TestRequestVO> list;
/**
* 层级校验,校验对象内部属性 --- 引用类型 -- 对象级联校验
*/
@Valid
@NotNull(message = "testRequestDTO不能为空")
private TestRequestVO testRequestDTO;
}
4.添加结果处理类
/**
* @program: hibrenate_validator_demo
* @description: ResultEntity
* @author: Z_R
* @create: 2020-11-22 20:16
*/
@Data
@AllArgsConstructor
public class ResultEntity {
private int code;
private Object data;
private String msg;
private boolean success;
public ResultEntity() {
}
public ResultEntity(int status) {
this.code = status;
}
public ResultEntity(int status, Object data) {
this.code = status;
this.data = data;
}
public ResultEntity(int code, String msg) {
this.code = code;
this.msg = msg;
}
public String getMsg() {
return msg;
}
public ResultEntity setMsg(String msg) {
this.msg = msg;
return this;
}
}
5.配置全局异常处理
/**
* @program: hibrenate_validator_demo
* @description: TestExceptionHandler
* @author: Z_R
* @create: 2020-11-22 20:23
*/
@SuppressWarnings("ALL")
@ControllerAdvice
public class TestExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(TestExceptionHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public ResultEntity handleException(Exception e) {
//MissingServletRequestParameterException
if (e instanceof MissingServletRequestParameterException) {
// @RequestParam 要求传入的参数 未传
log.error("MissingServletRequestParameterException ==== " + e.getMessage(), e);
MissingServletRequestParameterException mise = (MissingServletRequestParameterException) e;
return new ResultEntity(HttpStatus.BAD_REQUEST.value(), null).setMsg("参数" + mise.getParameterName() + "不能为空");
}
if (e instanceof MethodArgumentTypeMismatchException) {
// @RequestParam 传入参数类型不匹配
log.error("MethodArgumentTypeMismatchException ==== " + e.getMessage(), e);
return new ResultEntity(HttpStatus.BAD_REQUEST.value(), null).setMsg("参数类型不匹配");
}
log.error(e.getMessage(), e);
BindingResult result = null;
if (e instanceof MethodArgumentNotValidException) {
result = ((MethodArgumentNotValidException) e).getBindingResult();
} else if (e instanceof BindException) {
result = ((BindException) e).getBindingResult();
} else if (e instanceof ConstraintViolationException) {
// 使用@Valid 校验对象 参数不满足条件时 会抛出的 异常 对应的处理逻辑
Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) e).getConstraintViolations();
List<String> errors = new ArrayList<>();
for (ConstraintViolation<?> violation : constraintViolations) {
errors.add(violation.getMessage());
}
return new ResultEntity(HttpStatus.OK.value(), errors);
}
if (result != null) {
List<String> errors = new ArrayList<>();
for (ObjectError error : result.getAllErrors()) {
errors.add(error.getDefaultMessage());
}
return new ResultEntity(HttpStatus.BAD_REQUEST.value(), errors);
}
return new ResultEntity(HttpStatus.BAD_REQUEST.value());
}
}
6.在Controller层配置需要校验参数
/**
* @program: hibrenate_validator_demo
* @description:
* @author: Z_R
* @create: 2020-11-22 19:48
*/
@RestController
@Validated
public class TestController {
private static Logger logger = LoggerFactory.getLogger(TestController.class);
@GetMapping("/test1")
public String test1(@Valid TestRequestVO testRequestVO) {
logger.info(testRequestVO.toString());
//return new ResultEntity();
return "test1";
}
@PostMapping("/test2")
public ResultEntity test2(@RequestBody @Valid TestRequestVO testRequestVO) {
logger.info(testRequestVO.toString());
return new ResultEntity();
}
/**
* @param id
* @param name
* @param age
* @return
* @RequestParam 默认required属性为true,代表当前参数不能不传,所以已经具备 @NotNull的能力
* 需要在 类前面加
* //@Validated 用于 @RequestParam 类型 接口 参数 的 validator 校验,
* // 只有在类上加了这个注解,test3 @Min 等validator注解才能生效
*/
@GetMapping("/test3")
public String test3(@RequestParam(value = "id") Integer id,
@RequestParam(value = "name", required = false) String name,
@Min(value = 10, message = "age最小只能是10") @RequestParam(value = "age", required = false) Integer age) {
return "test3";
}
}
常用注解:
@Valid 被注释的元素是一个对象,需要检查此对象的所有字段值
@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(value) 被注释的元素必须符合指定的正则表达式
总结:
通过使用Hibernate Validator校验框架,可以在设计之初规避很多错误