使用 @restcontrolleradvice 配合 @exceptionhandler 可以统一拦截并处理 spring boot 应用中的 500 错误。具体做法是定义一个全局异常处理器类,在其中编写处理 exception 或 runtimeexception 的方法,该方法返回自定义的响应体对象,从而将原始的堆栈信息转化为标准的 json 格式返回给客户端。

如何捕获所有未处理的运行时异常
通过在全局异常处理器中声明 @ExceptionHandler(RuntimeException.class),可以捕获所有未被业务层 catch 的运行时异常。当控制器抛出此类异常时,Spring MVC 会将其转发到该处理方法,进而执行统一的错误逻辑。

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ErrorResponse handleRuntime(RuntimeException e) {
return new ErrorResponse(500, "Internal Server Error", e.getMessage());
}
}
上述代码定义了一个名为 GlobalExceptionHandler 的类,它使用了 @RestControllerAdvice 注解,这意味着它会扫描所有的 Controller 并拦截异常。方法 handleRuntime 专门处理 RuntimeException 类型的异常。当发生 500 错误时,该方法会实例化一个 ErrorResponse 对象,其中包含状态码、错误消息和具体的异常详情。这个对象会被自动序列化为 JSON 响应。
如何处理特定业务异常以区分错误类型
除了通用的运行时异常,通常还需要针对特定的业务场景(如参数校验失败、资源不存在)定义专门的异常类,并在同一个全局处理器中进行分类处理。这样可以为不同的错误返回更精确的状态码和提示信息,而不是全部返回 500。

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ErrorResponse handleNotFound(ResourceNotFoundException e) {
return new ErrorResponse(404, "Not Found", e.getMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public ErrorResponse handleBadRequest(IllegalArgumentException e) {
return new ErrorResponse(400, "Bad Request", e.getMessage());
}
}
在上面的代码中,我们添加了两个新的异常处理方法。第一个方法 handleNotFound 专门处理 ResourceNotFoundException,这通常用于表示请求的资源不存在,因此返回 404 状态码。第二个方法 handleBadRequest 处理 IllegalArgumentException,这通常用于参数校验不通过的情况,返回 400 状态码。这种细粒度的处理方式使得前端能够根据状态码和消息做出更准确的反馈。注意,这些特定的异常处理必须放在通用 RuntimeException 处理之前,或者确保它们被更具体的异常类型匹配,否则通用的处理器可能会先捕获它们。
全局异常处理对日志记录的影响
在全局异常处理器中记录日志是一个关键步骤,有助于排查生产环境中的问题。通过在异常处理方法中添加日志记录语句,可以保留异常的完整堆栈信息,而不仅仅是返回给客户端的简短消息。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ErrorResponse handleAll(Exception e) {
log.error("An unexpected error occurred", e);
return new ErrorResponse(500, "Internal Server Error", "An unexpected error occurred");
}
}
这段代码展示了如何在 handleAll 方法中使用 SLF4J 记录错误日志。通过调用 log.error 并传入异常对象 e,框架会自动记录完整的堆栈跟踪信息到日志文件中。这对于调试至关重要,因为客户端收到的消息通常是脱敏后的,不包含详细的内部错误原因。同时,返回给客户端的消息保持简洁,避免泄露敏感的内部实现细节。


















