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. 有利于后端技术部⻔的统⼀规范的标准制定, 不会出现稀奇古怪的返回内容.

相关推荐
华仔啊12 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang13 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
用户83071968408213 小时前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Ray Liang14 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解14 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SimonKing18 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean18 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven9720 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林5511 天前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河1 天前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化