使用 @restcontrolleradvice 结合 @exceptionhandler 注解即可实现全局异常处理并记录日志。在配置类中定义一个被 @restcontrolleradvice 标注的组件,并在其中编写处理特定异常的方法,该方法内调用日志框架(如 slf4j)记录错误信息,最后返回统一的 json 响应对象。这样当控制器抛出未捕获的异常时,spring boot 会自动拦截并执行该逻辑。

如何自定义异常处理器类并绑定到具体异常类型
创建一个 Java 类并使用 @RestControllerAdvice 注解将其声明为全局异常处理器。在该类中定义方法,使用 @ExceptionHandler 指定要处理的异常类,例如 RuntimeException 或自定义的业务异常。方法参数中注入 Exception 对象以获取异常详情,同时可以使用 WebRequest 或 HttpServletRequest 获取请求上下文信息。在方法体内,通过日志记录器输出堆栈跟踪和请求 URL,确保问题可追溯。

import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResponseEntity<string> handleAllExceptions(Exception ex, WebRequest request) {
String url = request.getDescription(false);
logger.error("Global exception occurred at: {}", url, ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error");
}
}</string>
上述代码定义了一个全局异常处理器,它捕获所有未处理的 Exception。当发生异常时,日志会记录请求描述和完整的异常堆栈。返回的 ResponseEntity 包含 HTTP 状态码 500 和简单的错误消息。这种结构确保了无论哪个 Controller 抛出异常,都会被统一处理。
如何区分业务异常与系统异常并记录不同日志级别
在实际开发中,通常需要将预期的业务异常(如参数校验失败、资源不存在)与非预期的系统异常(如空指针、数据库连接超时)区分开。可以定义一个自定义异常类 BusinessException,并在 @RestControllerAdvice 中分别添加针对 BusinessException 和 Exception 的处理方法。对于业务异常,使用 warn 或 info 级别记录日志,因为这是预期内的流程分支;对于系统异常,使用 error 级别记录,因为这代表程序出现了意外故障。

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
// 假设已定义 BusinessException 类
public class BusinessException extends RuntimeException {
public BusinessException(String message) { super(message); }
}
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BusinessException.class)
public ResponseEntity<string> handleBusinessException(BusinessException ex) {
logger.warn("Business logic error: {}", ex.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
}
@ExceptionHandler(Exception.class)
public ResponseEntity<string> handleSystemException(Exception ex) {
logger.error("System error", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("System Error");
}
}</string></string>
这段代码展示了两种异常处理路径。当抛出 BusinessException 时,日志记录警告级别,并返回 400 状态码;当抛出其他 Exception 时,日志记录错误级别,并返回 500 状态码。这种分离有助于运维人员快速判断问题是来自用户输入还是系统内部故障。注意,@ExceptionHandler 的顺序很重要,更具体的异常应放在前面,或者 Spring Boot 会自动匹配最具体的类型。
如果异常发生在过滤器链中而非控制器层该如何处理
全局异常处理器 @RestControllerAdvice 仅能拦截 DispatcherServlet 分发给 Controller 后的异常。如果异常发生在 Filter 或 Servlet 阶段,这些异常不会被 @ExceptionHandler 捕获。此时需要配置 SimpleMappingExceptionResolver 或使用 ErrorController 接口来实现对底层异常的捕获和日志记录。另一种更现代的方式是使用 WebMvcConfigurer 注册自定义的 HandlerExceptionResolver,或者在 Filter 中手动捕获异常并记录日志后转发到错误页面或返回错误响应。











