使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常

使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常

背景

由于项目中为了全局返回统一的JSON格式,使用ResponseBodyAdvice进行拦截,拦截的时候会将返回的信息统一一个对象返回到前端。但是有的同事将一个String的响应对象返回,结果报错com.example.demoweb.config.ApiResponse cannot be cast to java.lang.String

ResponseBodyAdvice 拦截器实现

ServletResponseBodyAdvice

package com.example.demoweb.config;import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import javax.servlet.http.HttpServletRequest;
import java.util.Objects;/*** @author tengwang8*/
@ControllerAdvice
@Slf4j
public class ServletResponseBodyAdvice implements ResponseBodyAdvice<Object> {@Autowiredprivate ApplicationContext applicationContext;@ExceptionHandler(BusinessException.class)@ResponseBodypublic ApiResponse businessException(BusinessException e) {log.error(" business  exception code = {} ,msg = {}", e.getCode(), e.getMsg());return ApiResponse.failed(e.getCode(), e.getMsg());}/*** 参数绑定异常** @param e 异常* @return 异常结果*/@ExceptionHandler(value = BindException.class)@ResponseBodypublic ApiResponse handleBindException(BindException e) {log.error("params bind exception: ", e);return wrapperBindingResult(e.getBindingResult());}/*** 参数校验异常,将校验失败的所有异常组合成一条错误信息** @param e 异常* @return 异常结果*/@ExceptionHandler(value = MethodArgumentNotValidException.class)@ResponseBodypublic ApiResponse handleValidException(MethodArgumentNotValidException e) {log.error("params valid exception:", e);return wrapperBindingResult(e.getBindingResult());}/*** 包装绑定异常结果** @param bindingResult 绑定结果* @return 异常结果*/private ApiResponse wrapperBindingResult(BindingResult bindingResult) {StringBuilder msg = new StringBuilder();for (ObjectError error : bindingResult.getAllErrors()) {msg.append(", ");if (error instanceof FieldError) {msg.append(((FieldError) error).getField()).append(": ");}msg.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage());}return ApiResponse.failed(ResultCode.UNAUTHORIZED, msg.substring(2));}/*** 这里直接返回true,表示对任何handler的responsebody都调用beforeBodyWrite方法** @param methodParameter* @param aClass* @return*/@Overridepublic boolean supports(MethodParameter methodParameter, Class aClass) {return true;}// 修改responsebody@Overridepublic Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {if (o instanceof ApiResponse) {return  o;} else {return ApiResponse.success(o);}}/*** 未定义异常** @param e 异常* @return 异常结果*/@ExceptionHandler(value = Exception.class)@ResponseBodypublic ApiResponse handleException(Exception e) {log.error("handleException :", e);return ApiResponse.failed(ResultCode.FAILED);}}

TestDemoController

/*** @author tengwang8* @date 2022年09月19日 11:02*/
@RestController
public class TestDemoController {@GetMapping("/tt")@ResponseBodypublic String test(){return "sadsadsad";}}

控制台输出:


java.lang.ClassCastException: com.example.demoweb.config.ApiResponse cannot be cast to java.lang.Stringat org.springframework.http.converter.StringHttpMessageConverter.addDefaultHeaders(StringHttpMessageConverter.java:44) ~[spring-web-5.3.22.jar:5.3.22]at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:211) ~[spring-web-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:293) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78) ~[spring-web-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.22.jar:5.3.22]at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) [spring-webmvc-5.3.22.jar:5.3.22]at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) [tomcat-embed-core-9.0.65.jar:4.0.FR]at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.3.22.jar:5.3.22]at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) [tomcat-embed-core-9.0.65.jar:4.0.FR]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.3.22.jar:5.3.22]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.22.jar:5.3.22]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.3.22.jar:5.3.22]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.22.jar:5.3.22]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.3.22.jar:5.3.22]at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) [spring-web-5.3.22.jar:5.3.22]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.65.jar:9.0.65]at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.65.jar:9.0.65]at java.lang.Thread.run(Thread.java:745) [na:1.8.0_102]

通过错误信息进行分析

StringHttpMessageConverter我们看到有返回string的消息转换器报错的异常,我们断点看一下:
在这里插入图片描述
然后我们这边到是对字符串是重新包装成了一个对象,所以就会报错。

我们再尝试断点看一下如果返回值是实体对象的时候,发现这个转换器是org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

在这里插入图片描述
那说明Spring 内部是通过不同的消息转换器(MessageConverter)来处理不同的返回值,每个MessageConverer是根据返回类型和媒体类型来选择处理的。

解决方案

其实解决很简单,判断一下返回值是否是String,如果是String的话就将对象处理为Json串就好了,废话不多说,直接上代码:

public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {if (o instanceof ApiResponse) {return  o;} else {ApiResponse<Object> success = ApiResponse.success(o);return   o instanceof String ? JSONUtil.toJsonStr(success) : success;}
}

总结

这个问题虽然解决了,其实我是觉得不应该这里随便写这个返回,应该按照规范来定义返回,String类型的数据适不适合返回的,这样不便于对接口响应字段的理解,所以这个虽说是技术问题,实际是规范问题,应该规范大家响应都需要返回实体对象,不管是返回一个字段还是多个字段,必须要使用实体返回。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nuxt3 components公共组件

1.目录结构 效果实现&#xff1a;写一个公共的right组件&#xff0c;在index和about页面同时引用它 2.index页面引入 index页面显示效果 about页面引用及效果

文件共享平台Pingvin Share

本文完成于 2 月上旬。最近正好应网友要求折腾了 ClamAV&#xff0c;所以翻出来一起发了&#xff0c;可以作为 ClamAV 的一个应用示例&#xff1b; 什么是 Pingvin Share &#xff1f; Pingvin Share 是自托管文件共享平台&#xff0c;是 WeTransfer 的替代品。使用 Pingvin Sh…

【爬虫学习】1、利用get方法对豆瓣电影数据进行爬取

♥️作者&#xff1a;白日参商 &#x1f935;‍♂️个人主页&#xff1a;白日参商主页 ♥️坚持分析平时学习到的项目以及学习到的软件开发知识&#xff0c;和大家一起努力呀&#xff01;&#xff01;&#xff01; &#x1f388;&#x1f388;加油&#xff01; 加油&#xff01…

elk高并发架构

1.前言 普通的elk架构只适合数据量小的情景&#xff0c;而且也不安全&#xff0c;在瞬时数据量大的情况下可能会导致logstash崩溃&#xff0c;从而导致数据的丢失&#xff0c;对于数据安全有较高要求&#xff0c;可以在架构中加入消息队列&#xff0c;既可以防止瞬时的大流量并…

vue 进阶---动态组件 插槽 自定义指令

目录 动态组件 如何实现动态组件渲染 使用 keep-alive 保持状态 keep-alive 对应的生命周期函数 keep-alive 的 include 属性和exclude属性 插槽 插槽的基础用法 具名插槽 作用域插槽 自定义指令 自定义指令的分类 私有自定义指令 全局自定义指令 了解 eslint 插件…

B/S版手术麻醉系统源码,基于php、mysql和vue2开发

手术麻醉系统是一套以数字形式与医院信息系统&#xff08;如HIS、EMR、LIS、PACS等&#xff09;和医疗设备等软、硬件集成并获取围手术期相关信息的计算机系统&#xff0c;其核心是对围手术期患者信息自动采集、储存、分析并呈现。该系统通过整合围手术期中病人信息、人员信息、…

IPV6使用越来越广,您会配置吗?

前面针对IPv6写过一篇文章&#xff0c;但是好多网友反映没有读懂&#xff0c;今天再给大家把内容浓缩一下&#xff0c;教给大家如何配置。 IPV6的推出主要是为了解决地址空间的不足&#xff0c;从而进一步的促进互联网的发展。IPV6地址空间大到惊人&#xff0c;有人比喻地球上…

时间序列预测 | Matlab灰狼算法(GWO)优化极限梯度提升树XGBoost时间序列预测,GWO-XGBoost时间序列预测模型,单列数据输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab灰狼算法(GWO)优化极限梯度提升树XGBoost时间序列预测,GWO-XGBoost时间序列预测模型,单列数据输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及…

Spring boot +React集成ChatGPT 智能AI

在这里插入代码片import {Button, Input, Radio,Alert,Modal } from antd; import Marquee from react-fast-marquee; import {ChromeOutlined,WifiOutlined,AimOutlined } from ant-design/icons; import React, {useEffect, useState, useRef} from react; import chatgptPn…

服务器数据恢复-raid10重建为raid6的数据恢复案例

服务器故障&#xff1a; 一台IBM V7000存储中的vdisk丢失&#xff0c;Solaris操作系统中的部署的Oracle数据库不可用。经过和工作人员的沟通得知故障原因&#xff1a;工作人员进行重建MDisk的操作&#xff0c;将原先的raid10重建为raid6&#xff0c;然后又再次重建为raid10&…

网络编程4——TCP协议的三大安全机制:三次握手四次挥手+确认应答机制+超时重传机制

文章目录 前言一、TCP协议段与机制TCP协议的特点TCP报头结构TCP协议的机制与特性 二、TCP协议的 连接管理机制 TCP建立连接&#xff1a;三次握手 TCP断开连接&#xff1a;四次挥手 三、TCP协议的 确认应答机制 四、TCP协议的 超时重传机制 总结 前言 本人是一个刚刚上路的I…

【Ubuntu学习MySQL——安装MySQL】

首先得su&#xff0c;然后输入密码&#xff0c;进入到root模式下&#xff0c;以下命令均在root用户模式下进行 1.在这里我们使用RPM包来安装Mysql&#xff0c;所以首先安装RPM包 apt install rpm2.安装完RPM包之后&#xff0c;检测系统是否自带安装MySQL&#xff0c;如果没有…