java中拦截器不能直接try-catch自定义异常,因其不包裹controller执行;应由@controlleradvice统一处理,拦截器仅负责预检与上下文准备。

Java 中自定义异常可以在拦截器中统一捕获处理,关键在于:拦截器需在 afterCompletion 或更合适的时机(实际常用 preHandle 配合 try-catch + 异常转发)之外,**依赖 Spring 的统一异常处理机制(@ControllerAdvice + @ExceptionHandler)来接管,而非在拦截器里“主动捕获”运行时抛出的异常**。因为拦截器本身不直接包裹 Controller 方法执行,它无法用常规 try-catch 捕获 Controller 中抛出的异常。
为什么不能在拦截器里直接 try-catch 自定义异常
拦截器的 preHandle 在 Controller 执行前调用,postHandle 在 Controller 执行后、视图渲染前调用,afterCompletion 在整个请求完成后调用——但 Controller 中抛出的异常会绕过 postHandle,直接进入 Spring 的异常分发流程,afterCompletion 的 Exception ex 参数虽能拿到异常,但此时响应已提交或即将提交,不适合做业务级错误响应(如返回 JSON 错误体)。
推荐做法:拦截器 + 全局异常处理器协同
让拦截器专注「预检」和「上下文准备」,把异常处理交给更专业的 @ControllerAdvice:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 定义自定义异常,继承
RuntimeException(非检查异常,使用更灵活):public class BizException extends RuntimeException { private int code; public BizException(int code, String message) { super(message); this.code = code; } // getter... } - 在 Controller 或 Service 中按需抛出:
if (user == null) { throw new BizException(4001, "用户不存在"); } - 编写全局异常处理器,统一响应格式:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BizException.class) @ResponseBody public Result> handleBizException(BizException e) { return Result.fail(e.getCode(), e.getMessage()); } }
拦截器中可做的补充工作
如果需要在拦截器中「感知」某些异常条件并提前拦截(比如鉴权失败),应主动判断、不依赖抛异常:
- 在
preHandle中校验 Token,发现无效时直接设置响应并返回false,阻止后续执行:if (!tokenValid) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(JSON.toJSONString(Result.fail(401, "未授权"))); return false; // 请求终止 } - 避免在拦截器里 throw BizException——这仍会触发全局处理器,但属于冗余设计,且破坏拦截器职责边界。
进阶:结合 HandlerExceptionResolver(较少用)
若必须在拦截器同层处理异常(如老旧项目未用 @ControllerAdvice),可实现 HandlerExceptionResolver,在 resolveException 中识别自定义异常并写响应。但这是 Spring MVC 底层扩展方式,现代项目优先选 @ControllerAdvice。
不复杂但容易忽略:拦截器不是异常捕获的主战场,它是请求生命周期的“守门人”;真正的异常归宿,是全局异常处理器。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










