zoukankan      html  css  js  c++  java
  • @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



  • 相关阅读:
    『实践』Yalmip建模+Cplex类求解(文末附程序、文章和算例)
    『实践』Matlab实现Flyod求最短距离及存储最优路径
    『转载』Matlab中fmincon函数获取乘子
    『实践』Yalmip获取对偶函数乘子
    『转载』hadoop 1.X到2.X的变化
    『转载』hadoop2.x常用端口、定义方法及默认端口
    『实践』VirtualBox 5.1.18+Centos 6.8+hadoop 2.7.3搭建hadoop完全分布式集群及基于HDFS的网盘实现
    C#设计模式学习笔记:(6)适配器模式
    ASP.NET 开源导入导出库Magicodes.IE 导出Pdf教程
    Rx基础
  • 原文地址:https://www.cnblogs.com/xiangkejin/p/9016498.html
Copyright © 2011-2022 走看看