常用参数校验注解:
- @AssertFalse 所注解的元素必须是Boolean类型,且值为false
- @AssertTrue 所注解的元素必须是Boolean类型,且值为true
- @DecimalMax 所注解的元素必须是数字,且值小于等于给定的值
- @DecimalMin 所注解的元素必须是数字,且值大于等于给定的值
- @Digits 所注解的元素必须是数字,且值必须是指定的位数
- @Future 所注解的元素必须是将来某个日期
- @Max 所注解的元素必须是数字,且值小于等于给定的值
- @Min 所注解的元素必须是数字,且值小于等于给定的值
- @Range 所注解的元素需在指定范围区间内
- @NotNull 所注解的元素值不能为null
- @NotBlank 所注解的元素值有内容
- @Null 所注解的元素值为null
- @Past 所注解的元素必须是某个过去的日期
- @PastOrPresent 所注解的元素必须是过去某个或现在日期
- @Pattern 所注解的元素必须满足给定的正则表达式
- @Size 所注解的元素必须是String、集合或数组,且长度大小需保证在给定范围之内
- @Email 所注解的元素需满足Email格式
1. @NotNull,@NotEmpty,@NotBlank的区别
@NotNull:不能为null,作用于对象
@NotEmpty:不能为null且长度必须大于0,作用于string(不能为"",可以为" ")、集合、map、 数组
@NotBlank:不能为null且不能为""、" ",作用于string
2. get请求参数校验
直接将注解用在参数前面就行,举例:
@GetMapping("/get-user")
public ResultResponse<UserVO> getUser(@NotNull (message = "用户Id不能为null") Long userId) {
return ResultResponse.success(new UserVO());
}
不带参数请求,返回结果如下:
这个报错显然没有封装,所以我们需要对ConstraintViolationException进行封装
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResultResponse handle(ValidationException exception) {
List<String> message = new ArrayList<>();
if(exception instanceof ConstraintViolationException){
ConstraintViolationException exs = (ConstraintViolationException) exception;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
message.add(item.getMessage());
}
}
return ResultResponse.fail("-1", JSON.toJSONString(message));
}
}
再次不带参数请求,返回结果如下:
3. post请求参数校验
方法实体参数前加注解@Validated
@PostMapping("/insertUser")
public ResultResponse<Boolean> insertUser(@RequestBody @Validated UserVO userVO) {
return ResultResponse.success(true);
}
实体字段上加校验注解
@NotNull(message = "用户id不能为空")
private Long userId;
@NotBlank(message = "用户名称不能为空")
private String userName;
private Integer age;
private String address;
private ChildVO childVO;
注意:若是校验对象集合,要使用@Valid注解
使用post请求访问不带参数访问,返回错误如下:
显然,这个校验错误,我们也需要封装一下
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResultResponse handle(MethodArgumentNotValidException exception) {
List<String> message = new ArrayList<>();
if(exception instanceof MethodArgumentNotValidException){
MethodArgumentNotValidException exs = (MethodArgumentNotValidException) exception;
BindingResult bindingResult = exs.getBindingResult();
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError item : allErrors) {
message.add(item.getDefaultMessage());
}
}
return ResultResponse.fail("-1", JSON.toJSONString(message));
}
封装之后,再次访问,报错如下:
4. 快速失败模式
-
validation默认是普通模式,即返回所有校验错误的信息
-
快速失败模式,即有一个错误就返回
快速失败模式配置方式:
@Configuration public class ValidatorConf { @Bean public Validator validator() { ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class ) .configure() .failFast( true ) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); return validator; } }
5. 分组校验
有时方法都用同一个实体做参数检验,可能有些参数是必要的,有些是不要的,这时可以分组校验,在校验注解中使用groups分组,方法中校验指定分组,可以指定多个分组
6. 自定义校验注解
eg:添加一个参数必须为偶数的注解
步骤:
1. 新建注解,添加message、groups、payload参数
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = EvenNumberValidatorImpl.class)
public @interface EvenNumber {
int value() default 0;
String message() default "参数必须为偶数";
Class[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2. 新建注解实现类,实现ConstraintValidator
public class EvenNumberValidatorImpl implements ConstraintValidator<EvenNumber, Integer> {
private int value;
@Override
public void initialize(EvenNumber constraintAnnotation) {
this.value = constraintAnnotation.value();
}
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
if (integer != null) {
return integer % 2 == 0;
}
return false;
}
}
3. 在字段上使用
@EvenNumber(message = "号码必须为偶数")
private Integer number;