添加统一异常处理类注解@RestControllerAdvice 添加日志注解@Slf4j 添加异常处理方法注解@ExceptionHandler

开启校验注解 JSR303

导包

<dependency>
	<groupId>javax.validation</groupId>
	<artifactId>validation-api</artifactId>
	<version>2.0.1.Final</version>
</dependency>
javax.validation.constraints

(1)在实体类中
@NotEmpty //不能为空
private String name;

(1)controller 开启校验@Valid
public R save(@Valid @RequestBody BrandEntity brand)

应用 自定义校验(单个处理)

@NotEmpty(message = "品牌名不能为空") //不能为空
private String name;

@NotEmpty
@URL(message = "logo必须是有效的URL")
private String logo;

private String descript;

private Integer showStatus;

@NotEmpty
@Pattern(regexp="/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")//自定义正则表达式
private String firstLetter;

@NotNull
@Min(value = 0,message = "排序必须必须最大于等于0")//最小是0
private Integer sort;


@RequestMapping("/save")//校验后面加一个女BindingResult 可以获取校验结构
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
    if (result.hasErrors()) {
        Map<Object, Object> map = new HashMap<>();
        //获取校验结果
        result.getFieldErrors().forEach((item) -> {
            //获取错误提示
            String message = item.getDefaultMessage();
            //获取错误属性名
            String field = item.getField();
            map.put(field,message);
        });
        //返回R错误提示,并put给map用data封装
        return R.error(400, "提交数据不合法").put("data",map);
    } else {
        brandService.save(brand);
    }
    return R.ok();
}

自定义校验(全局处理) 抽取全局异常类exception

//GulimallExceptionControllerAdvice
@Slf4j
//RestControllerAdvice包含@ControllerAdvice和@ResponseBody
//集中全局处理异常注解并说明处理哪个包
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
    //通过打印日志定位到异常类型的MethodArgumentNotValidException
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildExeption(MethodArgumentNotValidException e){
        //一一对应
        log.error("数据校验出错{},异常类型:{}",e.getMessage(),e.getClass());
        //校验结果 forEach 给errorMap集合
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError)->{
            errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
        });
        //返回输出错误信息
        return R.error(400,"数据校验出错").put("data",errorMap);
    }
}

抽取枚举类处理异常 定义

package com.atguigu.common.exception;
//定义状态码枚举
public enum BizCodeEnume {
    UNKONOW_EXCEPTION(10000,"系统格式校验失败"),
    VAILD_EXCEPTION(10001,"参数格式校验失败");

    private int code;
    private String msg;
    BizCodeEnume(int code,String msg){
        this.code=code;
        this.msg=msg;
    }
    public int getCode(){
        return code;
    }
    public String getMsg(){
        return msg;
    }
}
应用
@ExceptionHandler(value =  Throwable.class)
public R handleException(Throwable throwable){
    return R.error(BizCodeEnume.UNKONOW_EXCEPTION.getCode(),BizCodeEnume.UNKONOW_EXCEPTION.getMsg());
}

多场景分组校验

  • 设置实体类分组校验分组判断时候校验 groups ={UpdateGroup.class,AddGroup.class}
  • controller 设置@Validated({AddGroup.class}) 属于哪一个组
  • 默认没有指定分组的校验注解
//新建两个接口(无需写其他 只是空接口)
common.valid.AddGroup;
common.valid.UpdateGroup;
//实体类groups
public class BrandEntity implements Serializable {
   private static final long serialVersionUID = 1L;
   @NotNull(message = "修改必须指定ID",groups ={UpdateGroup.class})
   @Null(message = "新增不能指定ID",groups ={AddGroup.class})
   @TableId
   private Long brandId;
   
   //修改和新增 都不能为空
   @NotEmpty(message = "品牌名不能为空",groups ={UpdateGroup.class,AddGroup.class})
   private String name;
  
   //新增不能为空  修改或新增必须是有效的地址
   @NotEmpty(message = "logo必须是有效的URL",groups ={AddGroup.class})
   @URL(message = "logo必须是有效的URL",groups ={UpdateGroup.class,AddGroup.class})
   private String logo;
   
   private String descript;
   
   private Integer showStatus;
   
   @NotEmpty(groups ={AddGroup.class})
   @Pattern(regexp="/^[a-zA-Z]$/",message = "检索首字母必须是一个字母",groups ={UpdateGroup.class,AddGroup.class})//自定义正则表达式
   private String firstLetter;
   
   @NotNull(groups ={AddGroup.class})
   @Min(value = 0,message = "排序必须必须最大于等于0",groups ={UpdateGroup.class,AddGroup.class})//最小是0
    private Integer sort;
}
//controller层 @Validated
//新增校验分组@Validated({AddGroup.class})
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand)

//修改校验分组@Validated({UpdateGroup.class})
public R update(@Validated({UpdateGroup.class})@RequestBody BrandEntity brand) 

自定义value

ListValue ListValueConstraintValidator ValidationMessages.properties

@Documented
@Constraint(
        validatedBy = { ListValueConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
    String message() default "{com.atguigu.common.valid.ListValue.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    int[] vals() default {};;
}

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);
        }
    }

    //判断是否校验成功

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {

        return set.contains(value);
    }
}
//ValidationMessages.properties
com.atguigu.common.valid.ListValue.message=必须提交正确数
实体类
@ListValue(vals={0,1,},groups = {AddGroup.class, UpdateStatuesGroup.class})
private Integer showStatus;