RestTemplate简明教程
本文我们学习Spring REST 客户端 – RestTemplate,包括其各种操作如何使用。
1. 使用GET方法获取资源
示例中使用到的Foo实体类定义:
@Data
public class Foo {
private long id;
private String name;
public Foo() {
super();
}
public Foo(final String name) {
super();
this.name = name;
}
public Foo(final long id, final String name) {
super();
this.id = id;
this.name = name;
}
}
测试的服务器端rest 接口代码:
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@Controller
public class FooController {
private Map<Long, Foo> fooRepository = Maps.newHashMap(ImmutableMap.of(1L, new Foo(1L, randomAlphabetic(4))));
public FooController() {
super();
}
@RequestMapping(method = RequestMethod.GET, value = "/foos")
@ResponseBody
public Collection<Foo> findListOfFoo() {
return fooRepository.values();
}
// API - read
@RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
@ResponseBody
public Foo findById(@PathVariable final long id) throws HttpClientErrorException {
Foo foo = fooRepository.get(id);
if (foo == null) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
} else {
return foo;
}
}
// API - write
@RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Foo updateFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) {
fooRepository.put(id, foo);
return foo;
}
@RequestMapping(method = RequestMethod.PATCH, value = "/foos/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Foo patchFoo(@PathVariable("id") final long id, @RequestBody final Foo foo) {
fooRepository.put(id, foo);
return foo;
}
@RequestMapping(method = RequestMethod.POST, value = "/foos")
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public ResponseEntity<Foo> postFoo(@RequestBody final Foo foo) {
fooRepository.put(foo.getId(), foo);
final URI location = ServletUriComponentsBuilder
.fromCurrentServletMapping()
.path("/foos/{id}")
.build()
.expand(foo.getId())
.toUri();
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(location);
final ResponseEntity<Foo> entity = new ResponseEntity<Foo>(foo, headers, HttpStatus.CREATED);
return entity;
}
@RequestMapping(method = RequestMethod.HEAD, value = "/foos")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Foo headFoo() {
return new Foo(1, randomAlphabetic(4));
}
@RequestMapping(method = RequestMethod.POST, value = "/foos/new")
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public Foo createFoo(@RequestBody final Foo foo) {
fooRepository.put(foo.getId(), foo);
return foo;
}
@RequestMapping(method = RequestMethod.DELETE, value = "/foos/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public long deleteFoo(@PathVariable final long id) {
fooRepository.remove(id);
return id;
}
@RequestMapping(method = RequestMethod.POST, value = "/foos/form")
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public String submitFoo(@RequestParam("id") String id) {
return id;
}
}
1.1. 获取json
首先从简单的GET请求开始————使用getForEntity()方法的示例:
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
Http 响应也是可以访问,和检查状态码一样,也可以检查响应的内容是否正确,即检查响应体:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.getBody());
JsonNode name = root.path("name");
assertThat(name.asText(), notNullValue());
上面验证响应体中的字符串类型,使用Jackson提供的JsonNode验证一些细节。
1.2. 获取POJO
可以直接把响应体映射值POJO,一般为DTO类。现在可以调用getForObject方法:
Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
assertThat(foo.getName(), notNullValue());
assertThat(foo.getId(), is(1L));
2. 使用HEAD获取请求头
现在看下使用HEAD请求获取请求头,使用headForHeaders方法:
HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
3. 使用POST创建资源
创建资源可以使用三个API ———— postForLocation(), postForObject() , postForEntity()。
第一个返回新创建资源的uri,第二个返回资源本身。
3.1. postForObject API
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);
assertThat(foo, notNullValue());
assertThat(foo.getName(), is("bar"));
3.2. postForLocation API
与上面方法类似,postForLocation返回并返回资源,而是返回新增资源的uri:
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
URI location = restTemplate.postForLocation(fooResourceUrl, request);
assertThat(location, notNullValue());
4.3. exchange API
下面看看如何使用更通过 exchange API:
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
ResponseEntity<Foo> response = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
Foo foo = response.getBody();
assertThat(foo, notNullValue());
assertThat(foo.getName(), is("bar"));
3.4. 提交表单数据
接下来,看看如何提交表单数据,首先我们需要设置请求头的属性Content-Type” 为application/x-www-form-urlencoded。
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服务接口:
ResponseEntity<String> response = restTemplate.postForEntity(
fooResourceUrl+"/form", request , String.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
4. 使用OPTIONS获取所有支持的操作
接下来看使用OPTIONS获取特定URI所支持的操作,使用optionsForAllow:
Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);
HttpMethod[] supportedMethods
= {HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE};
assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));
5. 使用PUT更新资源
put方法非常简单。我们通过更通用的exchange实现put功能。
5.1. 使用exchange实现简单put操作
首先开始简单的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);
5.2. 使用exchange实现简单put操作
接下来使用请求回调来发出PUT请求。首先定义回调方法————设置所有必要的头信息以及请求体:
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());
};
}
requestCallback用于在请求发出之前修改请求头信息,实现一些额外公共业务功能,如加密或解密。
然后使用POST请求创建资源:
ResponseEntity<Foo> response = restTemplate
.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
接着更新资源,这里第三个参数指明了回调函数,clientHttpResponse参数用于对响应信息进行自定义解析。
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);
6. 使用DELETE删除资源
使用delete() 方法删除资源:
String entityUrl = fooResourceUrl + "/" + existingResource.getId();
restTemplate.delete(entityUrl);
7. 配置超时
可以简单通过 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);
}
8. 总结
本文介绍了通过RestTemplate实现调用HTTP的各种请求操作。实际开发中用得最多请求方式为GET和POST,其他方式为了安全考虑一般在应用服务器层配置禁用。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/100749098