RestTemplate 教程
1、概览
本文将带你了解如何使用 Spring REST 客户端 RestTemplate
发起各种类型的 HTTP 请求。
2、废弃警告
从 Spring Framework 5 开始,除了 WebFlux,Spring 还引入了一个名为 WebClient
的新 HTTP 客户端。
WebClient
是一种替代 RestTemplate
的现代 HTTP 客户端。它不仅提供传统的同步 API,还支持高效的非阻塞和异步方法。
如果要开发新的应用或迁移旧的应用,最好还是使用 WebClient
。在未来版本中,RestTemplate
将被弃用。
3、使用 GET 检索资源
3.1、获取纯 JSON 格式
使用 getForEntity()
API 发起 GET 请求:
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 响应,因此可以检查 HTTP 状态码是否成功,或者处理响应体:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode name = root.path("name");
Assertions.assertNotNull(name.asText());
如上,将响应体作为标准字符串(String
)返回,并使用 Jackson(以及 Jackson 提供的 JSON 节点结构)来验证一些细节。
3.2、检索 POJO 而非 JSON
还可以将响应直接映射到资源 DTO:
public class Foo implements Serializable {
private long id;
private String name;
// 标准的 get 、set 方法
}
只需要调用 template 的 getForObject
API 即可:
Foo foo = restTemplate
.getForObject(fooResourceUrl + "/1", Foo.class);
Assertions.assertNotNull(foo.getName());
Assertions.assertEquals(foo.getId(), 1L);
4、使用 HEAD 检索 Header
使用 headForHeaders()
API:
HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
Assertions.assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
5、使用 POST 创建资源
可以使用 postForLocation()
、postForObject()
或 postForEntity()
方法 在 API 中创建新资源。
前者(postForLocation
)返回新创建资源的 URI,后者返回资源本身。
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、postForLocation()
API
不返回完整的资源,只返回新创建资源的位置:
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
URI location = restTemplate
.postForLocation(fooResourceUrl, request);
Assertions.assertNotNull(location);
5.3、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");
5.4、提交表单数据
接着来看看如何使用 POST 方法提交表单。
首先,需要将 Content-Type 头设置为 application/x-www-form-urlencoded。
这样就可以向服务器发送包含以 &
分隔的 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);
最后,可以调用 restTemplate.postForEntity()
来请求 REST 服务: /foos/form
ResponseEntity<String> response = restTemplate.postForEntity(
fooResourceUrl+"/form", request , String.class);
Assertions.assertEquals(response.getStatusCode(), HttpStatus.CREATED);
6、使用 OPTIONS 获取允许的操作
使用 optionsForAllow
方法来获取指定 URL 上允许的操作(请求方法):
Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);
HttpMethod[] supportedMethods
= {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};
Assertions.assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));
7、使用 PUT 请求更新资源
PUT
请求,更具体地说,是该请求的 exchange()
API。
7.1、使用 exchange() 发起简单的 PUT 请求
对 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、使用 exchange() 以回调方式发起 PUT 请求
如下,在回调中可以设置所需的所有 Header 信息以及请求体:
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);
8、使用 DELETE 删除资源
使用 delete()
API 删除现有资源:
String entityUrl = fooResourceUrl + "/" + existingResource.getId();
restTemplate.delete(entityUrl);
9、超时配置
只需使用 ClientHttpRequestFactory
就能配置 RestTemplate
超时:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
还可以通过 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、总结
本文介绍了如何使用 RestTemplate
发起各种方式的请求。
Ref:https://www.baeldung.com/rest-template