• ResponseBodyAdvice接口使用导致的报错及解决


    一、ResponseBodyAdvice使用

    ResponseBodyAdvice用于在返回值写入响应之前,将body的内容重新封装,直接上代码

    1.1 CommonResponseDataAdvice

    @Component
    public class CommonResponseDataAdvice implements ResponseBodyAdvice<Object> {
        private static final String V_3_API_DOCS = "/v3/api-docs";
        private static final String SWAGGER_RESOURCES = "/swagger-resources";
        private static final String ADMIN_ACTUATOR = "/actuator";
    
        public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
            if (methodParameter.getAnnotatedElement().isAnnotationPresent(IgnoreResponseAdvice.class)) {
                return false;
            } else {
                return !methodParameter.getMethod().isAnnotationPresent(IgnoreResponseAdvice.class);
            }
        }
    
        @Nullable
        public Object beforeBodyWrite(@Nullable Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            //避免对swagger的api接口返回值进行封装
            if (((ServletServerHttpRequest) serverHttpRequest).getServletRequest().getRequestURI().equals(V_3_API_DOCS)) {
                return o;
            }
            if (((ServletServerHttpRequest) serverHttpRequest).getServletRequest().getRequestURI().contains(SWAGGER_RESOURCES)) {
                return o;
            }
            //避免对actuator的监控接口进行封装
            if (((ServletServerHttpRequest) serverHttpRequest).getServletRequest().getRequestURI().contains(ADMIN_ACTUATOR)) {
                return o;
            }
            if (o instanceof Result) {
                return o;
            }
            return new Result<>(0, "",o);
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    关键方法beforeBodyWrite,在SpringMVC主流程有讲到
    在这里插入图片描述
    它将被调用,从而将返回值封装到自定义的Result里面,方便前端统一处理状态码。

    二、报错及解决

    2.1 集成swagger报错

    在集成swagger之后,始终报错,接口文档出不来,出现如下错误信息:

    Unable to render this definition
    The provided definition does not specify a valid version field.
    Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: “2.0” and those that match openapi: 3.0.n (for example, openapi: 3.0.0).

    百度了半天没有用,最后检查/v3/api-docs接口发现返回值被封装之后,swagger的前端无法解析自定义的结构,导致报错。
    解决方案: 判断特定的接口路径不做封装

    2.2 接口直接返回String类型报错

    定义一个接口

    @GetMapping("/getUserName")
        @ApiOperation("根据ID获取用户")
        public String getUserName() {
            return "username";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用Swagger发送请求
    在这里插入图片描述
    报错了,说是Result无法强转为String,没办法只能从源码找解决方案,根据SpringMVC主流程,关键地方还是在这里
    在这里插入图片描述
    Spring提供了10个消息转换器,String在Json的前面。调用beforeBodyWrite方法之后
    在这里插入图片描述
    先匹配到转换器StringHttpMessageConverter,又将body封装成Result类型
    在这里插入图片描述
    StringHttpMessageConverter的泛型是String,进入write方法之后
    在这里插入图片描述
    t的类型是Result,子类中的addDefaultHeaders方法需要的是String
    在这里插入图片描述
    导致类型强转异常
    解决方案: 接口的返回String类型时,提前用Result封装。不能在beforeBodyWrite判断是StringHttpMessageConverter就不封装,因为StringHttpMessageConverter转换完就返回,Json转换器就用不上了。

    @GetMapping("/getUserName")
        @ApiOperation("根据ID获取用户")
        public Result<String> getUserName() {
            return new Result<>("username");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    js 判断数据类型
    Node.js简介
    G2O学习笔记
    python爬虫开源项目代码基于Python实现的数据分析系统
    微信公众号如何变更为订阅号?
    【LeetCode】1769.移动所有球到每个盒子所需的最小操作数
    Arduino从零开始(0)——介绍与点亮LED
    深度学习六十年简史
    Java GUI实现贪吃蛇游戏
    一键解决Win10 LTSC 2021官方镜像存在的问题
  • 原文地址:https://blog.csdn.net/yx444535180/article/details/125911407