SpringBoot統(tǒng)一返回處理出現(xiàn)cannot?be?cast?to?java.lang.String異常解決
一 問(wèn)題出現(xiàn)背景:
在使用 @RestControllerAdvice
和實(shí)現(xiàn) ResponseBodyAdvice
做 controller
層統(tǒng)一返回封裝時(shí)。當(dāng)返回字符串時(shí)會(huì)報(bào) “cannot be cast to java.lang.String” 異常,返回其他類(lèi)型就無(wú)任何問(wèn)題。
二 解決方案
如果返回的是字符串直接手動(dòng)封裝返回對(duì)象轉(zhuǎn)成json字符串返回即可。
完整代碼
@RestControllerAdvice public class ResponseResult implements ResponseBodyAdvice<Object> { /** * 支持注解@ResponseNotIntercept,使某些方法無(wú)需使用Result封裝 * * @param returnType 返回類(lèi)型 * @param converterType 選擇的轉(zhuǎn)換器類(lèi)型 * @return true 時(shí)會(huì)執(zhí)行beforeBodyWrite方法,false時(shí)直接返回給前端 */ @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { if (returnType.getDeclaringClass().isAnnotationPresent(ResponseNotIntercept.class)) { //若在類(lèi)中加了@ResponseNotIntercept 則該類(lèi)中的方法不用做統(tǒng)一的攔截 return false; } if (returnType.getMethod().isAnnotationPresent(ResponseNotIntercept.class)) { //若方法上加了@ResponseNotIntercept 則該方法不用做統(tǒng)一的攔截 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已經(jīng)被包裝了,就不進(jìn)行包裝 return body; } if (body instanceof String) { //解決返回值為字符串時(shí),不能正常包裝 return JSON.toJSONString(Result.success(body)); } return Result.success(body); } }
三 異常原因分析
原因:
SpringMVC
默認(rèn)會(huì)注冊(cè)一些自帶的 HttpMessageConvertor
(從先后順序排列分別為ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter,SourceHttpMessageConverter、AllEncompassingFormHttpMessageConverter) ,后端服務(wù)使用Restful API的形式,前后端得規(guī)范一般是json格式, SpringMVC
自帶 MappingJackson2HttpMessageConverter
,在依賴中引入 jackson
包后,容器會(huì)把 MappingJackson2HttpMessageConverter
自動(dòng)注冊(cè)到 messageConverters
鏈的末尾
當(dāng)返回的數(shù)據(jù)是非字符串時(shí)使用的 MappingJackson2HttpMessageConverter
寫(xiě)入返回對(duì)象。當(dāng)返回的數(shù)據(jù)是字符串時(shí),此處得方法是要去循環(huán)遍歷 HttpMessageConverter
集,因?yàn)?StringHttpMessageConverter
會(huì)先被遍歷到,這時(shí)會(huì)認(rèn)為 StringHttpMessageConverter
可以使用,在返回 Result
是使用 ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage)
;此方法是父類(lèi)方法 body
參數(shù)類(lèi)型為 Object
,實(shí)際調(diào)用的為 StringHttpMessageConverter
中的 addDefaultHeaders(HttpHeaders headers, String s, @Nullable MediaType type)
方法,使用 String
類(lèi)型的 s
來(lái)接收 Result
類(lèi)型的 body
,類(lèi)型不匹配則出現(xiàn) Result cannot be cast to java.lang.String
異常。
源碼詳細(xì)分析:
正常返回:
步驟一:遍歷 messageConverters
去判斷到 MappingJackson2HttpMessageConverter
是 GenericHttpMessageConverter
類(lèi)型的 converter
;
步驟二:進(jìn)一步判斷到 MappingJackson2HttpMessageConverter
可以寫(xiě)入對(duì)象類(lèi)型的數(shù)據(jù)。
步驟三:調(diào)用 beforeBodyWriter
方法將原有的 TestVO
對(duì)象數(shù)據(jù)封裝到 Result
對(duì)象中。
步驟四:調(diào)用 MappingJackson2HttpMessageConverter
中的 wirte
方法(代碼中用接口類(lèi)型接收的)
步驟五:通過(guò) MappingJackson2HttpMessageConverter
繼承關(guān)系發(fā)現(xiàn)其write方法在父類(lèi) AbstractHttpMessageConverter
中,在 write
方法中調(diào)用本類(lèi)中的 addDefaultHeaders
方法向輸出消息添加默認(rèn)報(bào)頭。(此處應(yīng)注意)
步驟六:將封裝好的Result對(duì)象返回給前端
返回為字符串異常
步驟一:遍歷 messageConverters
去判斷到 StringHttpMessageConverter
是null;
步驟二:進(jìn)一步判斷到 StringHttpMessageConverter
可以寫(xiě)入String類(lèi)型的數(shù)據(jù)。
步驟三:調(diào)用 beforeBodyWriter
方法將原有的 String
類(lèi)型數(shù)據(jù)封裝到 Result
對(duì)象中。
步驟四:調(diào)用 StringHttpMessageConverter
中的 wirte
方法(代碼中用接口類(lèi)型接收的)
步驟五:
調(diào)用父類(lèi) AbstractHttpMessageConverter
中的 write
方法,由于 StringHttpMessageConverter
重寫(xiě)了 addDefaultHeaders
方法,故 write
中調(diào)用子類(lèi)中的 addDefaultHeaders
。由于父類(lèi)中參數(shù)t為對(duì)象類(lèi)型,對(duì)應(yīng)子類(lèi)中接收的s為String類(lèi)型故會(huì)出現(xiàn)類(lèi)型轉(zhuǎn)換異常 Result cannot be cast to java.lang.String
(此處應(yīng)注意)
總結(jié)
到此這篇關(guān)于SpringBoot統(tǒng)一返回處理出現(xiàn)cannot be cast to java.lang.String異常解決的文章就介紹到這了,更多相關(guān)cannot be cast to java.lang.String異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
jsp+servlet實(shí)現(xiàn)簡(jiǎn)單登錄頁(yè)面功能(附demo)
本文主要介紹了jsp+servlet實(shí)現(xiàn)簡(jiǎn)單登錄頁(yè)面功能登錄成功跳轉(zhuǎn)新頁(yè)面,登錄失敗在原登錄界面提示登錄失敗信息,對(duì)初學(xué)者有一定的幫助,感興趣的可以了解一下2021-07-07Spring?MVC中@Controller和@RequestMapping注解使用
這篇文章主要介紹了Spring?MVC中@Controller和@RequestMapping注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02IDEA整合SSM框架實(shí)現(xiàn)網(wǎng)頁(yè)上顯示數(shù)據(jù)
最近做了個(gè)小項(xiàng)目,該項(xiàng)目包在intellij idea中實(shí)現(xiàn)了ssm框架的整合以及實(shí)現(xiàn)訪問(wèn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05