在微服务架构模式中,多个小型服务可以协同工作以提供一个特定的业务功能。这些服务之间可以通过REST API进行通信。要使用REST API,我们需要HTTP客户端,例如RestTemplate。RestTemplate是Spring框架提供的一个珍贵的HTTP客户端。它使开发人员能够使用HTTP请求进行远程调用。
一、RestTemplate的概述
RestTemplate是在Spring框架中提供的一个用于访问Rest服务的模板工具集,其实就是对HttpClient的封装。它提供了对HTTP请求生命周期的封装,使得开发者能够更方便地通过HTTP请求来调用Rest服务。
要使用RestTemplate,我们需要在Spring应用程序上下文中定义RestTemplate bean。可以使用如下语句快速创建RestTemplate:
RestTemplate restTemplate = new RestTemplate();
Spring提供了多种实现方式,包括Apache HttpClient以及Java原生URLConnection。它可以处理GET、POST、PUT、DELETE和其他HTTP请求方法,并且可以将服务端返回的JSON、XML和其他格式的数据进行转换。
二、实现RestTemplate基本使用
下面我们演示如何使用RestTemplate的GET请求方法。RestTemplate的getForObject()方法是RESTful API最好的工具。通过简单的代码行,我们就能够获取以JSON、XML等格式的数据。
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/student/get/{id}";
Map<String, String> uriParams = new HashMap<>();
uriParams.put("id", "1");
Student student = restTemplate.getForObject(url, Student.class, uriParams);
System.out.println(student);
以上代码中使用了getForObject方法,其中参数说明如下:
- url:目标URL,支持占位符URI。占位符以“{”和“}”包装,并且必须与url变量Map uriVariables和var-args参数(如果有)的键匹配。
- responseType:返回类型,其可以是一个正常的对象类型,例如Student,或将响应映射到集合类型,例如List<Student>
- uriVariables:占位符替换数组
除了GET请求方法,在RestTemplate中还有POST、PUT等常见的HTTP请求方法。这里就不详细展开了。
三、扩展RestTemplate的使用
1. 添加HTTP头信息
在发送HTTP请求时添加HTTP头信息,可以通过RestTemplate的Header请求头来实现:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
在以上示例中,我们将添加accept Http头来请求响应。在类HttpHeaders的实例化中,设置accept值为MediaType.APPLICATION_JSON,表示在响应中请求JSON数据。
2. 错误处理
在远程服务调用时,总会存在网络连接失败等异常情况,我们需要捕获这些异常,并对其进行处理。
RestTemplate提供了一个特殊的类RestClientException,用于捕获所有的异常。例如,我们可以通过以下方式在RestTemplate调用失败时捕获异常:
try {
ResponseEntity<String> response = restTemplate.getForEntity(URL, String.class);
} catch (RestClientException e) {
e.printStackTrace();
}
3. 异步调用RestTemplate
RestTemplate的请求是同步的,但是在高并发场景下,使用异步方式调用可以提高系统的性能。
Java8之前使用Callable和Future,Java8之后可以使用CompletableFuture。下面是Java8之前的代码:
RestTemplate restTemplate = new RestTemplate();
String url = "localhost:8080/index";
Callable<Map> task = () -> {
ResponseEntity<Map> exchange = restTemplate.exchange(url, HttpMethod.GET, request, Map.class);
return exchange.getBody();
};
FutureTask<Map> futureTask = new FutureTask<Map>(task);
new Thread(futureTask).start();
Map result = futureTask.get();
使用CompletableFuture的代码如下所示:
RestTemplate restTemplate = new RestTemplate();
String url = "localhost:8080/index";
CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
restTemplate.getForObject(url, String.class));
String result = future.get();
4. 自定义HttpMessageConverter
RestTemplate通过使用HttpMessageConverter将Http请求和响应转换为对象。默认情况下,HttpClient支持JSON和XML。如果您的服务端将数据提供为Jackson、Gson、XML或您自己的格式,您可以编写自定义消息转换器。
下面是一个自定义的消息转换器:
public class MappingJackson2CalendarHttpMessageConverter extends MappingJackson2HttpMessageConverter {
public MappingJackson2CalendarHttpMessageConverter() {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON);
setSupportedMediaTypes(mediaTypes);
}
@Override
protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
ObjectMapper mapper = getObjectMapper();
ObjectWriter writer = mapper.writerWithView(Views.Public.class);
writer.writeValue(outputMessage.getBody(), object);
}
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
ObjectMapper mapper = getObjectMapper();
return mapper.readValue(inputMessage.getBody(), getJavaType(clazz));
}
}
上述代码演示了继承MappingJackson2HttpMessageConverter并支持MediaType为application/json的文件格式。自定义的消息转换器MappingJackson2CalendarHttpMessageConverter允许您通过重写readInternal和writeInternal方法将请求和响应转换为所需的数据格式。
四、总结
RestTemplate是一个非常强大的HTTP客户端,可以用于与第三方REST服务进行通信,获取JSON/XML等数据,并对其进行处理。本文介绍了RestTemplate的基本用法、扩展用法、以及自定义实现HttpMessageConverter的用法。希望可以帮助到大家。