SpringBoot RestTemplate 介绍

目录

  • 前言
  • [一、RestTemplate 是什么?](#一、RestTemplate 是什么?)
  • [二、RestTemplate 和 HttpClient 区别](#二、RestTemplate 和 HttpClient 区别)
  • 三、二者核心区别
  • [四、为什么很多 Spring Boot 项目喜欢用 RestTemplate?](#四、为什么很多 Spring Boot 项目喜欢用 RestTemplate?)
  • [五、RestTemplate 的工作原理](#五、RestTemplate 的工作原理)
  • [六、Spring Boot 如何引入 RestTemplate](#六、Spring Boot 如何引入 RestTemplate)
  • [七、Maven 引入](#七、Maven 引入)
  • [八、如何创建 RestTemplate](#八、如何创建 RestTemplate)
    • [1.RestTemplate 创建](#1.RestTemplate 创建)
    • [2.RestTemplate + Apache HttpClient 创建](#2.RestTemplate + Apache HttpClient 创建)
  • 九、为什么要放到@Bean里?
  • [十、RestTemplate 常用方法](#十、RestTemplate 常用方法)
  • [十一、GET 请求示例](#十一、GET 请求示例)
    • [1. 请求接口](#1. 请求接口)
    • [2. Java对象](#2. Java对象)
    • [3. GET调用](#3. GET调用)
  • [十二、GET 带参数](#十二、GET 带参数)
  • [十三、POST 请求示例](#十三、POST 请求示例)
    • [1. 请求接口](#1. 请求接口)
    • [2. 请求对象](#2. 请求对象)
    • [3. POST调用](#3. POST调用)
  • 十四、exchange()(推荐)
    • [1.GET 示例](#1.GET 示例)
    • [2.GET 请求 + token 示例](#2.GET 请求 + token 示例)
    • [3. POST 示例](#3. POST 示例)
    • [4.POST 请求 + token](#4.POST 请求 + token)
    • 5.简单文件下载(byte\[\])示例
    • [6. InputStream 文件下载(推荐)](#6. InputStream 文件下载(推荐))
  • 十五、如何获取文件名、文件类型、判断请求成功?
  • [十六、RestTemplate 支持哪些底层实现?](#十六、RestTemplate 支持哪些底层实现?)
  • [十七、RestTemplate 缺点](#十七、RestTemplate 缺点)
  • 十八、现在为什么还大量使用?
  • [十九、RestTemplate vs WebClient](#十九、RestTemplate vs WebClient)
  • [二十、什么时候用 RestTemplate?](#二十、什么时候用 RestTemplate?)
  • [二十一、什么时候用 WebClient?](#二十一、什么时候用 WebClient?)
  • 二十二、企业里真实情况
  • 二十三、学习路线
  • 二十四、一个完整实际案例

前言

RestTemplate 和 HttpClient 都可以用于发送 HTTP 请求,但它们定位不同。

可以把它们理解成:

  • HttpClient:底层 HTTP 通信工具
  • RestTemplate:Spring 对 HttpClient 等工具的高级封装

一、RestTemplate 是什么?

RestTemplate 是 Spring 提供的一个:

  • 同步阻塞式 HTTP 客户端
  • 用于调用:
    • 微服务接口
    • 第三方 API
    • 文件下载
    • 外部系统通信

它本质上是:

text 复制代码
Spring 对 HTTP 请求进行了再次封装

让你:

  • 不用手动处理连接
  • 不用自己解析响应流
  • 不用自己转换 JSON

可以像调用普通方法一样发 HTTP 请求。


二、RestTemplate 和 HttpClient 区别

text 复制代码
业务代码
   ↓
RestTemplate
   ↓
ClientHttpRequestFactory
   ↓
HttpClient / OkHttp / JDK HttpURLConnection

也就是说:

text 复制代码
RestTemplate 是上层封装
HttpClient 是底层实现

三、二者核心区别

对比项 RestTemplate HttpClient
所属 Spring Apache
定位 高级HTTP工具 底层HTTP客户端
使用难度 简单 较复杂
JSON转换 自动 手动
与Spring整合 非常好 一般
学习成本 低 高
适合 微服务调用 底层定制
是否阻塞 是 有同步和异步
推荐状态 官方已维护模式 仍常用

四、为什么很多 Spring Boot 项目喜欢用 RestTemplate?

因为它:

  • 和 Spring 完美整合
  • 非常简单
  • 自动 JSON 转对象
  • 支持拦截器
  • 支持负载均衡
  • 支持超时配置
  • 支持统一异常处理

例如:

java 复制代码
User user = restTemplate.getForObject(url, User.class);

就直接得到 Java 对象了。

不用:

  • 创建连接
  • 读取 InputStream
  • Jackson 转换 JSON

五、RestTemplate 的工作原理

当你:

java 复制代码
restTemplate.getForObject(...)

时,内部会:

text 复制代码
1. 创建HTTP请求
2. 建立TCP连接
3. 发送请求
4. 获取响应
5. 自动解析JSON
6. 转换成Java对象

六、Spring Boot 如何引入 RestTemplate

其实:

text 复制代码
spring-web

里已经包含了。

Spring Boot Web 项目一般天然就有。


七、Maven 引入

如果没有,可以引入:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

这里面已经包含:

  • Spring MVC
  • RestTemplate
  • Jackson

八、如何创建 RestTemplate

1.RestTemplate 创建

通常会放到配置类里。

java 复制代码
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
            SimpleClientHttpRequestFactory factory =
            new SimpleClientHttpRequestFactory();

    	// 连接超时
    	factory.setConnectTimeout(5000);
    	// 读取超时
    	factory.setReadTimeout(10000);
    	return new RestTemplate(factory);
    }
}

然后:

java 复制代码
@Autowired
private RestTemplate restTemplate;

即可使用。


2.RestTemplate + Apache HttpClient 创建

因为 RestTemplate 默认实现性能一般。

很多公司会:

text 复制代码
RestTemplate + Apache HttpClient

获得:

  • 连接池
  • 更高性能
  • 更稳定

示例:

java 复制代码
@Bean
public RestTemplate restTemplate() {
    RequestConfig config = RequestConfig.custom()
            //建立TCP连接最大等待时间。例如:服务器不存在、网络不通
            .setConnectTimeout(5000)
            //读取超时。连接成功后服务器迟迟不返回数据,等待多久。
            .setResponseTimeout(10000)
            .build();

    CloseableHttpClient httpClient =
            HttpClients.custom()
                    .setDefaultRequestConfig(config)
                    .build();

    HttpComponentsClientHttpRequestFactory factory =
            new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(factory);
}

九、为什么要放到@Bean里?

因为 Spring 会:

  • 创建单例对象
  • 放入IOC容器
  • 全局复用
  • 自动注入

这样整个项目只会有一个 RestTemplate。


十、RestTemplate 常用方法

方法 作用
getForObject GET请求返回对象
getForEntity GET返回完整响应
postForObject POST返回对象
postForEntity POST返回完整响应
exchange 最强大的通用方法

十一、GET 请求示例


1. 请求接口

假设:

text 复制代码
GET http://localhost:8080/user/1

返回:

json 复制代码
{
  "id":1,
  "name":"Tom"
}

2. Java对象

java 复制代码
@Data
public class User {

    private Long id;

    private String name;
}

3. GET调用

java 复制代码
@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

java 复制代码
String url = "http://localhost:8080/user?id=1";

方式2:占位符(推荐)

java 复制代码
String url = "http://localhost:8080/user/{id}";

User user = restTemplate.getForObject(
        url,
        User.class,
        1
);

等价于:

text 复制代码
/user/1

十三、POST 请求示例


1. 请求接口

text 复制代码
POST /user/add

请求体:

json 复制代码
{
  "name":"Tom"
}

2. 请求对象

java 复制代码
@Data
public class UserReq {

    private String name;
}

3. POST调用

java 复制代码
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()(推荐)

实际项目中:

text 复制代码
90% 会使用 exchange()

因为它:

  • 支持所有 HTTP 方法
  • 支持请求头
  • 支持 token
  • 支持文件上传
  • 支持复杂请求

1.GET 示例

java 复制代码
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 示例

java 复制代码
@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 示例

java 复制代码
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

java 复制代码
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\[\])示例

对于一些小文件可以使用字节数组来下载:

java 复制代码
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 边读边写大文件,它不会一次性加载整个文件,更适合大文件

java 复制代码
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("下载成功");
}

十五、如何获取文件名、文件类型、判断请求成功?

HTTP 响应头里通常有:

java 复制代码
Content-Disposition

例如:

java 复制代码
Content-Disposition:
attachment; filename=test.pdf

获取文件名:

java 复制代码
String disposition = response.getHeaders().getFirst("Content-Disposition");

System.out.println(disposition);

获取 Content-Type:

java 复制代码
MediaType contentType = response.getHeaders().getContentType();

//application/pdf
System.out.println(contentType);

如何判断下载成功:

java 复制代码
if (response.getStatusCode() == HttpStatus.OK) {
    System.out.println("成功");
}

十六、RestTemplate 支持哪些底层实现?

默认:

text 复制代码
JDK HttpURLConnection

但也可以替换成:

  • Apache HttpClient(最常见)
  • OkHttp

例如:

java 复制代码
HttpComponentsClientHttpRequestFactory

底层用 HttpClient。


十七、RestTemplate 缺点

Spring 官方现在:

text 复制代码
已不再积极推荐 RestTemplate

而推荐:

text 复制代码
WebClient

原因:

  • RestTemplate 是阻塞式
  • 高并发性能一般
  • 不适合响应式

十八、现在为什么还大量使用?

因为:

  • 老项目太多
  • 简单稳定
  • 易于维护
  • 大量公司还在用

特别是:

text 复制代码
传统 Spring Boot 项目

仍然大量使用。


十九、RestTemplate vs WebClient

对比 RestTemplate WebClient
模型 同步阻塞 异步非阻塞
性能 一般 高
学习难度 简单 较高
使用广泛度 非常广 越来越广
推荐程度 维护模式 官方推荐

二十、什么时候用 RestTemplate?

适合:

  • 公司老项目
  • 普通微服务调用
  • 中小并发
  • 简单HTTP调用

二十一、什么时候用 WebClient?

适合:

  • 高并发
  • 网关
  • 响应式系统
  • 大量IO请求

二十二、企业里真实情况

很多公司:

text 复制代码
老项目:RestTemplate
新项目:OpenFeign/WebClient

因为:

text 复制代码
Feign 更适合微服务

例如:

java 复制代码
@FeignClient("user-service")
public interface UserClient {

    @GetMapping("/user/{id}")
    User get(@PathVariable Long id);
}

比 RestTemplate 更方便。


二十三、学习路线

建议学习顺序:

text 复制代码
1. HTTP基础
2. RestTemplate
3. HttpClient
4. OpenFeign
5. WebClient

因为:

text 复制代码
RestTemplate 是理解微服务调用最好的入门

二十四、一个完整实际案例

java 复制代码
@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();
    }
}
相关推荐
白杨尚青7 分钟前
C++入门篇(十):string(上)——认识string:构造与三大遍历(一条龙讲透operator[]、迭代器、auto、范围for)
java·开发语言·c++·笔记·stl
IT_陈寒11 分钟前
JavaScript闭包的这个坑,我居然今天才爬出来
前端·人工智能·后端
Thneonl18 分钟前
消息队列选型决策树:RabbitMQ vs Kafka vs Redis Streams
后端·架构
晚安日记wanna19 分钟前
大厂禁 JOIN 的真正原因,拆到第四层才清楚
数据库·后端·面试
anew___21 分钟前
《从零手写操作系统 (11):文件系统初探——initrd与VFS抽象层》
java·javascript·算法
天天向上29124 分钟前
Spring AI 实战:14 个踩坑记录,其中一个让我的测试全绿但产品是坏的
java·开源
dd聊技术29 分钟前
LLM 说"你这篇和已有文章 92% 相似",我去查了——它编的
后端
正在走向自律33 分钟前
从只写接口到独立交付前后端,飞算JavaAI能给Java后端工程师多少溢价?
java·springboot·ai编程·全栈开发·java求职·飞算javaai·金九银十
a努力。1 小时前
LangChain Agent消息链路全解析
java·前端·javascript
行百里er1 小时前
Redis 持久化——RDB 快照 vs AOF 日志
redis·后端