Files
rikako-note/spring/Spring Http Client/Spring RestTemplate.md

112 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RestTemplate
RestTemplate提供了比http client library更高层级的api其允许以更加容易的方式来调用rest接口。
## 初始化
RestTemplate的默认构造函数使用`java.net.HttpURLConnection`来执行http请求。
## URIs
RestTemplate的许多方法都接收一个URI template和URI tempalte变量要么作为`String`变量参数,要么作为`Map<String,String>`.
如下示例使用了String类型参数
```java
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");
```
如下示例则是使用了Map类型的参数
```java
Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(
"https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);
```
URI tempalte是自动编码的按如下示例所示
```java
restTemplate.getForObject("https://example.com/hotel list", String.class);
// Results in request to "https://example.com/hotel%20list"
```
## headers
可以通过`exchange()`方法来指定请求的headers如下所示
```java
String uriTemplate = "https://example.com/hotels/{hotel}";
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.header("MyRequestHeader", "MyValue")
.build();
ResponseEntity<String> response = template.exchange(requestEntity, String.class);
String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();
```
## body
向RestTemplate中方法传入的参数或RestTemplate方法返回的对象其与raw content之间的转换都是通过`HttpMessageConverter`来执行的。
在一个POST请求中传入到RestTemplate方法中的参数会被序列化到请求的body中
```java
URI location = template.postForLocation("https://example.com/people", person);
```
**使用者并不需要显式设置请求体的`Content-Type`header**。在大多数情况下都可以基于source Object类型找到一个合适的message converter而被选中的message converter则会设置content type header。如果在必要情况下可以通过`exchange`方法来显式提供`Content-Type` header并且在设置content type请求头之后会影响选中的message converter。
如下示例显示了一个get请求将响应的body反序列化为方法的返回类型
```java
Person person = restTemplate.getForObject("https://example.com/people/{id}", Person.class, 42);
```
类似于`Content-Type`请求头,`Accept`请求头也不需要显式设置。在多数情况下根据方法返回类型选中的message converter会帮助注入Accept请求头。在必要情况下可以通过`exchange()`方法来指定要传递的`Accept`请求头。
默认情况下RestTemplate注册了所有内置的message converter。
## Multipart
如果需要发送multipart数据需要提供一个`MultiValueMap<String,Object>`该map的value可以是一个part content objectfile part resource含有part content和header的HttpEntity。
```java
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
```
当MultiValueMap构建好之后可以将其传递给RestTemplate如下所示
```java
MultiValueMap<String, Object> parts = ...;
template.postForObject("https://example.com/upload", parts, Void.class);
```
如果MultiValueMap至少含有一个不为String的值那么Content-Type将会被`FormHttpMessageConverter`设置为`multipart/form-data`
如果MultiValueMap中只有String类型的值那么content-type会被设置为`application/x-www-form-urlencoded`
## Http接口
Spring允许将Http service定义为java接口该方法上有注解用于http交换。可以通过该接口产生一个代理对象实现该接口代理对象可以执行http请求交换。
首先,定义一个接口,并且通过`@HttpExchange`注解来标注接口中的方法:
```java
interface RepositoryService {
@GetExchange("/repos/{owner}/{repo}")
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
// more HTTP exchange methods...
}
```
其次可以创建一个代理对象来执行http请求创建方式如下所示
```java
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
RepositoryService service = factory.createClient(RepositoryService.class);
```
`@HttpExchange`注解也支持类级别,类级别注解将会应用到接口中所有的方法:
```java
@HttpExchange(url = "/repos/{owner}/{repo}", accept = "application/vnd.github.v3+json")
interface RepositoryService {
@GetExchange
Repository getRepository(@PathVariable String owner, @PathVariable String repo);
@PatchExchange(contentType = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
void updateRepository(@PathVariable String owner, @PathVariable String repo,
@RequestParam String name, @RequestParam String description, @RequestParam String homepage);
}
```