接口返回數據相關
使用@ResponseBody后返回NUll
說明:剛把后台運行起來,興高采烈的測試接口數據,結果無論如何都是返回null,
最終通過各種百度,發現原來是沒有引入關鍵的Jar包.
解決辦法:
需要引入jackson的jar包(jackson core和jackson mapper),引入后
圖:

首先: 確定的是(經過多次測試的結果)只有當返回值是 String時才會出現中文亂碼,而當返回值是Map<String, Object>或者是其它類型時,並沒有中文亂碼的出現.
然后找原因: 原因是這可以說是spring mvc的一個bug,spring MVC有一系列HttpMessageConverter去處理用@ResponseBody注解的返回值,如返回list或其它則使用 MappingJacksonHttpMessageConverter,返回string,則使用 StringHttpMessageConverter,而這個convert使用的是字符集是iso-8859-1,而且是final的。所以在當返回json中有中文時會出現亂碼。
- public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
解決辦法(以及是否嘗試成功): 嘗試了很多種網上的辦法,有一些根本無用,有一些當客戶端的Accep是 application/json;時無用.最終也是結合客戶端的修改才成功解決問題的。
環境:
SpringMvc 3.1
客戶端分為三種不同的請求:
1.瀏覽器中直接Get訪問,Accept是"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
2.用Jquery的jsonp ajax請求,Accept是"*/*"
3.用h5+環境下的mui ajax請求,Accept是"application/json;charset=utf-8"
(PS:h5+是最近做的跨平台移動項目的開發環境,另外就是有試過默認的Accept"application/json"的話不管服務器端用哪種方法,在呢么配置,都會返回亂碼,所以最后只得手動加上charset=utf-8了)
注: 如果什么都不加,第一種和第二種都是返回的亂碼,第三種由於手動要求了返回格式,所以沒有亂碼,這里之所以要第三組做對比是因為有一些方法會造成第三組不能正常訪問。
嘗試方法一: 在配置文件中的mvc:annotation-driven中添加如下代碼
- <mvc:annotation-driven >
- <!-- 消息轉換器 -->
- <mvc:message-converters register-defaults="true">
- <bean class="org.springframework.http.converter.StringHttpMessageConverter">
- <property name="supportedMediaTypes" value="text/html;charset=UTF-8"/>
- </bean>
- </mvc:message-converters>
- </mvc:annotation-driven>
最終結果:
請求方法1中文亂碼
請求方法2返回正確的中文
請求方法3返回正確的中文
嘗試方法二: 在配置文件中的mvc:annotation-driven中添加如下代碼
- <mvc:annotation-driven>
- <mvc:message-converters>
- <bean class="org.springframework.http.converter.StringHttpMessageConverter">
- <property name="supportedMediaTypes">
- <list>
- <span style="white-space:pre"> </span> <value>text/html;charset=UTF-8</value>
- <value>application/json;charset=UTF-8</value>
- <value>*/*;charset=UTF-8</value>
- </list>
- </property>
- </bean>
- </mvc:message-converters>
- </mvc:annotation-driven>
最終結果:
請求方法1中文亂碼
請求方法2返回正確的中文
請求方法3返回正確的中文
關於這種類型的方法為什么不能正確解決,原因網上都是各不相同,這里也不敢輕易做出結論.總之,目前來看這種方法不能解決問題
嘗試方法三: 在@RequestMapping里的配置produces="text/html;charset=UTF-8;"
- @RequestMapping(value = "***",produces="text/html;charset=UTF-8;")
原理: 手動給對應的Accept返回制定格式編碼數據。
最終結果:
請求方法1返回正確的中文
請求方法2返回正確的中文
請求方法3無法請求,出了錯,因為produces沒有添加application/json;對應的頭部.
嘗試方法四: 在@RequestMapping里的並發配置produces={"application/json;","text/html;charset=UTF-8;"}
- @RequestMapping(value = "***",produces={"application/json;","text/html;charset=UTF-8;"})
原理: 手動給對應的Accept返回制定格式編碼數據。
最終結果:
請求方法1返回中文亂碼
請求方法2返回中文亂碼
請求方法3返回正確的中文
嘗試方法五: 在@RequestMapping里的並發配置produces={"text/html;charset=UTF-8;","application/json;"}
- @RequestMapping(value = "***",produces={"text/html;charset=UTF-8;","application/json;"})
注意: 這里和上個方法的區別是,produces里面的順序對調了
原理: 手動給對應的Accept返回制定格式編碼數據。
最終結果:
請求方法1返回正確的中文
請求方法2返回正確的中文
請求方法3返回正確的中文
發現produces設置多個Accept只有第一個的charset是有用的,
后面的Accept設置有效(因為不設置就無法接收對應的Accept請求),但是charset設置是無效的.需要客戶端手動制定charset才行.
具體原因並不清楚(原諒我並不精通)
所以得出的結論是:
produces={"text/html;charset=UTF-8;","application/json;"}
這樣設置,這樣普通瀏覽器的請求就能正常顯示中文,而客戶端的模擬請求(可以是ajax或http)則手動指定Accept的charset,即可正常接收中文。
說明:剛剛搭建的Java web后台程序,用Http請求很正常,但是用普通的ajax請求時,出現了一個跨域問題,被拒絕訪問.
解決辦法:
在.net后台布置在IIS服務器上的,直接可以在IIS的應用池中配置Access-Control-Allow-Origin: *就行了.
PhP后台也只需要手動配置
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
Java Web后台可以再對應的tomcat服務器上通過CORS配置跨域訪問(詳情見另一篇),這里暫時只探討Java Web的JSONP實現
於是: 這里的Java Web后台采用了JSONP傳輸方式來支持跨域.
(缺點就是只支持Get,而且需要服務器端有JSONP的判斷,因為返回參數和普通的不一樣)
JSONP前端代碼:(這里是用了JQ的jsonp請求)
- <span style="white-space:pre"> </span>$.ajax(url, {
- data: data,
- dataType: "jsonp",
- jsonpCallback: 'testGetData',
- timeout: "15000", //超時時間設置為3秒;
- type: "POST",
- success: function(response) {
- var result = 'success:' + JSON.stringify(response);
- //返回的是utf8編碼,需要手動轉為utf16
- console.log(result);
- //alert(result);
- },
- error: function(error) {
- var result = 'error:' + JSON.stringify(error);
- console.log(result);
- //alert(result);
- }
- });
JSONP傳遞Java Web后台代碼片段:
1.在方法的最開頭獲取是否是JSONP請求-通過獲取callback參數
- //判斷是否是jsonp請求
- String jsoncallback = request.getParameter("callback");
- public static String getJsonPData(String callbackName,Map<String, Object> data) throws JsonGenerationException, JsonMappingException, IOException{
- ObjectMapper mapper = new ObjectMapper();
- String json = mapper.writeValueAsString(data);
- System.out.println("jsonp回調:"+callbackName);
- System.out.println("jackson解析的字符串:"+json);
- String result = "";
- if(callbackName==null||callbackName==""){
- //普通請求
- result = json;
- }else{
- //jsonp請求,返回的格式是類似於一個函數的字符串形式(前端再執行這個回調來獲取數據)
- result = callbackName+"("+json+")";
- }
- System.out.println("最終結果:"+result);
- return result;
- }