# 16.4.5　PUT 资源

为了对数据进行 PUT 操作，RestTemplate 提供了三个简单的 put() 方法。就像其他的 RestTemplate 方法一样，put() 方法有三种形式：

```java
void put(String url, Object request, Object... uriVariables) throws RestClientException;

void put(String url, Object request, Map<String, ?> uriVariables) throws RestClientException;

void put(URI url, Object request) throws RestClientException;
```

按照它最简单的形式，put() 接受一个 java.net.URI，用来标识（及定位）要将资源发送到服务器上，另外还接受一个对象，这代表了资源的 Java 表述。

例如，以下展现了如何使用基于 URI 版本的 put() 方法来更新服务器上的 Spittle 资源：

```java
public void updateSpittle(Spittle spittle) throws SpitterException {
  RestTemplate rest = new RestTemplate();
  String url = "http://localhost:8080/spittr-api/spittles/" + spittle.getId();
  rest.put(URI.create(url), spittle);
}
```

在这里，尽管方法签名很简单，但是使用 java.net.URI 作为参数的影响很明显。为了创建所更新 Spittle 对象的 URL，我们要进行字符串拼接。

从 getForObject() 和 getForEntity() 方法中我们也看到了，使用基于 String 的其他 put() 方法能够为我们减少创建 URI 的不便。这些方法可以将 URI 指定为模板并对可变部分插入值。以下是使用基于 String 的 put() 方法重写的 updateSpittle()：

```java
public void updateSpittle(Spittle spittle) throws SpitterException {
  RestTemplate rest = new RestTemplate();
  rest.put("http://localhost:8080/spittr-api/spittles/{id}",
    spittle, spittle.getId());
}
```

现在的 URI 使用简单的 String 模板来进行表示。当 RestTemplate 发送 PUT 请求时，URI 模板将 {id} 部分用 spittle.getId() 方法的返回值来进行替换。就像 getForObject() 和 getForEntity() 一样，这个版本的 put() 方法最后一个参数是大小可变的参数列表，每一个值会出现按照顺序赋值给占位符变量。

你还可以将模板参数作为 Map 传递进来：

```java
public void updateSpittle(Spittle spittle) throws SpitterException {
  RestTemplate rest = new RestTemplate();
  Map<String, String> params = new HashMap<String, String>();
  params.put("id", spittle.getId());
  rest.put("http://localhost:8080/spittr-api/spittles/{id}",
    spittle, params);
}
```

当使用 Map 来传递模板参数时，Map 条目的每个 key 值与 URI 模板中占位符变量的名字相同。

在所有版本的 put() 中，第二个参数都是表示资源的 Java 对象，它将按照指定的 URI 发送到服务器端。在本示例中，它是一个 Spittle 对象。RestTemplate 将使用表 16.1 中的某个 HTTP 消息转换器将 Spittle 对象转换为一种表述形式，并在请求体中将其发送到服务器端。

对象将被转换成什么样的内容类型很大程度上取决于传递给 put() 方法的类型。如果给定一个 String 值，那么将会使用 StringHttpMessageConverter：这个值直接被写到请求体中，内容类型设置为 “text/plain”。如果给定一个 MultiValueMap\<String, String>，那么这个 Map 中的值将会被 FormHttpMessageConverter 以 “application/x-wwwform- urlencoded” 的格式写到请求体中。

因为我们传递进来的是 Spittle 对象，所以需要一个能够处理任意对象的信息转换器。如果在类路径下包含 Jackson 2 库，那 么 MappingJacksonHttpMessageConverter 将以 application/json 格式将 Spittle 写到请求中。
