美文网首页程序员
优雅编程 - RestTemplate

优雅编程 - RestTemplate

作者: 林昀熙 | 来源:发表于2019-12-19 11:03 被阅读0次

RestTemplate介绍

RestTemplate是Spring提供的用于访问Rest服务的客户端,同时RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

RestTemplate初探

通过实例展示RestTemplate的使用

@Test
public void test01(){
   RestTemplate restTemplate = new RestTemplate();
   String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
   ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, 1, "Elon", 20);
   if(responseEntity.getStatusCode() == HttpStatus.OK){
       System.out.println(responseEntity.getBody());
   }
}

@Test
public void test02(){
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/api/v1/org/{department}/list");
    HttpEntity<String> formEntity = new HttpEntity<String>(getHttpHeaders());
    ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, formEntity, String.class, 2);
    if(responseEntity.getStatusCode() == HttpStatus.OK){
       System.out.println(responseEntity.getBody());
    }
}

// Mock登录授权信息
public static HttpHeaders getHttpHeaders(){
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));
    headers.add("Cookie", "token=123244545");
    return headers;
}

示例参数:

  • String url: 该方法第一个参数标识请求的url
  • Class<T> responseType: 该参数标识该次HTTP请求的结果映射成的对象类型,
  • Object... urlVariables: 该参数用来为url中的参数赋值,支持多个值传递.

RestTemplate的交互说明

上面示例中的交互可以分为三个步骤:

  1. url和参数聚合
  2. HTTP请求交互
  3. HTTP结果映射

对应的SpringRest中的如下方法.

@Override
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Object... urlVariables) throws RestClientException {
   URI expanded = getUriTemplateHandler().expand(url, urlVariables);
   return doExecute(expanded, method, requestCallback, responseExtractor);
}

URL和参数聚合

RestTemplate的源码中使用getUriTemplateHandler().expand(url, urlVariables)来完善完成URL中占位符参数的聚合。
示例:

@Test
public void url(){
   String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
   URI expanded = restTemplate.getUriTemplateHandler().expand(url, 1, "Elon", 20);
   // 输出结果: http://www.baidu.com?id=1&name=Elon&num=20
   System.out.println(expanded.toString());
}

RestTemplate中HTTP交互过程

http交互规范的定义

了解该块前先看看Spring中对ClientHttpRequest和对应的工厂接口的定义

ClientHttpRequest接口的定义

ClientHttpRequest接口的定义很简单,一个钩子方法

public interface ClientHttpRequest extends HttpRequest, HttpOutputMessage {
   ClientHttpResponse execute() throws IOException;
}

ClientHttpRequest接口默认提供了如下的扩展类

[图片上传失败...(image-d192aa-1576724583854)]

ClientHttpRequestFactory接口的定义

ClientHttpRequestFactory接口的定义如下:

public interface ClientHttpRequestFactory {
    ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
}

ClientHttpRequestFactory接口提供的实现类如下:

image

HttpAccessor的代理实现

Spring中定义了抽象类HttpAccessor, 提供了默认的ClientHttpRequestFactory实现,
ClientHttpRequestFactory默认值为SimpleClientHttpRequestFactory().

对应的HttpAccessor实现的代码:

public abstract class HttpAccessor {

   protected final Log logger = LogFactory.getLog(getClass());
   private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

   public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
       Assert.notNull(requestFactory, "'requestFactory' must not be null");
       this.requestFactory = requestFactory;
   }

   public ClientHttpRequestFactory getRequestFactory() {
       return this.requestFactory;
   }

   protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
       ClientHttpRequest request = getRequestFactory().createRequest(url, method);
       if (logger.isDebugEnabled()) {
           logger.debug("Created " + method.name() + " request for \"" + url + "\"");
       }
       return request;
   }
}
doExecute中的钩子使用

URL构建完成后RestTemplate调用的是一个doExecute方法,该方法对应的代码如下

protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,  ResponseExtractor<T> responseExtractor) throws RestClientException {
   Assert.notNull(url, "'url' must not be null");
   Assert.notNull(method, "'method' must not be null");
   ClientHttpResponse response = null;
   try {
       ClientHttpRequest request = createRequest(url, method);
       if (requestCallback != null) {
           requestCallback.doWithRequest(request);
       }
       response = request.execute();
       handleResponse(url, method, response);
       if (responseExtractor != null) {
           return responseExtractor.extractData(response);
       }
       else {
           return null;
       }
   }
   catch (IOException ex) {
       throw new ResourceAccessException("I/O error on " + method.name() +
               " request for \"" + url + "\": " + ex.getMessage(), ex);
   }
   finally {
       if (response != null) {
           response.close();
       }
   }
}

这里的createRequest(url, method)方法集成自抽象类HttpAccessor.这样,在构建完成后,HTTP交互过程交给定义的ClientHttpRequest的规范实现.

HTTP交互结果处理

HTTP交互接口返回通过ResponseExtractor<T>该规范来处理.
ResponseExtractor<T>接口的定义:

public interface ResponseExtractor<T> {
    T extractData(ClientHttpResponse response) throws IOException;
}

ResponseExtractor<T>接口默认提供的实现:

[图片上传失败...(image-130163-1576724583854)]

示例中我们的接口调用的返回结果实现使用的是ResponseEntityResponseExtractor<T>

@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables)
       throws RestClientException {
   RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
   ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
   return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
}

具体的实现可以参看RestTemplate,不再做过多介绍.

RestTemplate类关系图

RestTemplate类关系图

[图片上传失败...(image-171326-1576724583854)]

这里RestTemplate使用的常见的Rest请求的接口都定义在RestOperations中,对应的规范定义如下:

GET 规范


// GET

<T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;
    
<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
    
<T> T getForObject(URI url, Class<T> responseType) throws RestClientException;
    
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;
    
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

HEAD 规范

// HEAD
    
HttpHeaders headForHeaders(String url, Object... uriVariables) throws RestClientException;

HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables) throws RestClientException;
    
HttpHeaders headForHeaders(URI url) throws RestClientException;

POST 规范

// POST

URI postForLocation(String url, Object request, Object... uriVariables) throws RestClientException;
    
URI postForLocation(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;
    
URI postForLocation(URI url, Object request) throws RestClientException;

<T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
        throws RestClientException;
    
<T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
        throws RestClientException;
    
<T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException;
    
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
        throws RestClientException;
    
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
        throws RestClientException;
    
<T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;

PUT 规范

// PUT

void put(String url, Object request, Object... uriVariables) throws RestClientException;

void put(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;
    
void put(URI url, Object request) throws RestClientException;

DELETE 规范

// DELETE

void delete(String url, Object... uriVariables) throws RestClientException;
    
void delete(String url, Map<String, ?> uriVariables) throws RestClientException;

void delete(URI url) throws RestClientException;

OPTIONS 规范

// OPTIONS
    
Set<HttpMethod> optionsForAllow(String url, Object... uriVariables) throws RestClientException;

Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables) throws RestClientException;
    
Set<HttpMethod> optionsForAllow(URI url) throws RestClientException;

在提供通用REST(GET、POST、HEAD、PUT、DELETE、OPTIONS)规范操作的基础上还提供了exchange()和execute()相关的规范操作接口定义.

RestTemplate异步模块

AsyncRestTemplate是提供的异步操作RestTemplate的组件快.使用方式比较简单.

@Test
public void test(){
   AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
   String url = "http://www.baidu.com?id={id}&name={name}&num={age}";
   ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate.getForEntity(url, String.class, 1, "Elon", 20);
   try {
       ResponseEntity<String> responseEntity = listenableFuture.get();
       if(responseEntity.getStatusCode() == HttpStatus.OK){
           System.out.println(responseEntity.getBody());
       }
   } catch (Exception e) {
       LOG.error(e.getLocalizedMessage(), e);
   }
}

参考文档

官方文档

相关文章

网友评论

    本文标题:优雅编程 - RestTemplate

    本文链接:https://www.haomeiwen.com/subject/qzkmnctx.html