16.4.10 交换资源

到目前为止,我们已经看到 RestTemplate 的各种方法来 GET、PUT、DELETE 以及 POST 资源。在它们之中,我们看到两个特殊的方法:getForEntity() 和 postForEntity(),这两个方法将结果资源包含在一个 ResponseEntity 对象中,通过这个对象我们可以得到响应头和状态码。

能够从响应中读取头信息是很有用的。但是如果你想在发送给服务端的请求中设置头信息的话,怎么办呢?这就是 RestTemplate 的 exchange() 的用武之地。

像 RestTemplate 的其他方法一样,exchange() 也重载为三个签名格式。一个使用 java.net.URI 来标识目标 URL,而其他两个以 String 的形式传入 URL 并带有 URL 变量。如下所示:

<T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity,
			Class<T> responseType) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
			Class<T> responseType, Object... uriVariables) throws RestClientException;

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
			Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

exchange() 方法使用 HttpMethod 参数来表明要使用的 HTTP 动作。根据这个参数的值,exchange() 能够执行与其他 RestTemplate 方法一样的工作。

例如,从服务器端获取 Spitter 资源的一种方式是使用 RestTemplate 的 getForEntity() 方法,如下所示:

ResponseEntity<Spitter> response = rest.getForEntity(
  "http://localhost:8080/spittr-api/spitters/{spitter}",
  Spitter.class, spitterId);
Spitter spitter = response.getBody();

在下面的代码片段中,可以看到 exchange() 也可以完成这项任务:

ResponseEntity<Spitter> response = rest.exchange(
  "http://localhost:8080/spittr-api/spitters/{spitter}",
  HttpMethod.GET, null, Spitter.class, spitterId);
Spitter spitter = response.getBody();

通过传入 HttpMethod.GET 作为 HTTP 动作,我们会要求 exchange() 发送一个 GET 请求。第三个参数是用于在请求中发送资源的,但因为这是一个 GET 请求,它可以是 null。下一个参数表明我们希望将响应转换为 Spitter 对象。最后一个参数用于替换 URL 模板中 {spitter} 占位符的值。

按照这种方式,exchange() 与之前使用的 getForEntity() 是几乎相同的,但是,不同于 getForEntity() —— 或 getForObject() —— exchange() 方法允许在请求中设置头信息。接下来,我们不再给 exchange() 传递 null,而是传入带有请求头信息的 HttpEntity。

如果不指明头信息,exchange() 对 Spitter 的 GET 请求会带有如下的头信息:

GET /Spitter/spitters/habuma HTTP/1.1
Accept: application/xml, text/xml, application/*+xml, application/json
Content-Length: 0
User-Agent: Java/1.6.0_20
Host: localhost:8080
Connection: keep-alive

让我们看一下 Accept 头信息。Accept 头信息表明它能够接受多种不同的 XML 内容类型以及 application/json。这样服务器端在决定采用哪种格式返回资源时,就有很大的可选空间。假设我们希望服务端以 JSON 格式发送资源。在这种情况下,我们需要将 “application/json” 设置为 Accept 头信息的唯一值。

设置请求头信息是很简单的,只需构造发送给 exchange() 方法的 HttpEntity 对象即可,HttpEntity 中包含承载头信息的 MultiValueMap:

MultiValue<String, String> headers = new LinkedMultiValue<String, String>();
headers.add("Accept", "application/json");
HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);

在这里,我们创建了一个 LinkedMultiValueMap 并添加值为 “application/json” 的 Accept 头信息。接下来,我们构建了一个 HttpEntity(使用 Object 泛型类型),将 MultiValueMap 作为构造参数传入。如果这是一个 PUT 或 POST 请求,我们需要为 HttpEntity 设置在请求体中发送的对象 —— 对于 GET 请求来说,这是没有必要的。

现在,我们可以传入 HttpEntity 来调用 exchange():

ResponseEntity<Spitter> response = rest.exchange(
  "http://localhost:8080/spittr-api/spitters/{spitter}",
  HttpMethod.GET, requestEntity, Spitter.class, spitterId);
Spitter spitter = response.getBody();

表面上看,结果是一样的。我们得到了请求的 Spitter 对象。但在表面之下,请求将会带有如下的头信息发送:

GET /Spitter/spitters/habuma HTTP/1.1
Accept: application/json
Content-Length: 0
User-Agent: Java/1.6.0_20
Host: localhost:8080
Connection: keep-alive

假设服务器端能够将 Spitter 序列化为 JSON,响应体将会以 JSON 格式来进行表述。

Last updated