The Guide to RestTemplate – RestTemplate指南

最后修改: 2015年 9月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’re going to illustrate the broad range of operations where the Spring REST Client — RestTemplate — can be used, and used well.

在本教程中,我们将说明Spring REST客户端–RestTemplate–可以使用的广泛操作,并且使用得很好。

For the API side of all examples, we’ll be running the RESTful service from here.

对于所有例子的API方面,我们将从这里运行RESTful服务。

2. Deprecation Notice

2.淘汰通知

As of Spring Framework 5, alongside the WebFlux stack, Spring introduced a new HTTP client called WebClient.

从Spring Framework 5开始,与WebFlux栈一起,Spring引入了一个新的HTTP客户端,称为WebClient

WebClient is a modern, alternative HTTP client to RestTemplate. Not only does it provide a traditional synchronous API, but it also supports an efficient nonblocking and asynchronous approach.

WebClient是一个现代的、替代RestTemplate的HTTP客户端。它不仅提供了传统的同步API,而且还支持高效的非阻塞和异步方法。

That said, if we’re developing new applications or migrating an old one, it’s a good idea to use WebClient. Moving forward, RestTemplate will be deprecated in future versions.

也就是说,如果我们正在开发新的应用程序或迁移旧的应用程序,使用WebClient是一个好主意。展望未来,RestTemplate将在未来的版本中被废弃。

3. Use GET to Retrieve Resources

3.使用GET来检索资源

3.1. Get Plain JSON

3.1.获取普通的JSON

Let’s start simple and talk about GET requests, with a quick example using the getForEntity() API:

让我们从简单的开始,谈谈GET请求,使用getForEntity() API的一个快速例子

RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl
  = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response
  = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.OK);

Notice that we have full access to the HTTP response, so we can do things like check the status code to make sure the operation was successful or work with the actual body of the response:

注意,我们可以完全访问HTTP响应,所以我们可以做一些事情,比如检查状态代码以确保操作成功,或者处理响应的实际主体。

ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode name = root.path("name");
Assertions.assertNotNull(name.asText());

We’re working with the response body as a standard String here and using Jackson (and the JSON node structure that Jackson provides) to verify some details.

我们在这里把响应体作为一个标准的字符串,并使用Jackson(以及Jackson提供的JSON节点结构)来验证一些细节。

3.2. Retrieving POJO Instead of JSON

3.2.检索POJO而不是JSON

We can also map the response directly to a Resource DTO:

我们也可以直接将响应映射到一个资源DTO。

public class Foo implements Serializable {
    private long id;

    private String name;
    // standard getters and setters
}

Now we can simply use the getForObject API in the template:

现在我们可以简单地在模板中使用getForObject API。

Foo foo = restTemplate
  .getForObject(fooResourceUrl + "/1", Foo.class);
Assertions.assertNotNull(foo.getName());
Assertions.assertEquals(foo.getId(), 1L);

4. Use HEAD to Retrieve Headers

4.使用HEAD检索头文件

Let’s now have a quick look at using HEAD before moving on to the more common methods.

现在让我们在进入更常见的方法之前,先快速看一下使用HEAD。

We’re going to be using the headForHeaders() API here:

我们将在这里使用headForHeaders() API。

HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
Assertions.assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));

5. Use POST to Create a Resource

5.使用POST创建一个资源

In order to create a new Resource in the API, we can make good use of the postForLocation(), postForObject() or postForEntity() APIs.

为了在API中创建一个新的资源,我们可以很好地利用postForLocation()postForObject()postForEntity() APIs。

The first returns the URI of the newly created Resource, while the second returns the Resource itself.

第一个返回新创建资源的URI,而第二个返回资源本身。

5.1. The postForObject() API

5.1.postForObject() API

RestTemplate restTemplate = new RestTemplate();

HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);
Assertions.assertNotNull(foo);
Assertions.assertEquals(foo.getName(), "bar");

5.2. The postForLocation() API

5.2.postForLocation() API

Similarly, let’s have a look at the operation that instead of returning the full Resource, just returns the Location of that newly created Resource:

同样地,让我们来看看这个操作,它没有返回完整的资源,而只是返回新创建资源的Location

HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
URI location = restTemplate
  .postForLocation(fooResourceUrl, request);
Assertions.assertNotNull(location);

5.3. The exchange() API

5.3.exchange() API

Let’s have a look at how to do a POST with the more generic exchange API:

让我们来看看如何使用更通用的exchangeAPI进行POST。

RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
ResponseEntity<Foo> response = restTemplate
  .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
 
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);
 
Foo foo = response.getBody();
 
Assertions.assertNotNull(foo);
Assertions.assertEquals(foo.getName(), "bar");

5.4. Submit Form Data

5.4 提交表格数据

Next, let’s look at how to submit a form using the POST method.

接下来,让我们看看如何使用POST方法提交一个表单。

First, we need to set the Content-Type header to application/x-www-form-urlencoded.

首先,我们需要将Content-Type标头设置为application/x-www-form-urlencoded。

This makes sure that a large query string can be sent to the server, containing name/value pairs separated by &:

这确保了可以向服务器发送一个大的查询字符串,包含由&分隔的名称/值对。

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

We can wrap the form variables into a LinkedMultiValueMap:

我们可以将表格变量包装成LinkedMultiValueMap

MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "1");

Next, we build the Request using an HttpEntity instance:

接下来,我们使用一个HttpEntity实例构建Request

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

Finally, we can connect to the REST service by calling restTemplate.postForEntity() on the Endpoint: /foos/form

最后,我们可以通过在端点上调用restTemplate.postForEntity()连接到REST服务。/foos/form

ResponseEntity<String> response = restTemplate.postForEntity(
  fooResourceUrl+"/form", request , String.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);

6. Use OPTIONS to Get Allowed Operations

6.使用OPTIONS来获取允许的操作

Next, we’re going to have a quick look at using an OPTIONS request and exploring the allowed operations on a specific URI using this kind of request; the API is optionsForAllow:

接下来,我们将快速浏览一下使用OPTIONS请求,并使用这种请求探索特定URI上允许的操作;API是optionsForAllow

Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);
HttpMethod[] supportedMethods
  = {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};
Assertions.assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));

7. Use PUT to Update a Resource

7.使用PUT更新一个资源

Next, we’ll start looking at PUT and more specifically the exchange() API for this operation, since the template.put API is pretty straightforward.

接下来,我们将开始研究PUT,更具体地说,是这个操作的exchange() API,因为template.put API是非常简单的。

7.1. Simple PUT With exchange()

7.1.简单的PUTexchange()

We’ll start with a simple PUT operation against the API — and keep in mind that the operation isn’t returning a body back to the client:

我们将从一个针对API的简单的PUT操作开始–请记住,这个操作并不返回一个主体给客户端。

Foo updatedInstance = new Foo("newName");
updatedInstance.setId(createResponse.getBody().getId());
String resourceUrl = 
  fooResourceUrl + '/' + createResponse.getBody().getId();
HttpEntity<Foo> requestUpdate = new HttpEntity<>(updatedInstance, headers);
template.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class);

7.2. PUT With exchange() and a Request Callback

7.2.使用exchange()和请求回调的PUT

Next, we’re going to be using a request callback to issue a PUT.

接下来,我们将使用一个请求回调来发布一个PUT。

Let’s make sure we prepare the callback, where we can set all the headers we need as well as a request body:

让我们确保我们准备好回调,在那里我们可以设置所有我们需要的头信息以及请求主体。

RequestCallback requestCallback(final Foo updatedInstance) {
    return clientHttpRequest -> {
        ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(clientHttpRequest.getBody(), updatedInstance);
        clientHttpRequest.getHeaders().add(
          HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        clientHttpRequest.getHeaders().add(
          HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass());
    };
}

Next, we create the Resource with a POST request:

接下来,我们用一个POST请求来创建资源。

ResponseEntity<Foo> response = restTemplate
  .exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);

And then we update the Resource:

然后我们更新资源。

Foo updatedInstance = new Foo("newName");
updatedInstance.setId(response.getBody().getId());
String resourceUrl =fooResourceUrl + '/' + response.getBody().getId();
restTemplate.execute(
  resourceUrl, 
  HttpMethod.PUT, 
  requestCallback(updatedInstance), 
  clientHttpResponse -> null);

8. Use DELETE to Remove a Resource

8.使用DELETE删除一个资源

To remove an existing Resource, we’ll make quick use of the delete() API:

为了删除一个现有的资源,我们将快速使用delete() API。

String entityUrl = fooResourceUrl + "/" + existingResource.getId();
restTemplate.delete(entityUrl);

9. Configure Timeout

9.配置超时

We can configure RestTemplate to time out by simply using ClientHttpRequestFactory:

我们可以通过简单地使用ClientHttpRequestFactory来配置RestTemplate来超时。

RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int timeout = 5000;
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
      = new HttpComponentsClientHttpRequestFactory();
    clientHttpRequestFactory.setConnectTimeout(timeout);
    return clientHttpRequestFactory;
}

And we can use HttpClient for further configuration options:

而我们可以使用HttpClient来进一步配置选项。

private ClientHttpRequestFactory getClientHttpRequestFactory() {
    int timeout = 5000;
    RequestConfig config = RequestConfig.custom()
      .setConnectTimeout(timeout)
      .setConnectionRequestTimeout(timeout)
      .setSocketTimeout(timeout)
      .build();
    CloseableHttpClient client = HttpClientBuilder
      .create()
      .setDefaultRequestConfig(config)
      .build();
    return new HttpComponentsClientHttpRequestFactory(client);
}

10. Conclusion

10.结论

In this article, we went over the main HTTP Verbs, using RestTemplate to orchestrate requests using all of these.

在这篇文章中,我们讨论了主要的HTTP动词,使用RestTemplate来协调使用所有这些动词的请求。

If you want to dig into how to do authentication with the template, check out our article on Basic Auth with RestTemplate.

如果您想深入了解如何使用模板进行身份验证,请查看我们关于Basic Auth with RestTemplate的文章。

The implementation of all these examples and code snippets can be found over on GitHub.

所有这些例子和代码片段的实现都可以在GitHub上找到over on GitHub.