SpringBoot RestTemplate 介绍
目录
- 前言
- 一、RestTemplate 是什么?
- 二、RestTemplate 和 HttpClient 区别
- 三、二者核心区别
- 四、为什么很多 Spring Boot 项目喜欢用 RestTemplate?
- 五、RestTemplate 的工作原理
- 六、Spring Boot 如何引入 RestTemplate
- 七、Maven 引入
- 八、如何创建 RestTemplate
- 九、RestTemplate 常用方法
- 十、GET 请求示例
- 十一、GET 带参数
- 十二、POST 请求示例
- 十三、exchange()(推荐)
- 十四、拦截器
- 十五、封装类
- 十六、如何获取文件名、文件类型、判断请求成功?
- 十七、RestTemplate 支持哪些底层实现?
- 十八、RestTemplate 缺点
- 十九、现在为什么还大量使用?
- 二十、RestTemplate vs WebClient
- 二十一、什么时候用 RestTemplate?
- 二十二、什么时候用 WebClient?
- 二十三、企业里真实情况
- 二十四、学习路线
- 二十五、一个完整实际案例
前言
RestTemplate 和 HttpClient 都可以用于发送 HTTP 请求,但它们定位不同。
可以把它们理解成:
HttpClient:底层 HTTP 通信工具RestTemplate:Spring 对HttpClient等工具的高级封装
一、RestTemplate 是什么?
RestTemplate 是 Spring 提供的一个:
- 同步阻塞式 HTTP 客户端
- 用于调用:
- 微服务接口
- 第三方 API
- 文件下载
- 外部系统通信
它本质上是:
Spring 对 HTTP 请求进行了再次封装
让你:
- 不用手动处理连接
- 不用自己解析响应流
- 不用自己转换 JSON
可以像调用普通方法一样发 HTTP 请求。
二、RestTemplate 和 HttpClient 区别
业务代码
↓
RestTemplate
↓
ClientHttpRequestFactory
↓
HttpClient / OkHttp / JDK HttpURLConnection
也就是说:
RestTemplate 是上层封装
HttpClient 是底层实现
三、二者核心区别
| 对比项 | RestTemplate | HttpClient |
|---|---|---|
| 所属 | Spring | Apache |
| 定位 | 高级HTTP工具 | 底层HTTP客户端 |
| 使用难度 | 简单 | 较复杂 |
| JSON转换 | 自动 | 手动 |
| 与Spring整合 | 非常好 | 一般 |
| 学习成本 | 低 | 高 |
| 适合 | 微服务调用 | 底层定制 |
| 是否阻塞 | 是 | 有同步和异步 |
| 推荐状态 | 官方已维护模式 | 仍常用 |
四、为什么很多 Spring Boot 项目喜欢用 RestTemplate?
因为它:
- 和 Spring 完美整合
- 非常简单
- 自动 JSON 转对象
- 支持拦截器
- 支持负载均衡
- 支持超时配置
- 支持统一异常处理
例如:
User user = restTemplate.getForObject(url, User.class);
就直接得到 Java 对象了。
不用:
- 创建连接
- 读取 InputStream
- Jackson 转换 JSON
五、RestTemplate 的工作原理
当你:
restTemplate.getForObject(...)
时,内部会:
1. 创建HTTP请求
2. 建立TCP连接
3. 发送请求
4. 获取响应
5. 自动解析JSON
6. 转换成Java对象
六、Spring Boot 如何引入 RestTemplate
其实:
spring-web
里已经包含了。
Spring Boot Web 项目一般天然就有。
七、Maven 引入
如果没有,可以引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这里面已经包含:
- Spring MVC
- RestTemplate
- Jackson
八、如何创建 RestTemplate
1.RestTemplate 创建
通常会放到配置类里。
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory =
new SimpleClientHttpRequestFactory();
// 连接超时
factory.setConnectTimeout(5000);
// 读取超时
factory.setReadTimeout(10000);
return new RestTemplate(factory);
}
}
然后:
@Autowired
private RestTemplate restTemplate;
即可使用。
2.RestTemplate + Apache HttpClient 创建
因为 RestTemplate 默认实现性能一般。
很多公司会:
RestTemplate + Apache HttpClient
如果你使用 Spring Boot 2.x , 引入 httpclient :
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
如果你使用 Spring Boot 3.x , 引入 httpclient :
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
通过 RestTemplate + Apache HttpClient可获得:
- 连接池
- 更高性能
- 更稳定
示例:
@Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
//设置最大连接池
manager.setMaxTotal(500);
//每个目标主机最多连接
manager.setDefaultMaxPerRoute(100);
RequestConfig config = RequestConfig.custom()
//建立TCP连接最大等待时间。例如:服务器不存在、网络不通
.setConnectTimeout(5000)
//读取超时。连接成功后服务器迟迟不返回数据,等待多久。
.setResponseTimeout(10000)
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(manager)
.setDefaultRequestConfig(config)
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(factory);
}
九、RestTemplate 常用方法
| 方法 | 作用 |
|---|---|
| getForObject | GET请求返回对象 |
| getForEntity | GET返回完整响应 |
| postForObject | POST返回对象 |
| postForEntity | POST返回完整响应 |
| exchange | 最强大的通用方法 |
十、GET 请求示例
1. 请求接口
假设:
GET http://localhost:8080/user/1
返回:
{
"id":1,
"name":"Tom"
}
2. Java对象
@Data
public class User {
private Long id;
private String name;
}
3. GET调用
@Autowired
private RestTemplate restTemplate;
public void testGet() {
String url = "http://localhost:8080/user/1";
User user = restTemplate.getForObject(url, User.class);
System.out.println(user);
}
十一、GET 带参数
方式1:拼接URL
String url = "http://localhost:8080/user?id=1";
方式2:占位符(推荐)
String url = "http://localhost:8080/user/{id}";
User user = restTemplate.getForObject(
url,
User.class,
1
);
等价于:
/user/1
十二、POST 请求示例
1. 请求接口
POST /user/add
请求体:
{
"name":"Tom"
}
2. 请求对象
@Data
public class UserReq {
private String name;
}
3. POST调用
public void testPost() {
String url = "http://localhost:8080/user/add";
UserReq req = new UserReq();
req.setName("Tom");
User user = restTemplate.postForObject(
url,
req,
User.class
);
System.out.println(user);
}
十三、exchange()(推荐)
实际项目中:
90% 会使用 exchange()
因为它:
- 支持所有 HTTP 方法
- 支持请求头
- 支持 token
- 支持文件上传
- 支持复杂请求
1.GET 示例
HttpHeaders headers = new HttpHeaders();
headers.add("token", "123456");
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<User> response =
restTemplate.exchange(
"http://localhost:8080/user/1",
HttpMethod.GET,
entity,
User.class
);
User user = response.getBody();
2.GET 请求 + token 示例
@Autowired
private RestTemplate restTemplate;
public void test() {
String url = "http://localhost:8080/user/1";
// 1. 创建请求头
HttpHeaders headers = new HttpHeaders();
// 2. 设置 token
headers.set("Authorization", "Bearer abc123");
// 3. 封装 HttpEntity
HttpEntity<Void> entity = new HttpEntity<>(headers);
// 4. 发起请求
ResponseEntity<String> response =
restTemplate.exchange(
url,
HttpMethod.GET,
entity,
String.class
);
// 5. 获取响应
String body = response.getBody();
System.out.println(body);
}
3. POST 示例
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
UserReq req = new UserReq();
req.setName("Tom");
HttpEntity<UserReq> entity = new HttpEntity<>(req, headers);
ResponseEntity<User> response =
restTemplate.exchange(
"http://localhost:8080/user/add",
HttpMethod.POST,
entity,
User.class
);
User user = response.getBody();
4.POST 请求 + token
public void testPost() {
String url = "http://localhost:8080/order/create";
// 请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth("abc123");
// 请求体
Map<String, Object> body = new HashMap<>();
body.put("name", "Tom");
body.put("age", 18);
// 封装
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
// 请求
ResponseEntity<String> response =
restTemplate.exchange(
url,
HttpMethod.POST,
entity,
String.class
);
System.out.println(response.getBody());
}
setBearerAuth 是什么?
这个:
headers.setBearerAuth("abc123");
等价于:
Authorization: Bearer abc123
它是 Spring 专门提供的快捷方法。
如果不是 Bearer token 怎么办?
有些系统:
token: xxx
或者:
Authorization: xxx
那就:
headers.set("token", "abc123");
或者:
headers.set("Authorization", "abc123");
即可。
5.简单文件下载(byte[])示例
对于一些小文件可以使用字节数组来下载:
public void download() throws Exception {
String url = "http://localhost:8080/file/test.pdf";
// 请求头
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth("abc123");
HttpEntity<Void> entity = new HttpEntity<>(headers);
// 请求
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
entity,
byte[].class
);
// 获取文件字节
byte[] bytes = response.getBody();
// 保存文件
Files.write(
Paths.get("D:/test.pdf"),
bytes
);
System.out.println("下载完成");
}
6. InputStream 文件下载(推荐)
上面的示例使用 byte[] 会一次性加载整个文件到内存,对于大文件 大文件:500MB 或者1GB 这样的文件 容易 OOM(内存溢出)。
更推荐下面的使用 Resource 和 inputStream 边读边写大文件,它不会一次性加载整个文件,更适合大文件
public void download2() throws Exception {
String url = "http://localhost:8080/file/big.zip";
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth("abc123");
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<Resource> response =
restTemplate.exchange(
url,
HttpMethod.GET,
entity,
Resource.class
);
// 获取输入流
InputStream inputStream = response.getBody().getInputStream();
// 输出流
FileOutputStream out = new FileOutputStream("D:/big.zip");
byte[] buffer = new byte[8192];
int len;
while ((len = inputStream.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.close();
inputStream.close();
System.out.println("下载成功");
}
十四、拦截器
上面的 exchange() 示例代码里,我们每次发送请求时都会往请求头里设置 token 或者参数以及请求头,如果你的项目调用很多请求,每次构建请求时都需要手动设置 token 或者往请求头里塞一些公共的参数,这很不方便,我们可以在配置的时候使用拦截器。
拦截器常见用途:
- 自动添加 token或签名、请求头等
- 自动打印日志(URL、参数、响应时间)
- 请求失败自动重试
让我们回到上面 第八步 如何创建 RestTemplate 。
1.在配置类里使用 setInterceptors 增加拦截器
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 连接超时
factory.setConnectTimeout(5000);
// 读取超时
factory.setReadTimeout(10000);
RestTemplate restTemplate = new RestTemplate(factory);
//设置拦截器
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
HttpHeaders headers = request.getHeaders();
headers.set("Authorization", getToken());
// 继续执行请求
return execution.execute(request, body);
}));
return restTemplate;
}
}
解释:
上面的配置代码会给所有 RestTemplate 请求自动添加 token,这样以后每次发送请求时执行 时不需要每次手动往请求头塞 token,它会自动帮你加。例如:执行 restTemplate.exchange(...) 时
代码里的restTemplate.setInterceptors(...)是在给 RestTemplate 配置 HTTP 请求拦截器(Interceptor),
它的作用类似于AOP / Filter / Spring MVC Interceptor
即:
在真正发送 HTTP 请求之前
或者收到响应之后
做统一处理
企业中的经典写法:
public class TokenInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution)
throws IOException {
request.getHeaders().setBearerAuth(getToken());
return execution.execute(request, body);
}
}
然后配置类里:
restTemplate.setInterceptors(
Arrays.asList(
new TokenInterceptor()
)
);
2.请求前和请求后处理
上面的示例是在请求发送前拦截进行增加 token 处理,在拦截器里不仅可以在请求发送前进行拦截操作,也可以在请求后拦截处理。
@Bean(name = "restTemplateClient")
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory requestFactory =
new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(readTimeout);
requestFactory.setConnectTimeout(connectTimeout);
//使用 BufferingClientHttpRequestFactory 重复读取响应流
RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
restTemplate.setInterceptors(
Collections.singletonList(
(request, body, execution) -> {
// ======================
// 请求前
// ======================
System.out.println("请求开始");
System.out.println("请求URL: " + request.getURI());
System.out.println("请求方法: " + request.getMethod());
request.getHeaders().setBearerAuth(getToken());
// 记录开始时间
long start = System.currentTimeMillis();
// 真正发送请求
ClientHttpResponse response = execution.execute(request, body);
// ======================
// 响应后
// ======================
long end = System.currentTimeMillis();
System.out.println("请求结束");
System.out.println("耗时: " + (end - start));
System.out.println("响应状态码: " + response.getStatusCode());
//只有使用了 BufferingClientHttpRequestFactory 才能重复读取,否则 拦截器里读完后业务代码就读不到了,会导致返回body为空
String responseBody = StreamUtils.copyToString(
response.getBody(),
StandardCharsets.UTF_8);
System.out.println("响应: " +responseBody);
return response;
}
));
return restTemplate;
}
3.setInterceptors 是什么?
它的定义:
public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors)
意思:给 RestTemplate 配置请求拦截器链
Lambda 参数是什么?
这里:
(request, body, execution) -> {
其实等价于:
new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution
) throws IOException {
}
}
(1).request
HttpRequest request 代表:HTTP请求对象
里面有:
URL
请求头
请求方法
例如:
request.getURI()
request.getMethod()
request.getHeaders()
(2). body
byte[] body代表:请求体数据
例如 :
POST 请求里的 JSON:
{
“name”:“Tom”
}
实际上最终会变成:byte[]
(3).execution
这个最重要。
ClientHttpRequestExecution execution
它代表:真正执行HTTP请求的人
4.多个拦截器执行顺序
例如:
restTemplate.setInterceptors(
Arrays.asList(
interceptor1,
interceptor2,
interceptor3
)
);
执行顺序:
interceptor1 before
interceptor2 before
interceptor3 before
真正请求
interceptor3 after
interceptor2 after
interceptor1 after
类似责任链模式
十五、封装类
如果 每个请求都需要设置:token、timestamp、sign 你可以使用上面第十四部分拦截器进行统一拦截设置。但是如果你每个请求都要动态的根据参数计算并设置 sign ,那仅靠拦截器不够。因为拦截器拿不到业务层的签名逻辑。
这时通常可以封装一个工具类使用。
@Component
public class HttpClient {
@Autowired
private RestTemplate restTemplate;
public <T> T post(String url, Object req, Class<T> clazz) {
HttpHeaders headers = buildHeaders(req);
HttpEntity<Object> entity = new HttpEntity<>(req, headers);
ResponseEntity<T> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
clazz);
return response.getBody();
}
private HttpHeaders buildHeaders(Object req) {
HttpHeaders headers = new HttpHeaders();
String timestamp = String.valueOf(System.currentTimeMillis());
headers.set("timestamp", timestamp);
headers.set("token", getToken());
headers.set("sign",generateSign(req, timestamp));
return headers;
}
}
调用:
UserResp resp = httpClient.post("https://api.xxx.com/user/query", req, UserResp.class);
十六、如何获取文件名、文件类型、判断请求成功?
HTTP 响应头里通常有:
Content-Disposition
例如:
Content-Disposition:
attachment; filename=test.pdf
获取文件名:
String disposition = response.getHeaders().getFirst("Content-Disposition");
System.out.println(disposition);
获取 Content-Type:
MediaType contentType = response.getHeaders().getContentType();
//application/pdf
System.out.println(contentType);
如何判断下载成功:
if (response.getStatusCode() == HttpStatus.OK) {
System.out.println("成功");
}
十七、RestTemplate 支持哪些底层实现?
默认:
JDK HttpURLConnection
但也可以替换成:
- Apache HttpClient(最常见)
- OkHttp
例如:
HttpComponentsClientHttpRequestFactory
底层用 HttpClient。
十八、RestTemplate 缺点
Spring 官方现在:
已不再积极推荐 RestTemplate
而推荐:
WebClient
原因:
- RestTemplate 是阻塞式
- 高并发性能一般
- 不适合响应式
十九、现在为什么还大量使用?
因为:
- 老项目太多
- 简单稳定
- 易于维护
- 大量公司还在用
特别是:
传统 Spring Boot 项目
仍然大量使用。
二十、RestTemplate vs WebClient
| 对比 | RestTemplate | WebClient |
|---|---|---|
| 模型 | 同步阻塞 | 异步非阻塞 |
| 性能 | 一般 | 高 |
| 学习难度 | 简单 | 较高 |
| 使用广泛度 | 非常广 | 越来越广 |
| 推荐程度 | 维护模式 | 官方推荐 |
二十一、什么时候用 RestTemplate?
适合:
- 公司老项目
- 普通微服务调用
- 中小并发
- 简单HTTP调用
二十二、什么时候用 WebClient?
适合:
- 高并发
- 网关
- 响应式系统
- 大量IO请求
二十三、企业里真实情况
很多公司:
老项目:RestTemplate
新项目:OpenFeign/WebClient
因为:
Feign 更适合微服务
例如:
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User get(@PathVariable Long id);
}
比 RestTemplate 更方便。
二十四、学习路线
建议学习顺序:
1. HTTP基础
2. RestTemplate
3. HttpClient
4. OpenFeign
5. WebClient
因为:
RestTemplate 是理解微服务调用最好的入门
二十五、一个完整实际案例
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public User getUser(Long id) {
String url =
"http://localhost:8080/user/{id}";
HttpHeaders headers = new HttpHeaders();
headers.add("token", "abc123");
HttpEntity<Void> entity =
new HttpEntity<>(headers);
ResponseEntity<User> response =
restTemplate.exchange(
url,
HttpMethod.GET,
entity,
User.class,
id
);
return response.getBody();
}
}
更多推荐

所有评论(0)