背景:为避免Controller层重复的处理业务层抛出的异常,减少代码冗余,需要统一处理全局异常。
借助ControllerAdvice 、ExceptionHandler实现
在spring 3.2中,新增了ControllerAdvice 注解,用于拦截的Controller的异常,配合ExceptionHandler可以实现对不同异常的差异处理。拦截的规则参考spring源码包中@ControllerAdvice的定义,常用的规则是按照包路径和注解(basePackages、annotations)来匹配目标并处理。
前置条件:Spring框架的版本为4.1.7.RELEASE
// 定义controller增强器
@ControllerAdvice(annotations = ApiServiceTarget.class)
public class ApiServiceTargetExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public DefaultResponse handleBusinessException(BusinessException e) {
// todo
return new DefaultResponse ();
}
@ExceptionHandler(Exception.class)
@ResponseBody
public DefaultResponse handleException(Exception e) {
// todo
return new DefaultResponse ();
}
}
踩过的坑
在4.1.7.RELEASE版本,开始尝试时,将@ResponseBody加在了类上,而不是方法上,导致虽然可以拦截到异常,但是调用方(如RestTemplate.postForObject)不会接收到异常处理方法(handleBusinessException)返回的数据,而是会捕获到HTTP 405异常(HttpClientErrorException.MethodNotAllowed: 405 Method Not Allowed)。
高版本Spring(v5.1.4)提供了新的注解RestControllerAdvice,它是ControllerAdvice和ResponseBody的组合,直接将其加在类上,就无需在每一个方法上添加@ResponseBody注解了,其定义如下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice{...}