1. 概述
本教程將演示 Spring REST Client — RestTemplate — 可以用於的廣泛操作,並展示其高效使用。
對於所有示例中的 API 端,我們將從 這裏 運行 RESTful 服務。
2. 使用 GET 檢索資源
2.1. 獲取純 JSON
讓我們從簡單開始,討論 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);
請注意,我們擁有對 HTTP 響應的完整訪問權限,因此我們可以執行諸如檢查狀態碼以確保操作成功或處理實際響應體等操作:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode name = root.path("name");
Assertions.assertNotNull(name.asText());我們正在使用響應體作為標準 String 進行處理,並使用 Jackson(以及 Jackson 提供的 JSON 節點結構)來驗證一些細節。
2.2. 通過映射資源 DTO 而不是 JSON 獲取響應
我們可以直接將響應映射到資源 DTO:
public class Foo implements Serializable {
private long id;
private String name;
// standard getters and setters
}現在我們可以直接使用模板中的 getForObject API:
Foo foo = restTemplate
.getForObject(fooResourceUrl + "/1", Foo.class);
Assertions.assertNotNull(foo.getName());
Assertions.assertEquals(foo.getId(), 1L);
3. 使用 HEAD 獲取 Headers
現在我們快速瞭解一下如何使用 HEAD,然後再轉向更常用的方法。
我們將使用 headForHeaders() API。
HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
Assertions.assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));4. 使用 POST 創建資源
為了在 API 中創建新的資源,我們可以充分利用 postForLocation()、postForObject() 或 postForEntity() 這些 API。
第一個返回新創建的資源的 URI,第二個返回資源本身。
4.1. <em >postForObject()</em> 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");4.2. postForLocation() API
類似於地,讓我們來查看一個操作,它不返回完整的
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
URI location = restTemplate
.postForLocation(fooResourceUrl, request);
Assertions.assertNotNull(location);4.3. <em място>exchange() API
讓我們來看一下如何使用更通用的 exchange API 進行 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");
4.4. 提交表單數據
接下來,我們來看如何使用 POST 方法提交表單。
首先,我們需要將 Content-Type 頭設置為 application/x-www-form-urlencoded.
這確保了包含 name/value 對的查詢字符串可以被髮送到服務器,這些 name/value 對之間用 & 分隔。
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);我們可以在表單變量中將其包裝到一個 LinkedMultiValueMap 中:
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "1");接下來,我們使用 HttpEntity實例構建請求:
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);最後,我們可以通過調用 <a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#postForEntity-java.net.URI-java.lang.Object-java.lang.Class-">restTemplate.postForEntity()</a> 在 Endpoint: /foos/form 上進行連接。
ResponseEntity<String> response = restTemplate.postForEntity(
fooResourceUrl + "/form", request , String.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);
5. 使用 OPTIONS 獲取允許的操作
接下來,我們將快速瞭解如何使用 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)));
6. 使用 PUT 更新資源
接下來,我們將探討 PUT 以及更具體地説,用於此操作的 exchange() API,因為 template.put API 相當簡單。
6.1. 簡單的 PUT 請求中使用 exchange()
我們將從一個簡單的 PUT 請求到 API 開始,請注意,該操作不會將響應體返回給客户端:
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);6.2. 使用 exchange() 和請求回調進行 PUT 請求
接下來,我們將使用請求回調來發出 PUT 請求。
讓我們準備好回調函數,以便設置所需的全部請求頭以及請求體:
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());
};
}接下來,我們使用 POST 請求創建資源:
ResponseEntity<Foo> response = restTemplate
.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);
然後我們更新資源:
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);7. 使用 DELETE 刪除資源
要刪除現有資源,我們將快速使用 delete() API:
String entityUrl = fooResourceUrl + "/" + existingResource.getId();
restTemplate.delete(entityUrl);
8. 配置超時時間
我們可以配置四種不同的超時時間類型:
- 連接超時 – 等待 HTTP 連接建立的時間。我們將其配置在 RequestConfig 中
- 讀取超時 – 客户端等待服務器響應的時間。我們將其配置在 RequestConfig 中
- 套接字超時 – 用於 SSL 手動交換或 CONNECT 請求的連接超時。我們將其配置在 SocketConfig 中
- 連接請求超時 – 等待從 RequestConfig 的連接管理器請求連接的時間
我們可以通過簡單地使用 ClientHttpRequestFactory 來配置 RestTemplate 的超時時間。
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectionRequestTimeout(timeout*1000);
clientHttpRequestFactory.setConnectTimeout(timeout*2000);
clientHttpRequestFactory.setReadTimeout(timeout*3000);
return clientHttpRequestFactory;
}此外,我們可以使用 HttpClient 來配置各種超時選項。
這種方法的優勢在於,我們還可以通過 ConnectionConfig, RequestConfig, 和 SocketConfig 設置其他配置選項。
ClientHttpRequestFactory getClientHttpRequestFactoryAlternate() {
long timeout = 5;
int readTimeout = 5;
// Connect timeout
ConnectionConfig connectionConfig = ConnectionConfig.custom()
.setConnectTimeout(Timeout.ofMilliseconds(timeout*1000))
.build();
// Connection Request timeout
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(Timeout.ofMilliseconds(timeout*2000))
.build();
// Socket timeout
SocketConfig socketConfig = SocketConfig.custom()
.setSoTimeout(Timeout.ofMilliseconds(timeout*1000)).build();
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setDefaultSocketConfig(socketConfig);
connectionManager.setDefaultConnectionConfig(connectionConfig);
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
HttpComponentsClientHttpRequestFactory(httpClient);
// Read timeout
clientHttpRequestFactory.setReadTimeout(readTimeout*3000);
return clientHttpRequestFactory;
}9. 結論
本文介紹了主要的 HTTP 動詞,並使用 RestTemplate 來協調這些請求。
如果您想深入瞭解如何使用模板進行身份驗證,請查看我們關於 RestTemplate 中 Basic Auth 的文章。