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

5.5 KiB
Raw Blame History

RestTemplate

RestTemplate提供了比http client library更高层级的api其允许以更加容易的方式来调用rest接口。

初始化

RestTemplate的默认构造函数使用java.net.HttpURLConnection来执行http请求。

URIs

RestTemplate的许多方法都接收一个URI template和URI tempalte变量要么作为String变量参数,要么作为Map<String,String>.
如下示例使用了String类型参数

String result = restTemplate.getForObject(
        "https://example.com/hotels/{hotel}/bookings/{booking}", String.class, "42", "21");

如下示例则是使用了Map类型的参数

Map<String, String> vars = Collections.singletonMap("hotel", "42");

String result = restTemplate.getForObject(
        "https://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

URI tempalte是自动编码的按如下示例所示

restTemplate.getForObject("https://example.com/hotel list", String.class);

// Results in request to "https://example.com/hotel%20list"

headers

可以通过exchange()方法来指定请求的headers如下所示

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中

URI location = template.postForLocation("https://example.com/people", person);

使用者并不需要显式设置请求体的Content-Typeheader。在大多数情况下都可以基于source Object类型找到一个合适的message converter而被选中的message converter则会设置content type header。如果在必要情况下可以通过exchange方法来显式提供Content-Type header并且在设置content type请求头之后会影响选中的message converter。
如下示例显示了一个get请求将响应的body反序列化为方法的返回类型

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。

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如下所示

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注解来标注接口中的方法:

interface RepositoryService {

    @GetExchange("/repos/{owner}/{repo}")
    Repository getRepository(@PathVariable String owner, @PathVariable String repo);

    // more HTTP exchange methods...

}

其次可以创建一个代理对象来执行http请求创建方式如下所示

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注解也支持类级别,类级别注解将会应用到接口中所有的方法:

@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);

}