1. 给 Bean 添加校验注解: Javax.validation.constraints
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须提交")
private String name;
2. 在 Controller 层中,开启 校验功能 @Vaild
/**
* 删除
*/
@RequestMapping("/delete")
//@RequiresPermissions("product:brand:delete")
public R delete(@Valid @RequestBody Long[] brandIds){
brandService.removeByIds(Arrays.asList(brandIds));
return R.ok();
}
3. 给校验的 Bean 后,紧跟一个 BindingResult ,可获取到校验结果
/**
* 删除
*/
@RequestMapping("/delete")
//@RequiresPermissions("product:brand:delete")
public R delete(@Valid @RequestBody Long[] brandIds,BindingResult result){
if (result.hasErrors()) {
Map<String, String> map = new HashMap<>();
//1、获取校验的错误结果
result.getFieldErrors().forEach((item) -> {
//FieldError 获取到错误提示
String message = item.getDefaultMessage();
//获取错误的属性的名字
String field = item.getField();
map.put(field, message);
});
return R.error(400, "提交的数据不合法").put("data", map);
} else {
brandService.removeByIds(Arrays.asList(brandIds));
}
// brandService.removeByIds(Arrays.asList(brandIds));
return R.ok();
}
4. 将 Controller 层异常处理统一化管理
1). 使用 @ControllerAdvice
2). 使用 @ExceptionHandler 标注方法可以处理的异常类别
@Slf4j
//
@RestControllerAdvice(basePackages = "org.scut.mall.product.controller")
public class MallExceptionControllerAdvice {
// 处理校验异常
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e){
log.error("数据校验出现问题:{} , 异常类型: {}",e.getMessage(),e.getClass());
// 可以从 MethodArgumentNotValidException 获取到校验异常的结果信息 BindingResult
BindingResult bindingResult=e.getBindingResult();
Map<String,String> errorMap=new HashMap<>();
bindingResult.getFieldErrors().forEach(fieldError -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(BizCode.VALID_EXCEPTION.getCode(),BizCode.VALID_EXCEPTION.getMessage()).put("data",errorMap);
}
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
log.error("Exception: ",throwable);
return R.error(BizCode.UNKNOWN_EXCEPTION.getCode(),BizCode.UNKNOWN_EXCEPTION.getMessage());
}
}
5. 多场景下的分组校验
1). @NotBlank(message = "品牌名不为空",groups = {AddGroup.class,UpdateGroup.class})
AddGroup.class,UpdateGroup.class 为接口类
2). @Validated({AddGroup.class}) 开启校验功能
@Validated 为 Spring 框架的校验注解类,可以配合 1)中的 groups 进行分组校验
3). 默认没有指定分组的校验注解@NotBlank,在分组校验情况@Validated({AddGroup.class})下不生效,只会在@Validated生效
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){
brandService.updateDetail(brand);
return R.ok();
}
6. 自定义校验
1)编写一个自定义的校验注解
如校验某个变量是否为给定的值: 1、2、3
@Documented
// 关联自定义的校验器和自定义的校验注解
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
// 从资源 ValidationMessages.properties 文件中获取校验信息
String message() default "{com.atguigu.common.valid.ListValue.message}";
// 使用校验的分组
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
// 给定的校验值
int[] vals() default { };
}
2)编写一个自定义的校验器 ConstraintValidator
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
//初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
//判断是否校验成功
/**
*
* @param value 需要校验的值
* @param context
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
3)关联自定义的校验器和自定义的校验注解
在 1) 中的自定义注解上 关联 注解校验器
@Constraint(validatedBy = { ListValueConstraintValidator.class })
4) 使用自定义校验注解
@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
@ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class})
private Integer showStatus;