【springboot应用-RestTemplate】
简介
RestTemplate 提供了一个高层次的抽象来访问 HTTP 资源,支持通过模板方法执行常见的 HTTP 请求操作,如 GET、POST、PUT、DELETE 等。它简化了与 HTTP 服务的交互,使得代码更简洁、易读。
功能特点
- 多种请求方式:支持 GET、POST、PUT、DELETE 等多种 HTTP 方法。
- 连接管理:内部使用连接池来管理 HTTP 连接,提高性能。
- 错误处理:提供了异常处理机制,方便错误管理。
- 消息转换:支持多种消息转换方式,如 JSON、XML 等。
- 模板方法:提供了模板方法来简化请求参数的设置。
使用步骤
- 添加依赖
如果您使用的是 Maven,确保在 pom.xml 文件中添加了 Spring Web 依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.10</version>
</dependency>
- 创建 RestTemplate 实例
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
- 执行 GET 请求
使用 RestTemplate 发送 GET 请求并接收响应:
String url = "http://example.com/api/data";
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
String responseBody = response.getBody();
- 执行 POST 请求
发送一个包含请求体的 POST 请求:
MyRequestData data = new MyRequestData();
data.setName("lixiaoyi");
ResponseEntity<MyResponseData> response = restTemplate.postForEntity(url, data, MyResponseData.class);
MyResponseData responseBody = response.getBody();
- 配置请求
可以配置 RestTemplate 以自定义连接工厂、消息转换器等:
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(5000);
factory.setReadTimeout(5000);
restTemplate.setRequestFactory(factory);
- 异常处理
RestTemplate 可能会抛出 RestClientException,您可以捕获并处理这个异常:
try {
restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
// 处理异常
}
注意事项
- 异常处理:RestTemplate 抛出的异常应该被捕获并适当处理。
- 线程安全:RestTemplate 是线程安全的,可以在多个线程中使用同一个实例。
- 响应类型:在定义响应类型时,确保与返回的数据类型匹配。
实战项目
封装请求工具类
- RestUtil
/**
* RestAPI 调用器
*/
private final static RestTemplate RT;
static {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(30000);
requestFactory.setReadTimeout(4000000);
RT = new RestTemplate(requestFactory);
// 解决乱码问题
RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
// 新增个性化日志
List<ClientHttpRequestInterceptor> interceptors = Optional.ofNullable(RT.getInterceptors()).orElse(new ArrayList<>());
RestTemplateLogInterceptor restTemplateLogInterceptor = SpringContextUtils.getBean(RestTemplateLogInterceptor.class);
interceptors.add(restTemplateLogInterceptor);
RT.setInterceptors(interceptors);
}
public static RestTemplate getRestTemplate() {
return RT;
}
public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, JSONObject params, Class<T> responseType) {
if (StringUtils.isEmpty(url)) {
throw new RuntimeException("url 不能为空");
}
if (method == null) {
throw new RuntimeException("method 不能为空");
}
if (headers == null) {
headers = new HttpHeaders();
}
// 请求体
String body = "";
if (params != null) {
body = JSONArray.toJSONString(params, SerializerFeature.WriteMapNullValue);
}
// 拼接 url 参数
if (variables != null) {
url += ("?" + asUrlVariables(variables));
}
// 发送请求
HttpEntity<String> request = new HttpEntity<>(body, headers);
return RT.exchange(url, method, request, responseType);
}
- RestTemplateLogInterceptor 定义的抽象接口,实现交给各个业务模块
/**
* @author: lixiaoyi
* @date: 2024年10月20日20:09:03
* @description: 记录restTemplate日志 , 实现交给各个模块
*/
public interface RestTemplateLogInterceptor extends ClientHttpRequestInterceptor {
}
- LoggingInterceptor 日志实现
@Component
public class LoggingInterceptor implements RestTemplateLogInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
try {
// 记录日志
ApiForOtherRestUtil.saveLog(request.getURI().toString(), getRequest(request,body), getResponseBody(response));
}catch (Exception e){
e.printStackTrace();
}
return response;
}
private String getRequest(HttpRequest request, byte[] body) {
// 记录请求方法、URL、头信息和请求体
return new String(body);
}
private String getResponseBody(ClientHttpResponse response) throws IOException {
InputStream inputStream = response.getBody();
// 记录响应状态码、头信息和响应体
StringBuilder responseBody = new StringBuilder();
// 使用try-with-resources语句自动关闭流
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
responseBody.append(line).append(System.lineSeparator());
}
} catch (IOException e) {
// 处理或记录异常
e.printStackTrace();
}
// 打印响应状态码和响应体
return responseBody.toString();
}
}
和HttpClient 对比
- RestTemplate 优势
- 集成性:RestTemplate 是 Spring 框架的一部分,与 Spring 框架集成良好,提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率
。 - 易用性:RestTemplate 提供了同步的 API 来发送 HTTP 请求,使用起来相对简单,适合快速开发。
模板方法:提供了模板方法来简化请求参数的设置,使得代码更加简洁。
错误处理:提供了异常处理机制,方便错误管理。
- 集成性:RestTemplate 是 Spring 框架的一部分,与 Spring 框架集成良好,提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率
- RestTemplate 劣势
- 性能:默认情况下,RestTemplate 使用 HttpURLConnection,没有连接池,性能相对较低。
- 非异步:RestTemplate 是同步的,不适合需要异步处理的场景。
- 资源管理:需要手动管理连接的关闭,否则可能会导致资源泄露。
- HttpClient 优势
- 连接池:HttpClient 支持连接池,可以提高频繁请求的性能。
- 异步支持:HttpClient 支持异步请求,适合需要异步处理的场景。
- 配置灵活:HttpClient 提供了灵活的配置选项,包括超时设置、重试策略等。
- 协议支持:HttpClient 支持多种 HTTP 协议的方法,包括但不限于 GET、POST、PUT、DELETE 等。
- HttpClient 劣势
- 复杂性:HttpClient 的 API 相对复杂,需要更多的配置和手动管理。
- 资源管理:虽然支持连接池,但也意味着需要正确管理资源,否则可能会导致资源泄露。
- 社区活跃度:由于 Android 等平台的更新,HttpClient 的社区活跃度有所下降,一些新的优化和改进可能不如其他库及时。