本文详解如何在 Spring Boot 中正确配置全局异常处理器,解决 @ExceptionHandler 无法捕获并返回自定义错误信息的问题,涵盖注解位置、方法签名规范、响应结构设计及最佳实践。
本文详解如何在 spring boot 中正确配置全局异常处理器,解决 `@exceptionhandler` 无法捕获并返回自定义错误信息的问题,涵盖注解位置、方法签名规范、响应结构设计及最佳实践。
在 Spring Boot 中,异常处理的核心原则是分离关注点:业务逻辑层(如 @RestController)只负责抛出语义明确的异常(如 NotFoundException),而异常的统一拦截与响应格式化应交由专门的全局异常处理器完成。你当前代码中将 @ExceptionHandler 直接写在 @GetMapping 方法上,这是根本性错误——@ExceptionHandler 不能与请求映射注解(如 @GetMapping)共存于同一方法,且必须定义在带有 @ControllerAdvice 或 @RestControllerAdvice 的类中,才能被 Spring MVC 的异常解析器识别。
✅ 正确做法:使用 @RestControllerAdvice
首先,定义一个全局异常处理器类:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND) // 建议使用语义匹配的状态码
public ErrorResponse handleNotFoundException(NotFoundException e) {
return new ErrorResponse("NOT_FOUND", e.getMessage(), System.currentTimeMillis());
}
// 可选:统一处理其他异常(如 RuntimeException)
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleRuntime(Exception e) {
return new ErrorResponse("SERVER_ERROR", "Unexpected error occurred", System.currentTimeMillis());
}
}配套的响应实体类(推荐使用):
public class ErrorResponse {
private String code;
private String message;
private long timestamp;
public ErrorResponse(String code, String message, long timestamp) {
this.code = code;
this.message = message;
this.timestamp = timestamp;
}
// getter 方法(Lombok @Data 可自动省略)
}同时,确保你的自定义异常继承 RuntimeException(非检查异常),以便 Spring 自动传播:
public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}? 关键注意事项
- ❌ 错误示范:@ExceptionHandler 写在 @RestController 的某个接口方法内 → 无效,会被忽略;
- ✅ 正确位置:独立类 + @RestControllerAdvice(对所有 @RestController 生效)或 @ControllerAdvice(需配合 @ResponseBody);
- ✅ 状态码建议匹配业务语义:NotFoundException 应返回 404 NOT_FOUND,而非 500 INTERNAL_SERVER_ERROR;
- ✅ 方法参数必须包含对应异常类型(如 NotFoundException e),否则无法绑定;
- ✅ 返回值可为任意对象(Spring 自动序列化为 JSON),无需手动写 ResponseEntity(除非需精细控制 headers/status)。
✅ 验证效果
当访问 /userino/3 且数据库无 ID=3 的用户时,将返回:
{
"code": "NOT_FOUND",
"message": "Inexistent user 3",
"timestamp": 1715872390123
}而非默认的白页或嵌套错误体。这不仅提升了 API 的专业性,也为前端提供了可解析的结构化错误信息。
? 进阶提示:可通过 @Order(Ordered.HIGHEST_PRECEDENCE) 控制多个 @ExceptionHandler 的优先级;结合 @Valid 和 BindingResult 可统一处理参数校验异常;日志记录建议在 @ExceptionHandler 中添加 log.error("API exception", e) 便于追踪。

















