@RequestBody和@ResponseBody的使用情形以及RestTemplate的http報文轉換


@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> 

參考博客:json對象、json字符串的區別和相互轉換

 

@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")));
              }

            }
    }

}
View Code

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;
    }
}
View Code

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;
    }
    
    
    
}
View Code

 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM