问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Spring Boot 3.x Rest API最佳实践:统一响应结构

创作时间:
作者:
@小白创作中心

Spring Boot 3.x Rest API最佳实践:统一响应结构

引用
CSDN
1.
https://blog.csdn.net/felix_alone2012/article/details/141032180

在开发RESTful API时,统一的响应结构可以提高系统的稳定性和可维护性。本文将详细介绍如何在Spring Boot 3.x中实现统一的响应结构,包括定义响应类、实现响应体拦截以及进行API测试。

定义Response

首先,我们需要定义一个通用的响应类Response,用于封装所有API的响应数据。这个类使用了Lombok注解来简化代码,同时使用Jackson的@JsonInclude注解来控制JSON序列化时的空值处理。

package com.juan.demo.common.dto;
import ...
@Getter
@Setter
@ToString
public class Response<T> {
    /** 响应状态:0-成功 1-失败 */
    private Integer status;
    /** 实际数据 */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private T data;
    private static final Integer STATUS_SUCCESS = 0;
    public Response() {}
    private Response(Integer status, T data) {
        this.status = status;
        this.data = data;
    }
    public static <T> Response<T> ok(T data) {
        return new Response<>(STATUS_SUCCESS, data);
    }
    public static <T> Response<T> ok() {
        return ok(null);
    }
    public static void main(String[] args) {
        System.out.println(Response.ok());
        System.out.println(Response.ok(new ProductResultItemDTO(1L, "spring boot3入门", 30000)));
    }
}

这个类主要考察了泛型的使用,通过构造器重载和静态方法重载,提供了灵活的实例化方式。同时,为了防止外部随意创建实例,除了无参构造器外,其他构造器都被设置为私有。如果数据域为null,则不会参与JSON序列化。

响应体拦截

为了对所有REST控制器的响应结果进行统一处理,我们需要实现ResponseBodyAdvice接口。这个接口允许我们在响应体写入之前进行拦截和修改。

package com.juan.demo.common.web.support;
import ...
@Slf4j
@RestControllerAdvice
public class RestBodyAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return Response.ok(body);
    }
}

通过@RestControllerAdvice注解,我们可以确保这个拦截器作用于所有REST控制器。在beforeBodyWrite方法中,我们使用Response.ok(body)来包装原始的响应数据。

但是,当API返回值为String类型时,会遇到类型转换异常。这是因为Web框架在解析方法返回值时已经决定将其作为字符串响应。为了解决这个问题,我们需要在beforeBodyWrite方法中添加对String类型的特殊处理:

package com.juan.demo.common.web.support;
import ...
@Slf4j
...
public class RestBodyAdvice implements ResponseBodyAdvice<Object> {
    @Resource
    private ObjectMapper objectMapper;
    ...
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(...) {
        // 获取api返回值类型
        Type type = returnType.getGenericParameterType();
        log.info("type = {}", type);
        // 如果已经是字符串,则手动json序列化,并将内容类型重置为json格式,默认是普通文本格式
        if (type == String.class) {
            response.getHeaders().set("Content-Type", MediaType.APPLICATION_JSON_VALUE);
            return objectMapper.writeValueAsString(Response.ok(body));
        }
        ...
    }
}

通过上述调整,我们可以确保所有API响应都符合统一的JSON结构。

Rest API测试

经过上述配置后,我们可以测试之前的API是否正常工作。从测试结果来看,所有API都返回了统一的JSON结构,如下图所示:

其他API的测试留给读者自行验证。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号