Spring boot ResponseBodyAdvice接口全局统一返回控制,Api返回值是String 类型时异常

news2024/11/16 19:24:26

ResponseBodyAdvice简介

在大部分前后端分离项目中,后端的返回值基本都需要包装成一个GlobalResponse,其中属性有code、message、data等,来供前端使用。这样就导致大部分Api写完后都需要手动构建一个GlobalResponse对象并填充属性返回,也就造成了大量的重复代码。

  这类代码其实有很方便的处理方式,就是使用spring提供的responseBodyAdvice接口,同样有 responseBodyAdvice,就有 requestBodyAdvice。

requestBodyAdvice —— 请求体的统一处理器,一般用来对请求参数做一些统一的解密等。

responseBodyAdvice —— 响应体的统一处理器,一般用来统一返回值使用。

异常现象

在我们系统中定义一个类,实现responseBodyAdvice接口,配合@RestControllerAdvice注解就可以实现全局统一返回了,在实际使用中遇到一个问题,如果Api方法返回值 是String 类型时抛出异常。其他的目前一切正常,错误信息:

java.lang.ClassCastException: com.cxm.common.entrity.response.GlobalResponse cannot be cast to java.lang.String
    at org.springframework.http.converter.StringHttpMessageConverter.getContentLength(StringHttpMessageConverter.java:43)
    at org.springframework.http.converter.AbstractHttpMessageConverter.addDefaultHeaders(AbstractHttpMessageConverter.java:260)
    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:211)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:293)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.github.xiaoymin.swaggerbootstrapui.filter.SecurityBasicAuthFilter.doFilter(SecurityBasicAuthFilter.java:81)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.github.xiaoymin.swaggerbootstrapui.filter.ProductionSecurityFilter.doFilter(ProductionSecurityFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.cxm.interceptor.CxmRequestValidFilter.doFilter(CxmRequestValidFilter.java:94)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.cxm.interceptor.GzipRequestFilter.doFilter(GzipRequestFilter.java:26)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

源码解析

经过调试发现Spring 的HttpMessageConverter有11个:

[org.springframework.data.web.ProjectingJackson2HttpMessageConverter@21b07f0c,
 org.springframework.http.converter.ByteArrayHttpMessageConverter@3404df71,
  org.springframework.http.converter.StringHttpMessageConverter@125c42e3, 
  org.springframework.http.converter.StringHttpMessageConverter@24851f5c,
   org.springframework.http.converter.ResourceHttpMessageConverter@43fe325e, 
org.springframework.http.converter.ResourceRegionHttpMessageConverter@51939207,
 org.springframework.http.converter.xml.SourceHttpMessageConverter@21a8998c, 
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter@2ddb0d1a,
 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@1f05b63d, 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@524b1c70, 
org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter@37ca8b4c]

问题就出在StringHttpMessageConverter上面

具体的代码可以参考AbstractMessageConverterMethodProcessor类的writeWithMessageConverters方法

有问题的地方就出现在标记的地方write方法,调用AbstractHttpMessageConverter的write方法

接着会调用addDefaultHeaders

getContentLength有多个类实现,其中有一个就是StringHttpMessageConverter,这个类里面的getContentLength入参是String类型

@Override
    protected Long getContentLength(String str, @Nullable MediaType contentType) {
        Charset charset = getContentTypeCharset(contentType);
        return (long) str.getBytes(charset).length;
    }

这个时候会直接将对象GlobalResponse强制转换成String所以这个地方会报错

解决方案

如果返回值是String的时候,需要手动Json序列化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/381271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用BWASP对Web应用程序进行安全漏洞手工分析

关于BWASP BWASP是一款针对Web应用程序安全的开源工具,在该工具的帮助下,广大研究人员可以通过手工方式对Web应用程序进行漏洞分析。 BWASP工具可以通过对漏洞的分析来给广大研究人员提供预测信息,而无需对目标执行实际的渗透测试。 BWASP…

【STM32】cmsis-dap调试器-OpenOCD功能集成进CubeIDE中

前言 被自己买的Jlink真是要整烦了 一下连不上,一下固件掉升级,一下说是D版不给调试 于是乎决定,我买了个CMSIS-DAP调试器,决定放弃JLink这等#$%^&货… CMSIS-DAP 调试器 这个是开源调试器,硬件软件开源&#x…

Vue项目如何进行部署?是否有遇到部署服务后刷新404问题?

一、如何部署 前后端分离开发模式下,前后端是独立部署的,前端只需要将最后的构建物上传至目标服务器的Web容器指定的的静态目录下即可 我们知道vue项目在构建后,是生成一系列的静态文件 常规布署我们只需要将这个目录上传至目标服务器即可…

【Java】StringBuffer、StringBuilder

1. StringBuffer、StringBuilder、String对比 String:不可变的字符序列;对于增删改效率最低StringBuffer:可变的字符序列;jdk1.0声明;线程安全(使用了synchronized同步方法),所以效…

什么是工业物联网(IIoT)?

什么是工业物联网(IIoT)?工业物联网(IIoT) 被定义为一组设备和应用,允许大企业创建从核心到边缘的端到端连接环境。其还包括传统的物理基础设施,如集装箱和物流卡车,以收集数据,对事件做出反应,并在智能设备的帮助下做…

2023中国绿色铝业国际峰会 演讲嘉宾确认

2023中国绿色铝业国际峰会将以“双碳”目标下的铝业发展为主题,结合最佳案例和实践分享,探讨绿色铝业发展路径和最新技术,致力于打造一个绿色可持续的铝行业,助力中国实现“碳中和”目标。 会议时间/地点/主办方 2023年3月23日-…

JavaSE14-面向对象-修饰符

文章目录一、权限修饰符和包1.权限修饰符2.包二、static1.静态成员的调用格式2.注意事项3.static内存图4.使用场景三、final一、权限修饰符和包 1.权限修饰符 使用权限修饰符来控制被修饰的成员(如成员变量)的使用权限Java中有四种权限修饰符&#xff…

zabbix中的JMX监控、集成告警平台、分布式监控

文章目录前言一、zabbix中的JMX监控二、集成告警平台:zabbix监控结合睿象云报警三、分布式监控1.agent端主动回传数据2.proxy代理前言 一、zabbix中的JMX监控 JMX介绍: Jmx(Java Management Extensions)java管理拓展 JMX特点&…

linux代码库生成-make示例

1、add.c代码实现加法运算: int add(int a,int b) { return ab; } 2、头文件add.h #ifndef ADD_H #define ADD_H int add(int a,int b); #endif 3、CMakeLists.txt编写 cmake_minimum_required(VERSION 2.6) set(CMAKE_C_FLAGS -m32) project(test_add) include_dir…

OpenMLDB 社区月报 | 2023 年 2 月

导言 OpenMLDB 社区每个月都会发布一版社区月报,总结一个月以来的产品动态、社区活动、内容发布等,让大家对我们社区的发展有更加清晰的了解。如果您对我们的社区有任何建议,欢迎在 GitHub 上提 Issues 或 PR ,共同参与社区的建设…

统计学 假设检验

文章目录假设检验假设检验的基本原理提出假设作出决策表述决策结果一个总体参数的检验总体均值的检验总体比例的检验总体方差的检验两个总体参数的检验两个总体均值之差的检验两个总体比例之差的检验两个总体方差比的检验总体分布的检验正态性检验的图示法Shapiro-Wilk 和 K-S …

Vue3 企业级项目实战:通关 Vue3 企业级项目开发,升职加薪快人一步

Vue3 企业级项目实战 - 程序员十三 - 掘金小册Vue3 Element Plus Spring Boot 企业级项目开发,升职加薪,快人一步。。「Vue3 企业级项目实战」由程序员十三撰写,2744人购买https://s.juejin.cn/ds/S2RkR9F/ 课程介绍 很高兴为大家介绍这个…

LeetCode 1326. Minimum Number of Taps to Open to Water a Garden【贪心,桶排序】

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…

路由网络的构建与配置

Part.1 ⑴ 需求分析 在构建的局域网中,通过路由器间配置静态路由,实现PC1和PC2主机直接连通,主机网段不能与路由器直接互联网段通信。 ⑵ 环境要求 配置虚拟网卡的计算机,安装华为eNSP模拟软件。 规划拓扑 Part.2 ⑴ 拓扑描述…

NVIC 简介、抢占优先级和响应优先级

NVIC 简介 NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。 如果医院只有医生的话,当看病的人很多时,医生就得安排一下先看谁,后看谁,如果…

29 openEuler管理网络-配置网络绑定

文章目录29 openEuler管理网络-配置网络绑定29.1 使用nmcli29.2 使用命令行29.2.1 检查是否已安装Bonding内核模块29.2.2 创建频道绑定接口29.2.3 创建从属接口29.2.4 激活频道绑定29.2.5 创建多个绑定29 openEuler管理网络-配置网络绑定 29.1 使用nmcli 创建名为bond0的绑定&…

vue 组合API

一、组合API是什么?通过创建 Vue 组件,我们可以将界面中重复的部分连同其功能一起提取为可重用的代码段。组合api提供复用性降低耦合性增加可读性下面我们来看下在vue2.0中的一个场景:在2.0里面的**exportdefault{}**通常是由components、pro…

5.排序算法之二:选择排序

选择排序(select sort)在无序列表中,把无序列表分成有序区(刚开始有序区元素个数为0)和无序区(刚开始无序区元素个数为n),循环n-1趟,每一趟找到最小或最大的那个元素&…

CNC数据采集解决方案(2023杭州乐芯科技)

杭州乐芯科技IOT数据采集平台产品是杭州乐芯科技有限公司为满足工业4.0大型集团工厂推出的新一代数据采集平台级产品,可满足单一平台(一个服务器)同时采集各类设备,同时兼容各种工业数据采集协议,单服务器压力测试达10…

chainWebpack之optimization.splitChunks的cacheGroups缓存组代码分块实践案

研究了好几天webpack打包,我们项目是vue的高版本,已经没有了webpack.config.js文件了,是直接在vue.config.js里的chainWebpack方法直接配置,这样做法的好处是用户既可以保留webpack的默认配置,又可以通过chainWebpack设…