文章目录
-
- [一、RestTemplate 是什么?](#一、RestTemplate 是什么?)
- 二、快速入门
-
- [2.1 添加依赖](#2.1 添加依赖)
- [2.2 配置RestTemplate Bean](#2.2 配置RestTemplate Bean)
- [2.3 第一个GET请求](#2.3 第一个GET请求)
- 三、核心方法详解
-
- [3.1 GET请求](#3.1 GET请求)
-
- [(1) getForObject 示例](#(1) getForObject 示例)
- [(2) getForEntity 示例](#(2) getForEntity 示例)
- [3.2 POST请求](#3.2 POST请求)
-
- [(1) 发送JSON数据](#(1) 发送JSON数据)
- [(2) 发送表单数据](#(2) 发送表单数据)
- [3.3 PUT、DELETE请求](#3.3 PUT、DELETE请求)
- [3.4 万能的exchange方法](#3.4 万能的exchange方法)
- [3.5 处理集合类型](#3.5 处理集合类型)
- 四、进阶配置
-
- [4.1 设置超时时间](#4.1 设置超时时间)
- [4.2 切换底层HTTP客户端](#4.2 切换底层HTTP客户端)
- [4.3 统一添加请求头(拦截器)](#4.3 统一添加请求头(拦截器))
- 五、异常处理
- 六、最佳实践总结
- 参考文档
一、RestTemplate 是什么?
RestTemplate 是Spring 3.0就开始提供的同步HTTP客户端工具,位于 spring-web 模块中。它封装了底层HTTP库(JDK自带的 HttpURLConnection、Apache HttpClient、OkHttp等)的复杂性,提供了一套简洁的模板方法API。
简单说,它把发请求、处理响应、解析JSON等重复劳动都包办了。我们只需要告诉它:请求地址是什么?用什么方法?参数是什么?期望返回什么类型? 剩下的脏活累活它全搞定。
二、快速入门
2.1 添加依赖
如果你的项目是基于Spring Boot的,只需要引入Web起步依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这个依赖已经包含了 spring-web 模块,RestTemplate就在其中。
2.2 配置RestTemplate Bean
在Spring Boot 2.x及以上版本中,RestTemplate不会自动注入到容器里,需要我们手动注册。推荐在配置类中声明:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.3 第一个GET请求
配置好之后,在你的Service或Controller里注入RestTemplate,然后就可以愉快地发请求了:
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class TestController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test")
public String testGet() {
// 请求一个公开的API
String url = "https://api.github.com/users/defunkt";
// 直接获取响应体,转换为String
String result = restTemplate.getForObject(url, String.class);
return result;
}
}
启动项目,访问 http://localhost:8080/test,你就能看到从GitHub API返回的JSON数据了!
三、核心方法详解
RestTemplate为每种HTTP方法都提供了对应的模板方法。下面我们逐一讲解最常用的几个。
3.1 GET请求
GET请求主要有两种方法:getForObject 和 getForEntity。
| 方法 | 返回值 | 说明 |
|---|---|---|
getForObject() |
直接返回响应体(JSON转成的对象) | 简单粗暴,适合只需要数据体的场景 |
getForEntity() |
返回ResponseEntity<T>对象 |
包含状态码、响应头等完整信息 |
(1) getForObject 示例
假设我们有一个实体类 User:
java
public class User {
private Long id;
private String name;
// 省略getter/setter
}
java
// 方式1:直接返回User对象
String url = "http://localhost:8080/users/{id}";
User user = restTemplate.getForObject(url, User.class, 1);
// 方式2:使用Map传递多个参数
Map<String, String> params = new HashMap<>();
params.put("id", "1");
params.put("name", "张三");
User user2 = restTemplate.getForObject("http://localhost:8080/users/{id}?name={name}",
User.class, params);
(2) getForEntity 示例
java
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class, 1);
// 获取完整响应信息
HttpStatus statusCode = response.getStatusCode(); // 状态码
int statusCodeValue = response.getStatusCodeValue(); // 200, 404等
HttpHeaders headers = response.getHeaders(); // 响应头
User body = response.getBody(); // 响应体
if (response.getStatusCode().is2xxSuccessful()) {
System.out.println("请求成功:" + body.getName());
}
3.2 POST请求
POST请求同样有三个常用方法:
| 方法 | 说明 |
|---|---|
postForObject() |
提交数据,直接返回响应体 |
postForEntity() |
提交数据,返回完整响应 |
postForLocation() |
提交数据,只返回响应头中的Location(常用于创建资源后获取新资源地址) |
(1) 发送JSON数据
java
User newUser = new User();
newUser.setName("李四");
ResponseEntity<User> response = restTemplate.postForEntity(
"http://localhost:8080/users",
newUser, // Spring会自动将对象转成JSON
User.class
);
(2) 发送表单数据
java
// 表单数据需要用MultiValueMap包装
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", "zhangsan");
formData.add("password", "123456");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject(
"http://localhost:8080/login",
request,
String.class
);
3.3 PUT、DELETE请求
PUT和DELETE相对简单,一般不需要处理返回值:
java
// PUT - 更新资源
User updatedUser = new User();
updatedUser.setName("王五");
restTemplate.put("http://localhost:8080/users/{id}", updatedUser, 1);
// DELETE - 删除资源
restTemplate.delete("http://localhost:8080/users/{id}", 1);
3.4 万能的exchange方法
如果觉得上面的方法不够灵活,exchange 是RestTemplate最通用的方法,可以应对各种复杂场景:
java
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer token123");
headers.setContentType(MediaType.APPLICATION_JSON);
// 构建请求实体
HttpEntity<String> requestEntity = new HttpEntity<>(requestJson, headers);
// 发送请求,使用ParameterizedTypeReference处理泛型
ResponseEntity<List<User>> response = restTemplate.exchange(
"http://localhost:8080/users/list",
HttpMethod.GET,
requestEntity,
new ParameterizedTypeReference<List<User>>() {}
);
3.5 处理集合类型
当接口返回的是List<User>这样的泛型集合时,直接用User[].class或者使用ParameterizedTypeReference:
java
// 方式1:使用数组(简单)
User[] users = restTemplate.getForObject(url, User[].class);
// 方式2:使用ParameterizedTypeReference(推荐,类型安全)
ResponseEntity<List<User>> response = restTemplate.exchange(
url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {}
);
List<User> userList = response.getBody();
四、进阶配置
4.1 设置超时时间
默认情况下,RestTemplate没有设置超时,可能会导致线程长时间阻塞。推荐进行超时配置:
java
@Bean
public RestTemplate restTemplate() {
// 使用HttpComponentsClientHttpRequestFactory
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 连接超时 5秒
factory.setReadTimeout(10000); // 读取超时 10秒
factory.setConnectionRequestTimeout(3000); // 从连接池获取连接的超时 3秒
return new RestTemplate(factory);
}
需要先在pom.xml中添加依赖:
xml
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
4.2 切换底层HTTP客户端
RestTemplate默认使用JDK自带的HttpURLConnection,你可以切换到性能更好的实现:
| 底层库 | 配置方式 |
|---|---|
| Apache HttpClient | new RestTemplate(new HttpComponentsClientHttpRequestFactory()) |
| OkHttp | new RestTemplate(new OkHttp3ClientHttpRequestFactory()) |
java
// 切换到OkHttp
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
4.3 统一添加请求头(拦截器)
如果每个请求都需要添加相同的请求头(如认证Token),可以用拦截器统一处理:
java
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 添加拦截器
restTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add("User-Agent", "MyApp/1.0");
request.getHeaders().add("Authorization", "Bearer " + getToken());
return execution.execute(request, body);
});
return restTemplate;
}
五、异常处理
RestTemplate在遇到4xx或5xx状态码时会抛出异常,默认由DefaultResponseErrorHandler处理。我们可以自定义异常处理逻辑:
java
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 设置自定义错误处理器,避免直接抛异常
restTemplate.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
// 只有5xx才算错误,4xx不抛异常
return response.getStatusCode().is5xxServerError();
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// 自定义错误处理逻辑
System.err.println("请求出错:" + response.getStatusText());
}
});
return restTemplate;
}
在实际开发中,建议用try-catch包裹RestTemplate调用:
java
try {
User user = restTemplate.getForObject(url, User.class);
return user;
} catch (RestClientException e) {
log.error("调用远程服务失败", e);
// 降级处理或抛出自定义业务异常
throw new BusinessException("服务暂时不可用");
}
六、最佳实践总结
-
复用RestTemplate实例:RestTemplate是线程安全的,整个应用应该只创建一个Bean,到处注入使用。
-
配置合理的超时:永远不要使用无超时的RestTemplate,否则一个下游故障可能拖垮整个系统。
-
使用exchange处理复杂场景 :当需要自定义请求头、处理泛型响应时,
exchange是最佳选择。 -
异常一定要处理:网络调用不可靠,做好异常捕获和降级是基本功。
-
考虑升级到WebClient :如果是新项目,或者对性能要求较高,可以考虑使用
WebClient,它的API更现代,支持响应式编程。