springboot统一返回处理出现cannotbecasttojava.lang.string异常(代码片段)

伏加特遇上西柚 伏加特遇上西柚     2023-03-29     317

关键词:

SpringBoot统一返回处理出现cannot be cast to java.lang.String异常

一 问题出现背景:

在使用@RestControllerAdvice和实现ResponseBodyAdvicecontroller层统一返回封装时。当返回字符串时会报 “cannot be cast to java.lang.String” 异常,返回其他类型就无任何问题。

二 解决方案

如果返回的是字符串直接手动封装返回对象转成json字符串返回即可。

完整代码

@RestControllerAdvice
public class ResponseResult implements ResponseBodyAdvice<Object> 
    /**
     * 支持注解@ResponseNotIntercept,使某些方法无需使用Result封装
     *
     * @param returnType 返回类型
     * @param converterType  选择的转换器类型
     * @return true 时会执行beforeBodyWrite方法,false时直接返回给前端
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) 
        if (returnType.getDeclaringClass().isAnnotationPresent(ResponseNotIntercept.class)) 
            //若在类中加了@ResponseNotIntercept 则该类中的方法不用做统一的拦截
            return false;
        
        if (returnType.getMethod().isAnnotationPresent(ResponseNotIntercept.class)) 
            //若方法上加了@ResponseNotIntercept 则该方法不用做统一的拦截
            return false;
        
        return true;
    

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) 
        if (body instanceof Result) 
            // 提供一定的灵活度,如果body已经被包装了,就不进行包装
            return body;
        
        if (body instanceof String) 
            //解决返回值为字符串时,不能正常包装
            return JSON.toJSONString(Result.success(body));
        
        return Result.success(body);
    

三 异常原因分析

原因:

SpringMVC 默认会注册一些自带的HttpMessageConvertor (从先后顺序排列分别为ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter,SourceHttpMessageConverter、AllEncompassingFormHttpMessageConverter) ,后端服务使用Restful API的形式,前后端得规范一般是json格式,SpringMVC 自带MappingJackson2HttpMessageConverter,在依赖中引入 jackson 包后,容器会把MappingJackson2HttpMessageConverter自动注册到 messageConverters链的末尾

当返回的数据是非字符串时使用的 MappingJackson2HttpMessageConverter 写入返回对象。
当返回的数据是字符串时,此处得方法是要去循环遍历HttpMessageConverter集,因为StringHttpMessageConverter会先被遍历到,这时会认为StringHttpMessageConverter可以使用,在返回Result是使用((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);此方法是父类方法body参数类型为Object,实际调用的为StringHttpMessageConverter中的addDefaultHeaders(HttpHeaders headers, String s, @Nullable MediaType type)方法,使用String类型的s来接收Result类型的body,类型不匹配则出现Result cannot be cast to java.lang.String异常。

源码详细分析:

正常返回:

  • 步骤一:遍历messageConverters去判断到MappingJackson2HttpMessageConverter
    GenericHttpMessageConverter类型的converter
  • 步骤二:进一步判断到MappingJackson2HttpMessageConverter可以写入对象类型的数据。
  • 步骤三:调用beforeBodyWriter方法将原有的TestVO对象数据封装到Result对象中。
  • 步骤四:调用MappingJackson2HttpMessageConverter中的wirte方法(代码中用接口类型接收的)
  • 步骤五:通过MappingJackson2HttpMessageConverter继承关系发现其write方法在父类AbstractHttpMessageConverter中,在write方法中调用本类中addDefaultHeaders方法向输出消息添加默认报头。(此处应注意)
  • 步骤六:将封装好的Result对象返回给前端

返回为字符串异常

  • 步骤一:遍历messageConverters去判断到StringHttpMessageConverter是null;
  • 步骤二:进一步判断到StringHttpMessageConverter可以写入String类型的数据。
  • 步骤三:调用beforeBodyWriter方法将原有的String类型数据封装到Result对象中。
  • 步骤四:调用StringHttpMessageConverter中的wirte方法(代码中用接口类型接收的)
  • 步骤五
  • 调用父类AbstractHttpMessageConverter中的write方法,由于StringHttpMessageConverter重写了addDefaultHeaders方法,故write中调用子类中的addDefaultHeaders。由于父类中参数t为对象类型,对应子类中接收的s为String类型故会出现类型转换异常Result cannot be cast to java.lang.String(此处应注意)

springboot全局异常统一处理反参标准化

对于日常的开发过程中出现的异常,我把它分为两种,一种是需要给前端返回的异常,这种异常通常有入参格式、字段缺少、以及相关的业务异常,需要明确的告诉前端出现了什么问题,前端才好处理,而另一种异常例如空指针... 查看详情

springboot2全局统一返回restful风格数据统一异常处理

...vice拦截异常并统一处理。开发环境:IntelliJIDEA2019.2.2jdk1.8SpringBoot2.2.21、创建一个SpringBoot项目,pom.xml引用的依赖包如下<dependency><gr 查看详情

springboot2.0统一返回rest风格数据结构与统一异常处理

参考技术A结果: 查看详情

springboot统一功能处理(用户登录权限效验-拦截器异常处理数据格式返回)(代码片段)

...格式返回的实现3.2@ControllerAdvice源码分析本篇将要学习SpringBoot统一功能处理模块,这也是AOP的实战环节统一用户登录权限的效验实现接口HandlerInterceptor+WebMvcConfigurer统一异常处理使用注解@RestControllerAdvice+@Excepti... 查看详情

springboot统一功能处理(代码片段)

SpringBoot统一功能处理前言一、用户登录权限效验1.1最初的用户登录验证1.2SpringAOP用户统一登录验证的问题1.3Spring拦截器1.3.1准备工作1.3.2自定义拦截器1.3.3将自定义拦截器加入到系统配置1.4拦截器实现原理1.4.1实现原理源码分析1.4... 查看详情

springboot返回统一的json标准格式(代码片段)

自定义状态码枚举类封装返回结果全局异常捕获处理,使用@RestControllerAdvice注解拦截Controller方法的返回值,统一处理返回值/响应体创建Controller,准备测试请求接口,查看响应结果近年来,随着移动互联网... 查看详情

springboot返回统一的json标准格式(代码片段)

自定义状态码枚举类封装返回结果全局异常捕获处理,使用@RestControllerAdvice注解拦截Controller方法的返回值,统一处理返回值/响应体创建Controller,准备测试请求接口,查看响应结果近年来,随着移动互联网... 查看详情

springboot项目如何做到统一异常处理

...个项目中对于异常的处理就显得尤为重要.那么,小编就以SpringBoot框架,通过代码实例展示统一异常的处理方式.1.首先我们简单搭建一个SpringBoot框架的项目,项目名称是exceptionhandler(异常处理)2.导入 查看详情

统一异常处理的实现(代码片段)

前面介绍了SpringBoot如何整合定时任务已经SpringBoot如何创建异步任务和定时任务。不清楚的朋友可以看看之前的文章:《SpringBoot入门系列文章》接下来主要讲解如何在SpringBoot应用中使用统一异常处理。如何实现对异常数据与正... 查看详情

springboot中添加全局异常捕获类

前几天工作中遇到一个项目,前后端分离的,作为后端开发专注开发接口。对于程序中出现的异常如果不进行处理,将报错信息直接返回到前端十=时不优雅的,因此需要对异常进行捕获和处理,但是每个接口都单独处理异常则... 查看详情

知识点-springboot统一异常处理汇总(代码片段)

...在实际开发中,我们会遇到很多异常,在发生异常的时候SpringBoot默认提供了错误页面展示给用户。看似比较友好,其实页面很丑。上面讲的是做页面开发的时候遇到的问题,还有一种情况就是用来开发Rest接口,当错误的时候我... 查看详情

每天用springboot,还不懂restfulapi返回统一数据格式是怎么实现的?

关于Spring的全局处理,我有两方面要说:统一数据返回格式统一异常处理为了将两个问题说明清楚,将分两个章节分别说明,本章主要说第一点有童鞋说,我们项目都做了这种处理,就是在每个API都单独工具类将返回值进行封装... 查看详情

springboot统一处理返回实体与异常抛出(代码片段)

​当返回异常时,是这样子的"timestamp":"2019-12-11T05:37:10.096+0000","status":500,"error":"InternalServerError","message":"报错了","path":"/test/testException"但是,可能有时前台需要一个... 查看详情

springboot统一处理返回实体与异常抛出(代码片段)

​当返回异常时,是这样子的"timestamp":"2019-12-11T05:37:10.096+0000","status":500,"error":"InternalServerError","message":"报错了","path":"/test/testException"但是,可能有时前台需要一个... 查看详情

springboot如何统一后端返回格式?老鸟们都是这样玩的!

大家好,我是飘渺。今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常。首先我们来看看为什么要返回统一的标准格式?为什么要对SpringBoot返回统... 查看详情

springboot统一后端返回格式?老鸟们都是这样玩的!(代码片段)

大家好,我是bigsai。今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常。首先我们来看看为什么要返回统一的标准格式?为什么要对SpringBoot返回统... 查看详情

springboot如何统一后端返回格式?老鸟们都是这样玩的!(代码片段)

...c;我是只爱教妹学Java的秃头哥。今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常。首先我们来看看为什么要返回统一的标准格式?为什么要对SpringBoot... 查看详情

springboot中处理mybatis返回map时key值的大小写

为了统一不同数据库返回key值大小写不一致的问题,特自定义ObjectWrapperFactory来做统一的处理1,首先自定义MapWrapper/***将Map的key全部转换为小写**/publicclassMapKeyLowerWrapperextendsMapWrapper{publicMapKeyLowerWrapper(MetaObjectmetaObject,Map<Strin 查看详情