使用步骤
- 给实体类属性添加校验注解(校验注解都在javax.validation.constraints包下),默认的message都在ValadationMessages_zh_CN.properties,不满意可以自定义message提示,如
@NotBlank(message = "品牌名不能为空")
- 在Controller需要校验的实体类前加注解@Valid,如
public R save(@Valid @RequestBody BrandEntity brand) {}
- 在校验的实体类后紧跟BindingResult就可以获得校验结果,如
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {}
- 完整例子
/** * 保存 */ @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand, 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.save(brand); return R.ok(); }
postman测试 localhost:88/api/product/brand/save { "msg": "提交的数据不合法", "code": 400, "data": { "name": "品牌名必须提交" } }
统一异常处理
不使用BindingResult感知异常,有异常时,异常就会被抛出
基本使用
用统一异常处理来处理Controller里数据校验的逻辑
- 新建包exception、新建类ExceptionControllerAdvice
- 加了统一异常处理后,controller里参数中的BindingResult删掉,数据校验逻辑删掉
/**
* 集中处理所有异常
*/
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class ExceptionControllerAdvice {
@ExceptionHandler(value=Exception.class) //方法可以处理的异常
public R handleVaildException(Exception e){
log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
//BindingResult bindingResult = e.getBindingResult();
return R.error();
}
}
/**
* 集中处理所有异常
*/
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class ExceptionControllerAdvice {
@ExceptionHandler(value= MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e){
log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String,String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach((fieldError)->{
errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
});
//return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);
return R.error(400,"数据校验出现问题").put("data",errorMap);
}
枚举类怎么写?需要会
分组校验
实体类属性注解内添加注解属性groups,给注解分组
1.编写分组接口AddGroup、UpdateGroup,接口写在common模块valid包下
public interface AddGroup {
}
实体类上的注解
/**
* 品牌id
*/
@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})
@Null(message = "新增不能指定id",groups = {AddGroup.class})
@NotBlank(message="",groups= {AddGroup.class, UpdateGroup.class})
@TableId
private Long brandId;
2.Controller里原本@Valid替换成@Validated,此注解参数可指定一个或多个校验分组
使用@Validated后,实体类属性校验注解如果没有添加groups,那么实体类属性上的校验不生效,这种情况只会在@Validated不指定校验分组的时候生效
@Validated({AddGroup.class})
自定义校验注解
- 引入依赖
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
- 编写一个自定义校验注解
@Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) //校验器 @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.atguigu.common.valid.ListValue.message}"; //自定义校验注解的全类名 Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] vals() default { }; }
类路径下新建ValidationMessages.properties
com.atguigu.common.valid.ListVAlue.message="必须提交指定的值"
- 编写一个自定义校验器
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); } }
- 关联自定义校验注解和自定义校验器