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 构建,可直接导入运行。


原始标题:Rendering Exceptions in JSON with Spring