zoukankan      html  css  js  c++  java
  • Spring RestTemplate使用教程

    简介

    Spring'scentral class for synchronous client-side HTTP access.It simplifies communication with HTTPservers, and enforces RESTful principles. Ithandles HTTP connections, leaving application code to provide URLs(with possible template variables) andextract results.

    简单说就是:简化了发起HTTP请求以及处理响应的过程,并且支持REST。为什么说简化了呢?

    来看两种实现方式

    (1)使用java.net包下的URLConnection建立连接

    String result= "";  
            BufferedReaderin = null;  
            try {  
                String urlNameString= url +"?" + param;  
                URL realUrl= new URL(urlNameString);  
                // 打开和URL之间的连接  
                URLConnectionconnection = realUrl.openConnection();  
                // 设置通用的请求属性  
                connection.setRequestProperty("accept","*/*");  
                connection.setRequestProperty("connection","Keep-Alive");  
                connection.setRequestProperty("user-agent",  
                        "Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1;SV1)");  
                // 建立实际的连接  
                connection.connect();  
                // 获取所有响应头字段  
                Map<String,List<String>> map = connection.getHeaderFields();  
                // 遍历所有的响应头字段  
                for(String key : map.keySet()) {  
                    System.out.println(key+ "--->" + map.get(key));  
                }  
                // 定义 BufferedReader输入流来读取URL的响应  
                in =new BufferedReader(newInputStreamReader(  
                        connection.getInputStream()));  
                String line;  
                while ((line = in.readLine())!= null) {  
                    result += line;  
                }  
            } catch (Exception e) {  
                …  
            }  
            // 使用finally块来关闭输入流  
            finally{  
             // 关闭流  
            }  

    (2)使用RestTempalte

    ResponseEntity<SsoUrlPrm>result = restTemplate.getForEntity(requestPathUrl,SsoUrlPrm.class);  

    对外开放的接口

    (1)

    DELETE delete
    GET getForObject
      getForEntity
    HEAD headForHeaders
    OPTIONS optionsForAllow
    POST postForLocation
      postForObject
    PUT put
    any exchange
      execute

    (2)每一个小类又分三种,这三种有什么区别?

    * 第一种和第二种的首个参数都是用String表示一个URI。但它们的最后一个参数分别是Object[]和Map
    * 第三种的首个参数使用java.net.URI表示一个URI。且只有两个参数

      这是因为,String类型的URI支持占位符。比如:

    restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",String.class,"42", "21");

    那么最终访问的URI为:http://example.com/hotels/42/bookings/21

      但是String有一个小缺陷:String形式的URI会被URL编码两次(URL encode请自行百度),这就要求服务器在获取URI中的参数时主动进行一次解码,但如果服务的提供者不这么做呢?

      这时就需要使用不会使用任何编码的java.net.URI

    PS:参数‘Class<T>  responseType’定义了返回数据的类型。

    (3)Exchange

      与其它接口的不同:

    >允许调用者指定HTTP请求的方法(GET,POST,PUT等)

    >可以在请求中增加body以及头信息,其内容通过参数‘HttpEntity<?>requestEntity’描述

    >exchange支持‘含参数的类型’(即泛型类)作为返回类型,该特性通过‘ParameterizedTypeReference<T>responseType’描述。比如:

    List<String> a = new ArrayList<String>();   
    System.out.println(a.getClass());   
    System.out.println(a.getClass().getGenericSuperclass());   
    ParameterizedTypeReference pt = new ParameterizedTypeReference<ArrayList<String>>() {};   
    System.out.println(pt.getType());  

    得到的结果是:

    class java.util.ArrayList  
    java.util.AbstractList<E>  
    java.util.ArrayList<java.lang.String> 

    这是因为ParameterizedTypeReference<ArrayList<String>>并不根据实参而是使用getGenericSuperclass()方法获取其父类的类型(注意这里的new有花括号,是ParameterizedTypeReference的子类),父类的类型通过java.lang.reflect.Type描述,然后通过Type的getActualTypeArguments()获得了父类的实参类型,注意得到的Type类,并不是class类。

    (4)excute

    所有的get、post、delete、put、options、head、exchange方法最终调用的都是excute方法。举个栗子:
    @Override  
    public <T> T getForObject(String url, Class<T>  responseType, Object... urlVariables) throws    RestClientException {  
      RequestCallback requestCallback =     acceptHeaderRequestCallback(responseType);  
      HttpMessageConverterExtractor<T> responseExtractor =  
    <span style="white-space:pre">    </span>new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);  
      return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);  
    }  

    Excute方法只是将String格式的URI转成了java.net.URI,之后调用了doExecute方法。整个调用过程


    6.doExcute

    6.1 定义
    protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,ResponseExtractor<T> responseExtractor) throws RestClientException {…} 
    这里需要了解两个类: RequestCallback &ResponseExtractor
     
    6.2 RequestCallback
    Callback interface for code that operates on a ClientHttpRequest. Allows to manipulate the request headers, and write to the request body.
    简单说:用于操作请求头和body,在请求发出前执行。

    该接口有两个实现类:
    AcceptHeaderRequestCallback 只处理请求头,用于getXXX()方法。
    HttpEntityRequestCallback 继承于AcceptHeaderRequestCallback可以处理请求头和body,用于putXXX()、postXXX()和exchange()方法。

    * DELETE、HEAD、OPTIONS没有使用这个接口。
     
    6.3 发起请求
     
    6.4 ResponseExtractor
    6.4.1 定义
    Generic callback interface used by RestTemplate's retrieval methods Implementations of this interface perform the actual work of extracting data from a ClientHttpResponse, but don't need to worry about exception handling or closing resources.
    简单说:解析HTTP响应的数据,而且不需要担心异常和资源的关闭。
     
    该接口有三个实现类:
    HeadersExtractor 用于提取请求头。
    HttpMessageConverterExtractor 用于提取响应body。
    ResponseEntityResponseExtractor 使用HttpMessageConverterExtractor提取body(委托模式),然后将body和响应头、状态封装成ResponseEntity对象。
    6.4.2 提取响应body
    提取分三步:
    (1)提取器HttpMessageConverterExtractor寻找可用的转化器
    在默认的RestTemplate的构造函数中初始化了转化器集合,包括:

    转化器

    可转化的类型
    ByteArrayHttpMessageConverter byte[]
    StringHttpMessageConverter String
    ResourceHttpMessageConverter Resource
    SourceHttpMessageConverter javax.xml.transform.*
    AllEncompassingFormHttpMessageConverter MultiValueMap
    Jaxb2RootElementHttpMessageConverter XmlRootElement,XmlType(注解)
    ...  
    MappingJackson2HttpMessageConverter Json
    除了前五个,其他的转化器会由classloader尝试加载某个类来判断工程是否包含某个包,而后决定是否加入转化器集合。
    提取器遍历转化器集合以查找可用的转化器,其中MappingJackson2HttpMessageConverter总是在最后一个,因为该类实现了GenericHttpMessageConverter,算是一个通用转化器,只有在找不到合适的转化器时才轮到它。Spring提供了一个该类的实现,以保证总是能得到该类。

    (2)转化器寻找可用的反序列化器
    转化器持有一个反序列化器缓存集合,首先从缓存中寻找
    如果已有可用的反序列化器,则直接返回。否则创建一个新的反序列化器。
     
    反序列化器保存着待反序列化类的域、方法、构造器等信息,反序列化时就是使用构造器创建了一个新的实例。
    以jackson为例,创建反序列化器的过程在jackson-databind-xxx.jar中,有兴趣的可以看一下。调用栈如下(由下往上找):
    BeanDeserializerFactory.addBeanProps/addObjectIdReader/addReferenceProperties/addInjectables
    BeanDeserializerFactory.buildBeanDeserializer
    BeanDeserializerFactory.createBeanDeserializer

    (3)反序列化器执行反序列化

    TOKEN

    Json的一个或一组字符
    START_OBJECT {
    END_OBJECT }
    START_ARRAY [
    END_ARRAY ]
    VALUE_TRUE true
    VALUE_FALSE false
    ...  

    调用栈:

     
     
  • 相关阅读:
    如何编译Linux内核
    svn
    windows live writer …
    SVN服务器配置
    使用PowerDesigner创建数据库表图文并茂版
    maven学习
    在PreparedStatement中设置空值
    今天, 我的博客正式开通啦.
    Neo4j简介
    clinit和init(转载)
  • 原文地址:https://www.cnblogs.com/shamo89/p/9656402.html
Copyright © 2011-2022 走看看