在Spring MVC中,拦截器(Interceptor)抛出的异常默认无法被@RestControllerAdvice
捕获,因为拦截器的执行时机早于控制器方法。以下是几种解决方案:
1. 在拦截器内部直接处理异常
在拦截器中捕获异常,并手动设置响应内容,确保与全局异常处理的格式一致。
示例代码:
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
try {
// 业务逻辑
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write("{\"code\": 401, \"message\": \"Unauthorized\"}");
return false; // 中断后续流程
}
return true;
}
}
2. 自定义 HandlerExceptionResolver
通过实现HandlerExceptionResolver
接口,统一处理拦截器抛出的异常。
步骤:
- 创建自定义异常解析器:
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof CustomException) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
// 返回统一的JSON响应
String json = "{\"code\": 400, \"message\": \"Bad Request\"}";
try {
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
}
return null; // 其他异常由默认机制处理
}
}
- 注册自定义解析器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
resolvers.add(0, new CustomExceptionResolver());
}
}
3. 通过请求转发触发 @RestControllerAdvice
将异常转发到控制器方法,利用现有全局异常处理机制。
步骤:
- 在拦截器中转发请求:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
try {
// 业务逻辑
} catch (Exception e) {
request.setAttribute("exception", e);
request.getRequestDispatcher("/error/interceptor").forward(request, response);
return false;
}
return true;
}
- 定义错误处理端点:
@RestController
public class ErrorController {
@GetMapping("/error/interceptor")
public void handleInterceptorError(HttpServletRequest request) throws Exception {
throw (Exception) request.getAttribute("exception");
}
}
@RestControllerAdvice
处理异常:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllExceptions(Exception ex) {
// 返回统一响应格式
return new ResponseEntity<>(...);
}
}
总结选择
- 直接处理:适合简单场景,但需手动维护响应格式。
- 自定义解析器:灵活且集中管理异常,适合需要统一处理多种异常的情况。
- 请求转发:复用现有
@RestControllerAdvice
逻辑,但增加额外请求跳转。
根据项目结构选择最合适的方法,通常推荐方案1或方案2以确保代码简洁和可维护性。