1. 引言
Spring 在构建 RESTful API 时表现非常出色,尤其是处理正常流程的业务逻辑时非常得心应手。
但问题来了:当事情出错时,我们该怎么优雅地处理异常?
本文将介绍如何使用 Spring,将 Java 异常以 JSON 格式返回给客户端。这在构建健壮的 REST API 时非常关键。
如果你想更全面地了解 Spring 的异常处理机制,可以参考我们的两篇文章:Spring REST 异常处理全解析 和 Java 全局异常处理器实战。
2. 基于注解的解决方案
我们主要会用到三个 Spring MVC 注解来实现这个功能:
✅ @RestControllerAdvice
- 内部组合了
@ControllerAdvice
和@ResponseBody
- 用于将异常处理器注册为全局组件,适用于所有
@Controller
@ResponseBody
确保返回值自动序列化为 JSON
✅ @ExceptionHandler
- 用于指定某个方法处理特定类型的异常
✅ @ResponseStatus
(可选)
- 可以指定返回给客户端的 HTTP 状态码,比如 500 Internal Server Error
这三个注解配合使用,就可以创建一个 Spring Bean 来统一处理异常,并返回结构化的 JSON 错误信息。
3. 示例代码
3.1 定义一个自定义异常
我们先定义一个简单的自定义异常类:
public class CustomException extends RuntimeException {
public CustomException() {
super();
}
public CustomException(String message, Throwable cause) {
super(message, cause);
}
public CustomException(String message) {
super(message);
}
public CustomException(Throwable cause) {
super(cause);
}
}
3.2 定义全局异常处理器
接下来是异常处理器类:
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CustomException handleCustomException(CustomException ce) {
return ce;
}
}
⚠️ 注意:
@ResponseStatus
指定了返回的 HTTP 状态码为 500- 返回值是
CustomException
实例,Spring 会自动将其转换为 JSON @RestControllerAdvice
会自动加上@ResponseBody
,所以不用再额外加
3.3 示例 Controller
最后是一个简单的 Controller 示例,演示如何抛出异常:
@Controller
public class MainController {
@GetMapping("/")
public void index() throws CustomException {
throw new CustomException("Something went wrong");
}
}
当访问 /
接口时,会触发异常,Spring 会自动调用 ErrorHandler
中的处理方法,最终返回类似如下 JSON 响应:
{
"message": "Something went wrong",
"cause": null,
"stackTrace": [...],
"suppressedExceptions": []
}
4. 小结与建议
本文演示了如何在 Spring 中通过 @RestControllerAdvice
和 @ExceptionHandler
捕获异常,并将其以 JSON 格式返回给客户端。
✅ 推荐做法:
- 自定义异常类建议包含错误码、错误信息、时间戳等字段,以构建更清晰的错误响应结构
- 可以结合
@ControllerAdvice
实现全局异常处理,避免重复代码 - 对于 REST API,推荐始终使用
@RestControllerAdvice
而不是@ControllerAdvice
+@ResponseBody
的组合,更简洁
⚠️ 踩坑提醒:
- 不要直接返回
Throwable
或其子类实例,否则会暴露堆栈信息,建议封装为统一的ErrorResponse
对象 - 避免在生产环境中返回详细的异常堆栈,容易造成信息泄露
完整代码示例可以在 GitHub 仓库 中找到,该项目基于 Maven 构建,可直接导入运行。