SpringBoot之统一数据返回格式

目录

统一数据返回格式

使用

定义测试接口

运行结果

问题解答(结合源码)

解决方法:对返回类型为String类型的字符串进行序列化

优点


之前我们实现的图书管理系统,函数的返回值格式都不统一,如果将这些函数的返回值格式都进行统一,将方便后续的返回和接收,但是如果我们挨个修改这些函数的返回值格式,有些麻烦,那么有没有别的好的办法呢?----有,就是下面我们要讲解的"SpringBoot之统一数据返回格式"。

统一数据返回格式

使用

统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现

@ControllerAdvice 表⽰控制器通知类。

定义类 ResponseAdvice , 实现 ResponseBodyAdvice 接⼝, 并在类上添加

@ControllerAdvice 注解。

java 复制代码
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result){
            return body;
        }

        return Result.success(body);
    }
}

运行结果:

定义测试接口
java 复制代码
@RequestMapping("/test")
@RestController
public class TestController {
    @RequestMapping("/t1")
    public String t1(){
        return "string";
    }

    @RequestMapping("/t2")
    public Integer t2(){
        return 1;
    }

    @RequestMapping("/t3")
    public Boolean t3(){
        return true;
    }

}
运行结果

t2返回结果:

t3返回结果:

t1返回结果:

为什么其他方法都能够正常返回,而返回类型为String时却不能正常返回,而且还抛出了ClassCastException异常,这是为什么呢?

问题解答(结合源码)

根据IDEA控制台打印的堆栈信息,我们首先看看StringHttpMessageConverter和AbstractHttpMessageConverter这两个类,特别是StringHttpMessageConverter的addDefaultHeaders方法和AbstractHttpMessageConverter的write方法,其中StringHttpMessageConverter是继承了AbstractHttpMessageConverter并重写了几个方法,特别是addDefaultHeaders方法,下面通过Debug方式运行:

再继续运行,会捕获到异常

由此我们知道,是因为返回结果为String类型的"string"被转换成了Result类型,但是在执行AbstractHttpMessageConverter的write方法时,因为AbstractHttpMessageConverter的派生类StringHttpMessageConverter重写了addDefaultHeaders方法,此时会调用StringHttpMessageConverter的addDefaultHeaders方法,但是StringHttpMessageConverter的addDefaultHeaders方法要求 t 的类型是String类型,但是无法从自定义的Result类型转换成String类型,因此抛出了ClassCastException异常。

那么问题来了,上面的三个测试接口,走的都是Result.success()方法,为什么却有不一样的结果,通过调试:

对于返回类型为String类型,在AbstractMessageConverterMethodProcessor里面的writeWithMessageConverters()方法时,在经过下图所示过程中,String类型会被转换成Result类型的结果,而且后面走的是StringHttpMessageConverter的addDefaultHeaders方法,其中StringHttpMessageConverter重写了AbstractHttpMessageConverter的addDefaultHeaders方法;

而返回值类型不是String类型时,经过和刚刚同样的步骤时,直接走的是AbstractHttpMessageConverter的addDefaultHeaders方法,而没有走StringHttpMessageConverter的addDefaultHeaders方法。

解决方法:对返回类型为String类型的字符串进行序列化
java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import springbook.model.Result;

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result){
            return body;
        }
        if (body instanceof String){
            return objectMapper.writeValueAsString(Result.success(body));
        }
        return Result.success(body);
    }
}

运行结果:

优点
  1. ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据

  2. 降低前端程序员和后端程序员的沟通成本, 按照某个格式实现就可以了, 因为所有接⼝都是这样返回的.

  3. 有利于项⽬统⼀数据的维护和修改.

  4. 有利于后端技术部⻔的统⼀规范的标准制定, 不会出现稀奇古怪的返回内容.

相关推荐
Pluchon1 天前
Java个人综合项目——萌部落社区V2.0
java·python·spring·spring cloud·postman·idea
梦雨生生1 天前
java开发工具(学习第一天)
java·开发语言·学习
她说可以呀1 天前
Spring-ai-alibaba文生图
java·人工智能·spring
松仔log1 天前
Java中级——组合和继承
android·java·开发语言
不才不才不不才1 天前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
snow@li1 天前
HikariCP:高性能数据库连接池全景深入梳理
java·数据库
sugar__salt1 天前
Spring 三层架构与 IoC、依赖注入完全指南
java·spring boot·后端·spring·架构·maven·intellij-idea
edwarddamon1 天前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
Raas1001 天前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
evans在进步1 天前
Spring AI 从入门到实战:用 Java 实现大模型对话与 Tool Calling
java·人工智能·spring