使用 Spring Boot ResponseBodyAdvice 处理统一响应

在现代的 RESTful API 设计中,返回一致的响应格式对客户端的兼容性和可维护性至关重要。为了解决这个问题,我们可以使用 Spring Boot 中的 ResponseBodyAdvice 接口。本文将介绍如何通过实现 ResponseBodyAdvice 接口来统一处理 API 的响应格式,以便更好地服务于前端需求。

背景

在很多场景下,我们的 API 可能会向客户端返回不同类型的响应,例如成功、错误、分页等。为避免多重条件判断,我们可以通过 ResponseBodyAdvice 来实现统一响应格式化。例如,我们希望所有的返回数据都在一个统一的响应结构中,比如:

{
    "code": 200,
    "message": "成功",
    "data": { ... }
}

这样的结构清晰而易于维护。

ResponseBodyAdvice 接口概述

ResponseBodyAdvice 是 Spring MVC 提供的一个接口,可以在处理完请求后,对返回的结果进行加工。我们可以实现该接口以改变返回内容。

接口方法

  • supports: 判断是否支持该类型的响应。
  • beforeBodyWrite: 在响应体写入之前处理响应内容。

示例代码

下面是一个简单的示例,演示如何使用 ResponseBodyAdvice 来统一响应格式。

1. 创建统一响应类

首先,我们需要一个响应类来封装我们的返回数据。

public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;

    public ApiResponse(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    // Getters and Setters
}

2. 实现 ResponseBodyAdvice

接着,我们实现 ResponseBodyAdvice 来格式化响应。

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 仅支持指定的返回类型,或者你想要支持的条件
        return true; // 这里简单返回true,表示支持所有返回类型
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                   Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                   ServerHttpRequest request, ServerHttpResponse response) {

        // 如果body是ApiResponse类型,直接返回
        if (body instanceof ApiResponse) {
            return body;
        }

        // 封装为ApiResponse
        return new ApiResponse<>(200, "成功", body);
    }
}

3. 测试 API

在控制器中定义一个简单的 API:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user")
    public User getUser() {
        return new User("John Doe", 25);
    }
}

4. 运行与测试

启动应用后,访问 /user 接口,你将得到如下响应:

{
    "code": 200,
    "message": "成功",
    "data": {
        "name": "John Doe",
        "age": 25
    }
}

关系图

使用mermaid语法表示类之间的关系:

erDiagram
    API_RESPONSE {
        int code
        string message
        object data
    }
  
    USER {
        string name
        int age
    }
  
    API_RESPONSE ||--o{ USER : contains

类图

使用mermaid语法表示类结构:

classDiagram
    class ApiResponse {
        +int code
        +string message
        +T data
        +ApiResponse(int code, string message, T data)
    }

    class User {
        +string name
        +int age
    }

    class ApiResponseAdvice {
        +boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType)
        +Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response)
    }

    ApiResponseAdvice --> ApiResponse
    ApiResponse --> User

结尾

通过实现 ResponseBodyAdvice 接口,我们能够轻松地统一我们的 API 响应格式,从而提高 API 的可维护性和使用体验。此外,这种方式也便于我们后续的拓展,例如在需要时添加统一错误处理逻辑等。

希望本文能帮助到需要自定义 Spring Boot API 响应的开发者。如果有其他问题或需要更深入的探讨,欢迎留言交流!