首先新建一个全局异常处理类GlobleException,名字可以任取,然后在类上添加@ControllerAdvice或者@RestControllerAdvice注解,这两个注解的作用都是统一处理异常,不同的是,@RestControllerAdvice将处理的异常结果以JSON的形式响应,而@ControllerAdvice则没有指定响应数据类型,如果也想以JSON数据形式响应,可以在方法或者类上添加@ResponseBody注解。此外这两个异常处理注解还有几个默认的属性,我们可使用basePackages属性来指定统一异常处理的范围。例如---@ControllerAdvice(basePackages = "com.atguigu.gulimall.gulimallproduct.controller")
以下为参考示例:
非特定异常处理,直接使用异常父类Exception.class,不推荐直接使用
/*
* 集中处理所有异常
* */
@Slf4j //日志切面
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.gulimallproduct.controller")
public class GlobleExpection {
//异常处理器,可以通过value指定处理异常的类型,可以是多个异常类组成的数组Class<? extends Throwable>[] value() default {}
@ExceptionHandler(value = Exception.class)
public R handleVaildException(Exception e){
log.info("数据校验出现问题:{},异常类型:{}",e.getMessage(),e.getCause());
return R.error();
}
}
特定异常处理,使用特定异常类型MethodArgumentNotValidException.class,可以很好的定制处理特定异常,推荐使用,可以结合上面的一起使用。
/*
* 集中处理所有异常
* */
@Slf4j //日志切面
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.gulimallproduct.controller")
public class GlobleExpection {
//异常处理器,可以通过value指定处理异常的类型,可以是多个异常类组成的数组Class<? extends Throwable>[] value() default {}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e){
Map<String, String> map = new HashMap<>();
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach((item) -> {
String field = item.getField();
String message = item.getDefaultMessage();
map.put(field,message);
});
log.info("数据校验出现问题:{},异常类型:{}",e.getMessage(),e.getCause());
//我们可以写一个常量类或者美剧类,对响应状态码和相应的信息进行判定。方便平时使用
return R.error(400,"出现数据校验异常").put("data",map);
}
}
一般来说,全局异常处理@ExceptionHandler(value = Exception.class)尽量使用精确的异常类,对特定的异常进行特定的处理,不推荐直接使用父类Exception.class
为什么统一异常处理注解命名时@ControllerAdvice而不是其他名字,因为在Resuful风格的程序中,请求的入口和响应的出口都是在controller层,所以想统一处理异常,只要处理响应数据这一层的异常就行,其他层出现异常会向上抛出异常,一直到controller层。