解決@ResponseBody作用在返回類型為String的方法時(shí)的坑
@ResponseBody作用在返回類型為String的方法時(shí)的坑
在默認(rèn)的Spring配置中,當(dāng)在返回類型為String的Controller方法時(shí),在其上加上@ResponseBody時(shí)會(huì)出現(xiàn)問題,那就是返回的不再是我們期待的Json格式的字符串了,而是會(huì)變成在正常的Json串前后加上雙引號(hào)。
這是為什么呢?這是因?yàn)樵贖TTPMessageConverter中對(duì)應(yīng)寫json格式相應(yīng)的處理類在寫json的時(shí)候默認(rèn)是對(duì)String類型進(jìn)行這樣處理的。
以Gson為例
在SpringBoot中,有相應(yīng)的Configuartion來(lái)配置用戶來(lái)解析Json格式的HttpMessageConverter,經(jīng)過DEBUG發(fā)現(xiàn),在HttpMessageConverter列表中第一個(gè)符合處理json返回格式的是GsonHttpMessageConverter,他是在GsonHttpMessageConvertersConfiguration類中被注入的。
他對(duì)json的處理是
?? ?@Override ?? ?protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage) ?? ??? ??? ?throws IOException, HttpMessageNotWritableException { ?? ??? ?Charset charset = getCharset(outputMessage.getHeaders()); ?? ??? ?OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), charset); ?? ??? ?try { ?? ??? ??? ?if (this.jsonPrefix != null) { ?? ??? ??? ??? ?writer.append(this.jsonPrefix); ?? ??? ??? ?} ?? ??? ??? ?if (type != null) { ?? ??? ??? ??? ?this.gson.toJson(o, type, writer); ?? ??? ??? ?} ?? ??? ??? ?else { ?? ??? ??? ??? ?this.gson.toJson(o, writer); ?? ??? ??? ?} ?? ??? ??? ?writer.close(); ?? ??? ?} ?? ??? ?catch (JsonIOException ex) { ?? ??? ??? ?throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex); ?? ??? ?} ?? ?}
因?yàn)镚son默認(rèn)對(duì)String類型的對(duì)象轉(zhuǎn)化為json就是會(huì)加上雙引號(hào)的,所以導(dǎo)致了String類型的返回不再是json串了。
如果想要String類型也轉(zhuǎn)為正常的json格式的話,只要重寫GsonHttpMessageConverter即可。
?? ?@Override ?? ?protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage) ?? ??? ??? ?throws IOException, HttpMessageNotWritableException { ?? ??? ?Charset charset = getCharset(outputMessage.getHeaders()); ?? ??? ?OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), charset); ?? ??? ?try { ?? ??? ??? ?if (this.jsonPrefix != null) { ?? ??? ??? ??? ?writer.append(this.jsonPrefix); ?? ??? ??? ?} ?? ??? ??? ?if (type != null) { ? ? ? ? ? ? ? ? //對(duì)于String類型的,直接拼接,不轉(zhuǎn)json ?? ??? ??? ?if("java.lang.String".equals(type.getTypeName())){ ? ? ? ? ? ? ? ? writer.append(value.toString()); ?? ??? ??? ?}else{ ?? ??? ??? ??? ?this.gson.toJson(o, type, writer); ? ? ? ? ? ? ? ? } ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ??? ?else { ?? ??? ??? ??? ?this.gson.toJson(o, writer); ?? ??? ??? ?} ?? ??? ??? ?writer.close(); ?? ??? ?} ?? ??? ?catch (JsonIOException ex) { ?? ??? ??? ?throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex); ?? ??? ?} ?? ?}
對(duì)于FastJson,在測(cè)試的時(shí)候發(fā)現(xiàn),對(duì)于低版本的FastJson,會(huì)存在一個(gè)問題,就是當(dāng)Java對(duì)象并沒有默認(rèn)的構(gòu)造器的時(shí)候,是會(huì)報(bào)錯(cuò)的,需要使用新版本的FastJson才會(huì)去尋找合適的構(gòu)造器去實(shí)例化對(duì)象。
至于哪個(gè)版本才可以稱為新版本,沒有仔細(xì)研究,我使用的1.2.47版本已經(jīng)修復(fù)這個(gè)問題。
Fastjson還是有很多坑的,之前有研究過他之前的一個(gè)遠(yuǎn)程漏洞,這個(gè)后續(xù)會(huì)寫一篇文章,個(gè)人并不建議使用Fastjson,推薦Gson。
對(duì)了,如果你使用的是fastjson提供的HTTPMessageConverter,是一樣會(huì)對(duì)String格式做加引號(hào)處理的,具體可以看相應(yīng)源碼。
心得
所以為了@ResponseBody能良好的實(shí)現(xiàn)返回json格式的功能,要不我們就不要返回String對(duì)象,要么就需要重寫相應(yīng)將返回對(duì)象處理為Json的HTTPMessageConverter,特殊化他對(duì)String類型的處理。
response.body().string()的坑坑坑?。?!
一不小心 浪費(fèi)了2個(gè)小時(shí)
response.body().string()
這個(gè)東西明明就看到過是string string為啥還是寫成了toString()...
寫成了response.body().toString()后打印出來(lái)的就是okhttp3.internal.http.RealResponseBody@815f248這樣的數(shù)據(jù)!??!
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)WORD和PDF互相轉(zhuǎn)換以及數(shù)據(jù)填充示例
本文介紹了如何使用Java實(shí)現(xiàn)WORD和PDF的互轉(zhuǎn)以及數(shù)據(jù)填充功能,通過導(dǎo)入Aspose庫(kù)并使用其工具類,可以輕松實(shí)現(xiàn)WORD和PDF模板的填充和轉(zhuǎn)換,需要的朋友可以參考下2025-02-02SpringBoot利用自定義注解實(shí)現(xiàn)多數(shù)據(jù)源
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何利用自定義注解實(shí)現(xiàn)多數(shù)據(jù)源效果,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下2022-10-10java版微信公眾平臺(tái)消息接口應(yīng)用示例
這篇文章主要介紹了java版微信公眾平臺(tái)消息接口應(yīng)用,結(jié)合實(shí)例形式對(duì)比分析了PHP與java應(yīng)用微信公眾平臺(tái)接口的相關(guān)調(diào)用與操作技巧,需要的朋友可以參考下2017-07-07使用springboot在工具類中讀取配置文件(ClassPathResource)
這篇文章主要介紹了使用springboot在工具類中讀取配置文件(ClassPathResource),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java yield()線程讓步實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java yield()線程讓步實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03