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

这篇具有很好参考价值的文章主要介绍了使用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> {
    @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的消息转换器报错的异常,我们断点看一下:
使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常,java,开发语言
然后我们这边到是对字符串是重新包装成了一个对象,所以就会报错。

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

使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常,java,开发语言
那说明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类型的数据适不适合返回的,这样不便于对接口响应字段的理解,所以这个虽说是技术问题,实际是规范问题,应该规范大家响应都需要返回实体对象,不管是返回一个字段还是多个字段,必须要使用实体返回。文章来源地址https://www.toymoban.com/news/detail-536251.html

到了这里,关于使用ResponseBodyAdvice返回值为String出现cannot be cast to java.lang.String异常的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 已解决java.lang.String cannot be cast to java.lang.Integer异常的正确解决方法,亲测有效!!!

    已解决java.lang.String cannot be cast to java.lang.Integer异常的正确解决方法,亲测有效!!! 开发中经常会遇到java.lang.String cannot be cast to java.lang.Integer异常,记录下我怎么解决的。 这个错误是因为你试图将一个字符串对象转换为整数对象,但是类型不匹配。 下滑查看解决方法 在

    2023年04月08日
    浏览(75)
  • eclipse报错:Multiple annotations found at this line: - String cannot be resolved to a type 解决方法

    写老师布置的作业从机房copy到自己的电脑上发现报错了,以下是报错信息: Multiple annotations found at this line: 在该行中找到的多个注释 - String cannot be resolved to a type -string不能解析为类型 - The method getParameter(String) from the type ServletRequest refers to the missing tye string 从ServletRequest类型

    2024年02月10日
    浏览(38)
  • MySQL 连接出现 Authentication plugin ‘caching_sha2_password‘ cannot be loaded

    在使用Navicat Premium 12连接MySQL数据库时会出现Authentication plugin \\\'caching_sha2_password\\\' cannot be loaded  出错 出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法:把mysql用户登录密码加密规则还原成mysql_native_password

    2024年02月09日
    浏览(40)
  • 已解决java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String异常的

    已解决java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String异常的正确解决方法,亲测有效!!! java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String的错误通常发

    2024年01月21日
    浏览(53)
  • ERROR Executor: Exception in task 0.0 in stage 1.0 (TID 1)Long cannot be cast to java.lang.String

    问题 尝试使用spark写入Hbase报错 这是报错行,rowkey的id这个字段是我使用sparkSQL自带的函数临时添加的,打印schema发现是long类型 原因 java Long类型好像不能getAs为String,所以报错了 解决 将这个字段转换为String再次尝试

    2024年02月12日
    浏览(75)
  • RSA加密,公钥、私钥的生成,前端使用公钥加密,JSEncrypt返回值为false的原因以及解决方法,XML转换Pkcs1、8

    非对称加密算法,两个且不同的Key,一个公开,一个私密,公开加密,私密解密。 特点: 原文短,加密后密文长 生成相对较慢 安全性超强 我们使用.net进行生成公钥、私钥。 使用RSA.ToXmlString(Boolean) 方法生成公钥以及私钥,方法中接收一个参数, true  表示同时包含 RSA 公钥

    2024年01月21日
    浏览(64)
  • java实体类属性值为null不返回或者某个属性不返回

    java实体类值为null或者无关紧要的属性,也返回给了前端,看起来不太高明。可以使用JsonInclude注解或者JsonField注解过滤掉。 用在实体类前或者属性前都可以。 用在属性前。 以上示例中,当total为null时不返回,适用于没有分页的情况。

    2024年02月12日
    浏览(43)
  • vue 对后端返回字段值为null的变成空字符串

    // 字段null转字符串 1.export function null2str(data) {     for (let x in data) {         if (data[x] === null) {             // 如果是null 把直接内容转为 \\\'\\\'             data[x] = \\\"\\\";         } else {             if (Array.isArray(data[x])) {                 // 是数组遍历数组 递归继续处理      

    2024年02月11日
    浏览(40)
  • mysql 自定义函数,返回值为sql查询后的某个字段的值

    函数框架:如果使用的是 Navicat 等可视化工具,通过点击界面填写相应的条件就可以得到函数框架 1、definer 翻译成中文是“定义者”的意思。MySQL中,创建视图(view)、函数(function)、存储过程(procedure)、触发器(trigger)、事件(event)时,都可以指定 DEFINER = user 选项,即指定此对象

    2024年01月18日
    浏览(43)
  • java后端返回数据给前端时去除值为空或NULL的属性、忽略某些属性

    目录 一、使用场景 二、环境准备 1、引入依赖 2、实体类 三、示例 1、不返回空值 (1)方式 (2)测试 (3)说明 2、不返回部分属性 (1)方式 (2)测试 四、 Jackson常用注解 1、 @JsonProperty 2、@JsonPropertyOrder 3、@JsonInclude 4、@JsonIgnoreProperties 5、@JsonFormat 6、@JsonUnwrapped         在开发过程

    2024年02月04日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包