实际工作中我们经常会遇到利用 java 去访问其他接口获取数据,常用的有 JDK 原生的 HttpURLConnection 无需依赖其他包,提供了很多方法;另外 HttpClient 也是我们的不二选择,在 spring 之前,我们经常会用 HttpClient 来处理;还有一种方式就是利用 Socket,使用起来比较麻烦;用了 spring 之后,RestTemplate 则更加方便,更加灵活。

一、概述

spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。

在Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring 模板类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。

RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。

考虑到RestTemplate类是为调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。例如,RestTemplate类具有headForHeaders()、getForObject()、postForObject()、put()和delete()等方法。

二、实现

最新api地址:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

RestTemplate包含以下几个部分:

HttpMessageConverter 对象转换器
ClientHttpRequestFactory 默认是JDK的HttpURLConnection
ResponseErrorHandler 异常处理
ClientHttpRequestInterceptor 请求拦截器

常规配置

1
2
3
4
5
6
7
8
public MyRestClientService(RestTemplateBuilder restTemplateBuilder) {  
this.restTemplate = restTemplateBuilder
.basicAuthorization("username", "password")
.setConnectTimeout(3000)
.setReadTimeout(5000)
.rootUri("http://api.example.com/")
.build();
}

ClientHttpRequestInterceptor
学习使用带有Spring RestTemplate的ClientHttpRequestInterceptor,以Spring AOP风格记录请求和响应头和主体。

拦截器记录请求和响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.Charset;

public class RequestResponseLoggingInterceptor implements ClientHttpRequestInterceptor {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
logRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
logResponse(response);

//Add optional additional headers
response.getHeaders().add("headerName", "VALUE");

return response;
}

private void logRequest(HttpRequest request, byte[] body) throws IOException
{
if (log.isDebugEnabled())
{
log.debug("===========================request begin================================================");
log.debug("URI : {}", request.getURI());
log.debug("Method : {}", request.getMethod());
log.debug("Headers : {}", request.getHeaders());
log.debug("Request body: {}", new String(body, "UTF-8"));
log.debug("==========================request end================================================");
}
}

private void logResponse(ClientHttpResponse response) throws IOException
{
if (log.isDebugEnabled())
{
log.debug("============================response begin==========================================");
log.debug("Status code : {}", response.getStatusCode());
log.debug("Status text : {}", response.getStatusText());
log.debug("Headers : {}", response.getHeaders());
log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
log.debug("=======================response end=================================================");
}
}
}

注册ClientHttpRequestInterceptor

1
2
3
4
5
6
7
8
9
10
11
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();

restTemplate.setRequestFactory(newBufferingClientHttpRequestFactory(clientHttpRequestFactory()));
restTemplate.setMessageConverters(Collections.singletonList(mappingJacksonHttpMessageConverter()));

restTemplate.setInterceptors( Collections.singletonList(newRequestResponseLoggingInterceptor()) );

return restTemplate;
}

三、使用

GET

1
2
3
4
5
6
7
8
private static void getEmployees(){
final String uri = "http://localhost:8080/springrestexample/employees";

RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);

System.out.println(result);
}

使用RestTemplate定制HTTP头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
private static void getEmployees(){
final String uri = "http://localhost:8080/springrestexample/employees";

RestTemplate restTemplate = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);

System.out.println(result);
}

Get请求获取响应为一个对象

1
2
3
4
5
6
7
8
private static void getEmployees(){
final String uri = "http://localhost:8080/springrestexample/employees";
RestTemplate restTemplate = new RestTemplate();

EmployeeListVO result = restTemplate.getForObject(uri, EmployeeListVO.class);

System.out.println(result);
}

URL 参数

1
2
3
4
5
6
7
8
9
10
11
private static void getEmployeeById(){
final String uri = "http://localhost:8080/springrestexample/employees/{id}";

Map<String, String> params = new HashMap<String, String>();
params.put("id", "1");

RestTemplate restTemplate = new RestTemplate();
EmployeeVO result = restTemplate.getForObject(uri, EmployeeVO.class, params);

System.out.println(result);
}

POST

1
2
3
4
5
6
7
8
9
10
private static void createEmployee(){
final String uri = "http://localhost:8080/springrestexample/employees";

EmployeeVO newEmployee = new EmployeeVO(-1, "Adam", "Gilly", "test@email.com");

RestTemplate restTemplate = new RestTemplate();
EmployeeVO result = restTemplate.postForObject( uri, newEmployee, EmployeeVO.class);

System.out.println(result);
}

Submit Form Data

1
2
3
4
5
6
7
8
9
10
11
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "1");

HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

RestTemplate restTemplate = new RestTemplate();
EmployeeVO result = restTemplate.postForObject( uri, request, EmployeeVO.class);
System.out.println(result);

PUT

1
2
3
4
5
6
7
8
9
10
11
private static void updateEmployee(){
final String uri = "http://localhost:8080/springrestexample/employees/{id}";

Map<String, String> params = new HashMap<String, String>();
params.put("id", "2");

EmployeeVO updatedEmployee = new EmployeeVO(2, "New Name", "Gilly", "test@email.com");

RestTemplate restTemplate = new RestTemplate();
restTemplate.put ( uri, updatedEmployee, params);
}

Simple PUT

1
2
3
4
5
6
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);

使用.exchange和请求回调

1
2
3
4
5
6
7
8
9
10
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());
};
}

DELETE

1
2
3
4
5
6
7
8
9
private static void deleteEmployee(){
final String uri = "http://localhost:8080/springrestexample/employees/{id}";

Map<String, String> params = new HashMap<String, String>();
params.put("id", "2");

RestTemplate restTemplate = new RestTemplate();
restTemplate.delete ( uri, params );
}

以上便是 Spring RestTemplate 在实际开发中使用的方法,请笑纳吧!

更多文章请关注微信公众号: 治恒说说