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

news2024/9/24 9:19:38

使用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> {
    @Autowired
    private ApplicationContext applicationContext;
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public 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)
    @ResponseBody
    public ApiResponse handleBindException(BindException e) {
        log.error("params bind exception: ", e);
        return wrapperBindingResult(e.getBindingResult());
    }

    /**
     * 参数校验异常,将校验失败的所有异常组合成一条错误信息
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public 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
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }


    // 修改responsebody
    @Override
    public 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)
    @ResponseBody
    public 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")
    @ResponseBody
    public String test(){

        return "sadsadsad";
    }

}

控制台输出:


java.lang.ClassCastException: com.example.demoweb.config.ApiResponse cannot be cast to java.lang.String
	at 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.coloradmin.cn/o/732136.html

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

相关文章

【Linux】高级IO(一)

文章目录 高级IO阻塞IO模型非阻塞IO模型多路转接IOselect简介socket 就绪条件select服务器select的优缺点多路转接的使用场景 高级IO 非阻塞IO&#xff0c;记录锁&#xff0c;系统V流机制&#xff0c;I/O多路转接&#xff08;I/O&#xff09;多路复用&#xff0c;readv 和 wri…

English Learning - L3 综合练习 10 口语语法串讲与思维回顾 2023.07.5 周三

English Learning - L3 综合练习 10 口语语法串讲与思维回顾 2023.07.5 周三 [知识点 1] 名词性从句问题&#xff1a;到底什么是名词笥从句&#xff1f;例 1&#xff1a;我的东西你都可以随便用例 2&#xff1a;不管是谁&#xff0c;放你鸽子就是混蛋例 3&#xff1a;说那种话的…

CMU15-445 2022 Fall 通关记录 —— Project 2:B+ Tree(下篇)

Project 2&#xff1a;B Tree Project #2 - BTree | CMU 15-445/645 :: Intro to Database Systems (Fall 2022) NOTE&#xff1a; 记录完成该Pro中&#xff0c;一些可能会遇到的问题&#xff1a; 本实验中&#xff0c;有很多API是需要自己去实现的&#xff0c;因此&#x…

Mycat【Mycat高可用(安装配置HAProxy、安装配置Keepalived)】(八)-全面详解(学习总结---从入门到深化)

目录 Mycat高可用_安装配置HAProxy Mycat高可用_安装配置Keepalived 复习&#xff1a; Mycat高可用_安装配置HAProxy 安装配置HAProxy 查看列表 yum list | grep haproxy yum安装 yum -y install haproxy 修改配置文件 $ vim /etc/haproxy/haproxy.cfg 启动HAProxy …

安全漏洞的检测利用

安全漏洞的检测&利用 一、安全漏洞的基本概念1.1、什么是漏洞1.2、漏洞的简单理解1.3、微软的RPC漏洞与蠕虫病毒1.4、微软经典的蓝屏漏洞1.5、Heartbleed&#xff08;心脏滴血&#xff09;漏洞1.6、破壳漏洞CVE-2014-62711.7、漏洞的危害1.8、漏洞的成因1.9、漏洞的信息的组…

mysql工具sequel pro

一、安装sequel pro 下载地址&#xff1a;https://www.sequelpro.com/ 需要翻墙 二、安装mysql 下载地址&#xff1a;https://www.mysql.com/ 傻瓜式安装即可 记得设置密码 三、配置环境变量 &#xff08;1&#xff09;打开终端 &#xff08;2&#xff09;open ~/.bash_profile…

【送书福利-第十五期】计算机全栈高手到底该怎么发展?

大家好&#xff0c;我是洲洲&#xff0c;欢迎关注&#xff0c;一个爱听周杰伦的程序员。关注公众号【程序员洲洲】即可获得10G学习资料、面试笔记、大厂独家学习体系路线等…还可以加入技术交流群欢迎大家在CSDN后台私信我&#xff01; 本文目录 一、前言二、书籍介绍1、《前端…

0代码训练GPT-5?MIT微软证实GPT-4涌现自我纠错能力迭代

我们都知道&#xff0c;大模型具有自省能力&#xff0c;可以对写出的代码进行自我纠错。 这种自我修复背后的机制&#xff0c;究竟是怎样运作的&#xff1f; 对代码为什么是错误的&#xff0c;模型在多大程度上能提供准确反馈&#xff1f; 近日&#xff0c;MIT和微软的学者发…

【数据分析 - 基础入门之NumPy①】Anaconda安装及使用

知识目录 前言一、 Anaconda是什么二、为什么使用Anaconda三、安装步骤3.1 下载安装3.2 配置conda源 结语 前言 大家好&#xff01;我是向阳花花花花&#xff0c;本期给大家带来的是 Anaconda 安装及使用。 每日金句分享&#xff1a;故事不长&#xff0c;也不难讲。』—— 「…

期望DP入门

期望DP一般步骤&#xff1a; 1.模拟过程&#xff0c;找出线性性质&#xff0c;作为阶段&#xff08;这本质上也是线性DP&#xff09; 2.涉及DP状态 原则&#xff1a; 体现线性性质 体现边权 根据对期望有无贡献来设计状态 一般在状态设计时需要倒着设计 3.转移 根据边…

如何将自定义字体添加到 iOS 应用程序(SwiftUI + 得意黑)

1. 工具 Xcode Version 14.3 (14E222b)SwiftUI得意黑 Smiley Sans 2. Download https://github.com/atelier-anchor/smiley-sans/releases 3. Add Files to xxx 4. Add Test Code Text("Less is more. 朱洪苇 123").font(.custom("SmileySans-Oblique",…

【电子量产工具】4. UI系统

文章目录 前言一、UI界面分析二、结构体描述按钮三、按钮初始化四、默认绘制按键事件函数五、默认按下按键事件函数六、测试程序实验效果总结 前言 最近看了 电子量产工具 这个项目&#xff0c;本专栏是对该项目的一个总结。 一、UI界面分析 UI 是用户界面&#xff08;User In…

GEE:提取地区 NDVI/LST/RVI 并进行时间序列线性插值和SG滤波

作者&#xff1a;CSDN _养乐多_ 本文将介绍使用Landsat数据集&#xff0c;构建时间序列&#xff0c;并使用线性插值算法填补缺失数据&#xff0c;或者去云空洞&#xff0c;并进一步对完整的时间序列数据进行SG滤波处理。 文章目录 一、代码二、代码链接三、需要请私聊 一、代…

OPCUA 的历史数据库/聚合服务器的实现细节

进入了AI 大数据时代&#xff0c;无论是工业自动化系统&#xff0c;还是物联网系统&#xff0c;对大数据的采集&#xff0c;存储和分析都十分重要。大数据被称为工业的石油&#xff0c;未来制造业的持续改善离不开大数据。 传统的应用中&#xff0c;历史数据的存储是特定的数据…

官方外设库SDA安装和验证

第一种方法 1.打开mobaxterm&#xff0c;通过windows浏览器打开https://github.com/orangepi-xunlong/wiringOP下载压缩包&#xff0c;点击上传外设库的压缩包 2.输入命令 unzip 解压 3.输入命令 sudo ./build 安装工具包 4.验证安装完毕用 输入gpio readall 显示下面图片 第二…

数据分析实战(基础篇):从数据探索到模型解释

前言 本文着重介绍数据分析实战的基础知识和技巧&#xff0c;探索从数据探索到建模再到模型解释的完整过程内容包含数据探索、模型建立、调参技巧、SHAP模型解释数据来源于kaggle平台&#xff0c;crab age prediction数据集&#xff0c;数据详情 数据说明 数据背景 螃蟹味道…

【性能设计篇】聊聊异步处理

在性能设计的时候&#xff0c;其实主要的三板斧就是数据库(读写分离、分库分表)&#xff0c;缓存&#xff08;提升读性能&#xff09;&#xff0c;异步处理&#xff08;提升写性能&#xff09;以及相关的秒杀设计以及边缘设计等。 本篇主要介绍异步处理的哪些事&#xff0c;我们…

6.2.1 网络基本服务---域名解析系统DNS

6.2.1 网络基本服务—域名解析系统DNS 因特网是需要提供一些最基本的服务的&#xff0c;今天我们就来讨论一下这些基本的服务。 域名系统&#xff08;DNS&#xff09;远程登录&#xff08;Telnet&#xff09;文件传输协议&#xff08;FTP&#xff09;动态主机配置协议&#x…

Day47

思维导图 练习 实现登录框中&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;并跳转到其他界面 second.h #ifndef SECOND_H #define SECOND_H#include <QWidget>namespace Ui { class Second; }class Second : public QWidget {Q_OBJECTpublic:explicit …

Matlab绘图时的几个小技巧(修改刻度线长度、添加/去掉右边和上面的轴与刻度线、出图时去掉旁边的空白部分)

set(gca,TickLength,[0.005,0.035]); %修改坐标轴刻度线的长度 box on; %开启右面和上面的坐标轴 box off;%关闭右面和上面的坐标轴 set(gca, LooseInset, [0,0,0,0]);%删除掉图旁边多余的空白部分首先随便出一张图 我想让刻度线更长或更短一些&#xff1a; 我想让右侧和上面…