@RequestBody和@ResponseBody兩個注解,分別完成請求報文到對象和對象到響應報文的轉換。
@RequestBody
1、@requestBody注解常用來處理content-type不是默認的application/x-www-form-urlcoded編碼的內容,
比如說:application/json或者是application/xml等。一般情況下來說常用其來處理application/json類型。
作用:
- 注解用於將Controller的方法參數,根據HTTP Request Header的
content-Type的內容,通過適當的HttpMessageConverter轉換為JAVA類 - 再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。
說明:request的body部分的數據編碼格式由header部分的Content-Type指定;
2、通過@requestBody可以將請求體中的JSON字符串綁定到相應的bean上,當然,也可以將其分別綁定到對應的字符串上。例如說以下情況:
$.ajax({ url:"/login", type:"POST", data:'{"userName":"admin","pwd","admin123"}', content-type:"application/json charset=utf-8", success:function(data){ alert("request success ! "); } }); @requestMapping("/login") public void login(@requestBody String userName,@requestBody String pwd){ System.out.println(userName+" :"+pwd); }
這種情況是將JSON字符串中的兩個變量的值分別賦予了兩個字符串,但是呢假如我有一個User類,擁有如下字段:
String userName;
String pwd;
那么上述參數可以改為以下形式:@requestBody User user 這種形式會將JSON字符串中的值賦予user中對應的屬性上
需要注意的是,JSON字符串中的key必須對應user中的屬性名,否則是請求不過去的。
另外這里要注意其實 @RequestBody接收的是一個Json對象的字符串,而不是一個Json對象。
Json對象和Json字符串的區別就是有沒有定義的時候有沒有單引號的。。。
如果ajax請求傳的是Json對象,后來用 JSON.stringify(data)的方式就能將對象變成字符串。
同時ajax請求的時候也要指定dataType: "json",contentType:"application/json" 這樣就可以輕易的將一個對象或者List傳到Java端,使用@RequestBody即可綁定對象或者List.。
<script type="text/javascript"> $(document).ready(function(){ var saveDataAry=[]; var data1={"userName":"test","address":"gz"}; var data2={"userName":"ququ","address":"gr"}; saveDataAry.push(data1); saveDataAry.push(data2); $.ajax({ type:"POST", url:"user/saveUser", dataType:"json", contentType:"application/json", data:JSON.stringify(saveData), success:function(data){ } }); }); </script>
@ResponseBody
該注解用於將Controller的方法返回的對象,根據HTTP Request Header的Accept的內容,
通過適當的HttpMessageConverter轉換為指定格式后,寫入到Response對象的body數據區。
通常是在使用 @RequestMapping 后,返回值通常解析為跳轉路徑,加上 @Responsebody 后返回結果不會被解析為跳轉路徑,而是直接寫入HTTP 響應正文中。

HTTP 請求和響應是基於文本的,意味着瀏覽器和服務器通過交換原始文本進行通信。但是,使用 Spring,controller 類中的方法返回純 ‘String’ 類型和域模型(或其他 Java 內建對象)。
如何將對象序列化/反序列化為原始文本?這由HttpMessageConverter 處理。
Http請求和響應報文本質上都是一串字符串,當請求報文來到java世界,它會被封裝成為一個ServletInputStream的輸入流,供我們讀取報文。響應報文則是通過一個ServletOutputStream的輸出流,來輸出響應報文。
我們從流中,只能讀取到原始的字符串報文,同樣,我們往輸出流中,也只能寫原始的字符。
而在java世界中,處理業務邏輯,都是以一個個有業務意義的對象為處理維度的,那么在報文到達SpringMVC和從SpringMVC出去,都存在一個字符串到java對象的阻抗問題。
這一過程,不可能由開發者手工轉換。我們知道,在Struts2中,采用了OGNL來應對這個問題,而在SpringMVC中,它是HttpMessageConverter機制。

請看:
SpringMVC源碼剖析(五)-消息轉換器HttpMessageConverter
HttpMessageConverter(消息轉換器 )和@responsebody使用
RestTemplate中http報文轉換處理
在RestTemplate中,
我們知道,調用reseful接口傳遞的數據內容是json格式的字符串,返回的響應也是json格式的字符串。
然而restTemplate.postForObject方法的請求參數RequestBean和返回參數ResponseBean卻都是java類。是RestTemplate通過HttpMessageConverter自動幫我們做了轉換的操作。
默認情況下RestTemplate自動幫我們注冊了一組HttpMessageConverter用來處理一些不同的contentType的請求。
如StringHttpMessageConverter來處理text/plain;MappingJackson2HttpMessageConverter來處理application/json;MappingJackson2XmlHttpMessageConverter來處理application/xml。
你可以在org.springframework.http.converter包下找到所有spring幫我們實現好的轉換器。
如果現有的轉換器不能滿足你的需求,你還可以自己實現。
請看:如何使用RestTemplate訪問restful服務
注意:
StringHttpMessageConverter默認使用的字符集是ISO-8859-1,在遇到中文的時候會有亂碼,所以需要移除RestTemplate默認的StringHttpMessageConverter修改字符字符集后重新設置。
spring的json轉換器默認使用的是Jackson,json字符串和對應的Entity如果有字段對不上就會報錯,這個有點不符合國情,而FastJson則不會報錯,所以很多時候都會用FastJSON替換默認的Jackson。
配置示例:
@Configuration public class RestAutoConfig { public static class RestTemplateConfig { @Bean//負載均衡的restTemplate @LoadBalanced //spring 對restTemplate bean進行定制,加入loadbalance攔截器進行ip:port的替換 //"http://user/getusername,就能解析成http://127.0.0.1:8083//getusername RestTemplate lbRestTemplate(HttpClient httpclient) { RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpclient)); template.getMessageConverters().add(0,new StringHttpMessageConverter(Charset.forName("utf-8"))); template.getMessageConverters().add(1,new FastJsonHttpMessageConvert5()); return template; } @Bean //直連的restTemplat,這時只能使用http://127.0.0.1:8083//getusername地址,不能解析http://user/getusername RestTemplate directRestTemplate(HttpClient httpclient) { RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpclient)); template.getMessageConverters().add(0,new StringHttpMessageConverter(Charset.forName("utf-8"))); template.getMessageConverters().add(1,new FastJsonHttpMessageConvert5()); return template; } // FastJsonHttpMessageConvert4有一個bug,它是默認支持MediaType.ALL,spring在處理MediaType.ALL的時候會識別成字節流,而不是json,這里就對他進行改造和處理 public static class FastJsonHttpMessageConvert5 extends FastJsonHttpMessageConverter4{ static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public FastJsonHttpMessageConvert5(){ setDefaultCharset(DEFAULT_CHARSET); setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON,new MediaType("application","*+json"))); } } } }
HTTPclient Bean獲取類:
@Configuration @ConditionalOnClass({HttpClient.class}) @EnableConfigurationProperties(HttpClientProperties.class) public class HttpClientAutoConfiguration { private final HttpClientProperties properties; public HttpClientAutoConfiguration(HttpClientProperties properties){ this.properties = properties; } /** * httpclient bean 的定義 * @return */ @Bean @ConditionalOnMissingBean(HttpClient.class) public HttpClient httpClient() { RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(properties.getConnectTimeOut()) .setSocketTimeout(properties.getSocketTimeOut()).build();// 構建requestConfig HttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig) .setUserAgent(properties.getAgent()) .setMaxConnPerRoute(properties.getMaxConnPerRoute()) .setMaxConnTotal(properties.getMaxConnTotaol()) .build(); return client; } }
HTTPClient參數類:
@ConfigurationProperties(prefix="spring.httpclient") public class HttpClientProperties { private Integer connectTimeOut = 1000; private Integer socketTimeOut = 1000000; private String agent = "agent"; private Integer maxConnPerRoute = 10; private Integer maxConnTotaol = 50; public Integer getConnectTimeOut() { return connectTimeOut; } public void setConnectTimeOut(Integer connectTimeOut) { this.connectTimeOut = connectTimeOut; } public Integer getSocketTimeOut() { return socketTimeOut; } public void setSocketTimeOut(Integer socketTimeOut) { this.socketTimeOut = socketTimeOut; } public String getAgent() { return agent; } public void setAgent(String agent) { this.agent = agent; } public Integer getMaxConnPerRoute() { return maxConnPerRoute; } public void setMaxConnPerRoute(Integer maxConnPerRoute) { this.maxConnPerRoute = maxConnPerRoute; } public Integer getMaxConnTotaol() { return maxConnTotaol; } public void setMaxConnTotaol(Integer maxConnTotaol) { this.maxConnTotaol = maxConnTotaol; } }
