SpringBoot统一返回处理出现cannot be cast to java.lang.String异常
在使用@RestControllerAdvice和实现ResponseBodyAdvice做controller层统一返回封装时。当返回字符串时会报 “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方法向输出消息添加默认报头。(此处应注意)
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(此处应注意)
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
所以我开始关注ruby,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出
我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案
对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一
为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998