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 ,在依賴(lài)中引入 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-07
Spring?MVC中@Controller和@RequestMapping注解使用
這篇文章主要介紹了Spring?MVC中@Controller和@RequestMapping注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
IDEA整合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

