Spring Boot 统一数据返回格式 分析 和 处理

目录

实现统一数据格式

 测试 

 原因分析

 解决方案


  • 🎥 个人主页:Dikz12
  • 📕格言:吾愚多不敏,而愿加学
  • 欢迎大家👍点赞✍评论⭐收藏

实现统一数据格式

统⼀的数据返回格式使⽤ @ControllerAdvice ResponseBodyAdvice 的⽅式实现;
@ControllerAdvice : 表⽰控制器通知类.
比如:添加类 ResponseAdvice , 实现 ResponseBodyAdvice 接⼝, 并在类上添加
@ControllerAdvice 注解.
import com.example.demo.model.Result;
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;

@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) {
        return Result.success(body); //返回 Result 类型的数据
    }
}

 supports⽅法: 判断是否要执⾏beforeBodyWrite⽅法. true为执⾏, false不执⾏. 通过该⽅法可以 选择哪些类或哪些⽅法的response要进⾏处理, 其他的不进⾏处理.

beforeBodyWrite⽅法:对response⽅法进⾏具体操作处理.

 测试 

 写一些不同的返回结果,看看哪些会出现问题!

import com.example.demo.model.BookInfo;
import com.example.demo.model.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public Integer t1() {
        return 12334;
    }

    @RequestMapping("/t2")
    public String t2() {
        return "hello";
    }

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

    @RequestMapping("/t4")
    public BookInfo t4() {
        return new BookInfo();
    }

    @RequestMapping("/t5")
    public Result t5() {
        return Result.success("success");
    }
}

1.返回结果为Integer,可以正确响应.

 

2.返回结果为String,结果显示内部错误.

 

 控制台查看日志:

3.返回结果为Boolean,可以正常响应.

 

 4.返回结果为BookInfo对象,可以正常响应.

5.返回结果为Result,发现又进行了一次封装.

  

 问题:1.返回结果为String,不能正常进行处理了;2.返回结果为Result,又多进行了一次封装.

 原因分析

这时候就会非常纳闷了,为什么就处理String的时候会出错呢?就不得不去看源码分析了.

SpringMVC (也就是在初始化时) 默认会注册⼀些⾃带的 HttpMessageConverter (转换器) (从先后顺序排列分别为 ByteArrayHttpMessageConverter , StringHttpMessageConverter , SourceHttpMessageConverter , SourceHttpMessageConverter , AllEncompassingFormHttpMessageConverter )


 这些转换器是有先后顺序的,是用ArrayList存储的.会根据我们的返回结果挨个判断使用哪个转换器!!!

此时,就会发现问题就出现在 StringHttpMessageConverter.

处理的内容主要是在AbstractMessageConverterMethodProcessor 中 会有一个writeWithMessageConverters()方法.

通过getAdvice()拿到了beforBodyWrite 就会对body进行处理,处理完之后并没有结束(body变成了Result类型),此时,也并没有出错。会继续执行((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage).

 由于 StringHttpMessageConverter 重写了addDefaultHeaders⽅法, 所以会执⾏⼦类的⽅法

然⽽⼦类 StringHttpMessageConverter 的addDefaultHeaders⽅法定义接收参数为String, 此

时t为Result类型, 所以出现类型不匹配" Result cannot be cast to java.lang.String "的异常.

 解决方案

1.当返回结果为Result时,就直接返回body.

2.当返回结果为String时,采用SpringBoot内置提供的Jackson来实现信息的序列化 

@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) {
        //body 是返回的结果
        //当返回结果为Result类型时,就直接返回body
        if (body instanceof Result) {
            return body;
        }
        //返回结果为String类型, 使⽤SpringBoot内置提供的Jackson来实现信息的序列化
        if (body instanceof String) {
            return objectMapper.writeValueAsString(Result.success(body));
        }
        return Result.success(body); //返回 Result 类型的数据
    }
}

相关推荐

  1. SpringBoot 统一后端返回格式处理全局异常

    2024-03-29 20:32:03       41 阅读
  2. Springboot 中设置统一返回格式

    2024-03-29 20:32:03       46 阅读
  3. SpringBoot 自定义异常返回数据格式

    2024-03-29 20:32:03       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-29 20:32:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-29 20:32:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-29 20:32:03       82 阅读
  4. Python语言-面向对象

    2024-03-29 20:32:03       91 阅读

热门阅读

  1. 蓝桥杯备考随手记: practise01

    2024-03-29 20:32:03       43 阅读
  2. 超声波雷达探测车位及信号处理方法

    2024-03-29 20:32:03       43 阅读
  3. C#程序结构详解

    2024-03-29 20:32:03       34 阅读
  4. 单元测试(UT)用例简介

    2024-03-29 20:32:03       41 阅读
  5. pod反亲和配置【软亲和和硬亲和】

    2024-03-29 20:32:03       38 阅读
  6. 力扣 1.两数之和

    2024-03-29 20:32:03       32 阅读
  7. 学习笔记(16)函数防抖和节流

    2024-03-29 20:32:03       35 阅读
  8. 制造业上云解决方案

    2024-03-29 20:32:03       40 阅读
  9. 低代码与数智化OA:重塑企业办公新生态

    2024-03-29 20:32:03       49 阅读
  10. Unity Shader——透明效果

    2024-03-29 20:32:03       39 阅读