ResponseBodyAdvice、String返回值报cannot be cast to java.lang.String的解决办法

实现ResponseBbodyAdvice接口后,Controller层返回String类型报错的解决办法

1. 问题背景
本人是“某为”的外包开发,项目早期采用的是传统三层架构+n的模式进行开发,但开发到中期后,甲方出台了项目代码规范有要求,其中就包含了冗余代码指标。为了降低无用代码冗余,我们做了很多代码结构层次上的优化。其中在减少controller层无用代码冗余的时候,采用的方案就是采用实现ResponseBbodyAdvice接口来进行的。近期由于我本人希望给页面响应特定的字符串(也就是controller方法返回类型为String),然后惊讶的发现报了类似如下图的错误:
在这里插入图片描述

2. 解决方案
为了节省部分读者的时间,这边先给出解决问题的方式,问题根因将在第三点内容中进行分析和详解。话不多说,上源码:

/**
 * 数据返回格式统一封装
 *
 * @author wei yun shi
 * @date 2020/10/30 16:40
 */
@ControllerAdvice
public class UnifiedResponseHandle implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return returnType.getMethodAnnotation(UnifiedResponse.class) != null;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (returnType.getMethodAnnotation(UnifiedResponse.class) != null) {
            return new ResponseResult<>(HttpStatus.OK.value(), body);
        }
        return body;
    }
}

上图中,UnifiedResponseHandle就是我实现ResponseBodyAdvice接口的类,而ResponseResult是用来作统一响应风格的类,UnifiedResponse是自定义注解,这里主要通过判断方法上是否包含自定义注解来进行判断是否要做统一处理。报错的地方是在这一行代码上

 return new ResponseResult<>(HttpStatus.OK.value(), body);

解决办法是,将ResponseResult对象转为json格式字符串后再返回,整改后如下:

return JSON.toJSONString(new ResponseResult<>(HttpStatus.OK.value(), body));

至此问题已经解决。时间有限的同学到这里就可以结束了,但作为一名优秀的开发,显然仅此而已是远远不够的,要有专研的精神。
3. 问题根因—找出问题的本质
3.1问题分析
按理说我们通过封装后返回的就是转换json格式的数据,为何报了类型转换异常?为什么这个对象要转换成String呢?笔者第一时间想到的是springMVC的默认处理机制导致的,我们知道当我们返回值类型为字符串的时候,mvc框架就会将其跳转到路径为返回内容的地址。但乱说是不能作为依据的,况且这个问题需要去处理。
于是debug走起,
在这里插入图片描述
我们看到,这里所选的类型转换器是"org.springframework.http.converter.StringHttpMessageConverter",至此我们再看如果返回其他类型看看这里选择的是何种转换器呢?
在这里插入图片描述

将返回值类型改为int后,可以发现mvc框架选中的转换器是org.springframework.http.converter.json.MappingJackson2HttpMessageConverter。
那么问题是找到了,返回字符串的时候采用的是特殊的StringHttpMessageConverter转换器,而其他格式则是采用MappingJackson2HttpMessageConverter转换器来解析的,StringHttpMessageConverter转换器将内容转为String字符串,而当前我们返回的则是一个具体的对象,这就导致了报错的根本原因也就是类型转换异常。
基于问题的根因找到了,那么是否意味着我们只需将其类型转换器强制更改为MappingJackson2HttpMessageConverter就可以了呢?实践是检验真理的唯一标准,立马开干,修改后的代码如下:

package helper;

import com.alibaba.fastjson.JSON;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 数据返回格式统一封装
 *
 * @author wei yun shi
 * @date 2020/10/30 16:40
 */
@ControllerAdvice
public class UnifiedResponseHandle implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return returnType.getMethodAnnotation(UnifiedResponse.class) != null;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (returnType.getMethodAnnotation(UnifiedResponse.class) != null) {
            selectedConverterType=(new MappingJackson2HttpMessageConverter()).getClass();
            return new ResponseResult<>(HttpStatus.OK.value(), body);
        }
        return body;
    }
}

执行后,我们很遗憾的发现,其结果并非我们所愿,还是报错了,依旧是本问提到的那个类型转换异常,同时我们发现,框架使用的类型转换器依旧StringHttpMessageConverter,显然我们强行设置的类型转换器没有生效。如此,显然这个方案是行不通的,那么我们只能转换思路。如果使用返回类型是String,转换器就是StringHttpMessageConverter,那么最终他是要将结果转换为String,假如我们将结果字符串直接返回是否会有问题呢?显然是没问题的,但显然这样还达不到我们的目的,我们最终是需要返回一个对象的。
通过前面的实验我们可以知道,只要返回的最终结果是String类型,那么在框架使用StringHttpMessageConverter转换器的时候,就可以规避类型转换的问题。那么我们只需要将结果对象提前转换为字符串即可,也就是第二点使用的解决方案,将对象通过JSON转换为JSON格式的字符串,至此问题的解决方案和根据已经找到。

ps:如果文章对你有帮助,请给个赞吧!!!

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值