应在全局异常处理器(@controlleradvice)中统一返回标准响应,而非在拦截器中直接写响应;拦截器仅负责抛出自定义异常,由异常处理器捕获并封装为result格式。

在 Spring Boot 项目中,自定义异常要在拦截器(如 HandlerInterceptor)中统一返回标准响应结构,关键不是“在拦截器里 throw 异常”,而是**让拦截器感知到异常后,交由全局异常处理器处理**。拦截器本身不负责构造 JSON 响应,它只做预处理或放行;真正统一包装异常响应的,是 @ControllerAdvice + @ExceptionHandler。
为什么不在拦截器里直接返回 JSON?
拦截器运行在 DispatcherServlet 的早期阶段(preHandle),此时 Spring MVC 的异常解析机制(如 ExceptionHandlerExceptionResolver)尚未介入。若你在 preHandle 中手动写入 HTTP 响应体并返回 false,会跳过后续流程,但会导致:
- 响应体未经过消息转换器(如
Jackson2ObjectMapper)序列化,容易出错 - 状态码、Content-Type、日志、统一格式等难以维护
- 与全局异常处理逻辑割裂,违反单一职责
正确做法:拦截器抛异常 → 全局处理器捕获并封装
步骤如下:
- 定义自定义异常,例如
BusinessException extends RuntimeException,可带code和message - 在拦截器的
preHandle中,校验失败时直接throw new BusinessException(1001, "登录已失效") - 编写全局异常处理器,用
@ControllerAdvice拦截该异常,并返回标准结构(如Result<void>.fail(code, msg)</void>)
示例代码片段
自定义异常:
private final int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
// getter 省略
}
拦截器中抛出:
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!isLoginValid(request)) {
throw new BusinessException(401, "用户未登录或 token 已过期");
}
return true;
}
全局异常处理器:
@ControllerAdvicepublic class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseBody
public Result
return Result.fail(e.getCode(), e.getMessage());
}
}
补充说明
如果拦截器中需要区分「业务异常」和「系统异常」,可在自定义异常上加标记接口(如 interface BusinessExceptionMarker),然后在全局处理器中用 @ExceptionHandler(BusinessExceptionMarker.class) 统一捕获。这样即使未来新增多种业务异常,也不用改处理器逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











