Spring Boot的全局异常处理器如何配置?
在 Spring Boot 中配置全局异常处理器,是实现统一错误响应、提升系统健壮性和可维护性的关键手段。核心使用两个注解:@ControllerAdvice 和 @ExceptionHandler。
下面从 原理、步骤、完整示例、最佳实践 四个方面详细说明。
一、核心原理
-
@ControllerAdvice
是一个组合注解(包含@Component),作用于类上,表示该类是一个全局的控制器增强器。它会自动被 Spring 容器扫描并注册为 Bean,并对所有@Controller或@RestController中抛出的异常进行拦截。 -
@ExceptionHandler
作用于方法上,用于指定该方法处理哪些类型的异常。可以精确到具体异常类(如NullPointerException),也可以处理通用异常(如Exception)。
💡 执行流程:
Controller 抛出异常 → Spring MVC 的DispatcherServlet捕获 → 查找匹配的@ControllerAdvice中的@ExceptionHandler方法 → 执行并返回结果。
二、配置步骤(5 步)
✅ 第 1 步:创建全局异常处理类
package com.example.demo.exception; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; // @RestControllerAdvice = @ControllerAdvice + @ResponseBody @RestControllerAdvice public class GlobalExceptionHandler { // 处理特定异常 @ExceptionHandler(NullPointerException.class) public Result handleNpe(NullPointerException e) { return Result.error("空指针异常: " + e.getMessage()); } // 处理自定义业务异常 @ExceptionHandler(BusinessException.class) public Result handleBusiness(BusinessException e) { return Result.error(e.getCode(), e.getMessage()); } // 兜底处理所有未捕获异常 @ExceptionHandler(Exception.class) public Result handleGeneral(Exception e) { // 生产环境建议不暴露具体异常信息 return Result.error(500, "服务器内部错误"); } }
🔔 注意:
- 使用
@RestControllerAdvice而不是@ControllerAdvice,是为了让返回值自动转为 JSON(相当于每个方法都加了@ResponseBody)。- 如果你返回的是 HTML 页面,则用
@ControllerAdvice。
✅ 第 2 步:定义统一返回格式(推荐)
package com.example.demo.common; import lombok.Data; @Data public class Result<T> { private int code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.code = 200; result.message = "success"; result.data = data; return result; } public static <T> Result<T> error(String message) { return error(500, message); } public static <T> Result<T> error(int code, String message) { Result<T> result = new Result<>(); result.code = code; result.message = message; return result; } }
✅ 第 3 步:(可选)定义自定义业务异常
package com.example.demo.exception; public class BusinessException extends RuntimeException { private int code; public BusinessException(int code, String message) { super(message); this.code = code; } // getter... }
在业务代码中抛出:
if (user == null) { throw new BusinessException(1001, "用户不存在"); }
✅ 第 4 步:确保包路径被扫描到
- 全局异常处理类必须位于 Spring Boot 主启动类所在包或其子包下。
- 否则需显式指定扫描路径:
@SpringBootApplication(scanBasePackages = "com.example") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
✅ 第 5 步:(重要)启用异常转发(处理 404)
默认情况下,访问不存在的 URL 不会抛出异常,而是返回 404 页面。若想让 404 也被全局处理器捕获,需在 application.properties 中添加:
# 当没有找到处理器时,抛出 NoHandlerFoundException spring.mvc.throw-exception-if-no-handler-found=true # 禁用静态资源映射(避免干扰) spring.web.resources.add-mappings=false
然后在全局处理器中添加:
@ExceptionHandler(NoHandlerFoundException.class) public Result handle404() { return Result.error(404, "接口不存在"); }
三、完整示例结构
src/main/java/com/example/demo/
├── DemoApplication.java
├── controller/
│ └── UserController.java
├── exception/
│ ├── GlobalExceptionHandler.java
│ └── BusinessException.java
└── common/
└── Result.java
四、最佳实践建议
| 场景 | 建议 |
|---|---|
| 开发阶段 | 可在 handleGeneral 中返回 e.getMessage() 便于调试 |
| 生产环境 | 隐藏具体异常信息,只返回友好提示,避免信息泄露 |
| 异常分类 | 优先处理具体异常(如 ValidationException, IllegalArgumentException),最后用 Exception 兜底 |
| 日志记录 | 在 @ExceptionHandler 方法中加入 log.error("异常:", e); |
| HTTP 状态码 | 可结合 ResponseEntity 返回不同状态码:return ResponseEntity.status(400).body(Result.error(...)); |
五、常见问题排查
-
全局异常处理器没生效?
- 检查是否被 Spring 扫描到(包路径问题)
- 检查是否缺少
spring-boot-starter-web依赖
-
404 无法被捕获?
- 必须配置
spring.mvc.throw-exception-if-no-handler-found=true
- 必须配置
-
返回的是 HTML 而不是 JSON?
- 确保使用的是
@RestControllerAdvice,而不是@ControllerAdvice
- 确保使用的是
✅ 总结
通过 @RestControllerAdvice + @ExceptionHandler,你可以:
- 统一错误格式
- 避免在每个 Controller 中写 try-catch
- 提升 API 友好性和安全性
- 集中记录异常日志
这是 Spring Boot 项目必备的基础配置之一。
浙公网安备 33010602011771号