小工具知识网

当前位置: 首页 > 行业知识 > Spring Boot 统一数据返回格式 分析 和 处理

行业知识

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

2026-11-08 17:54:26 来源:互联网转载

目录

实现统一数据格式

 测试 

 原因分析

 解决方案


  •  个人主页: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;@ControllerAdvicepublic 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来实现信息的序列化 

    @ControllerAdvicepublic 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 类型的数据    }}

上一篇:Mebi英语怎么读?

下一篇:传奇服务器攻防怎么打的?