1. 概述
本文介绍如何使用 Spring 的 RestTemplate
实现文件上传,涵盖 单文件 和 多文件 上传场景。
内容简洁实用,适合在项目中快速落地,避免踩坑。✅
2. 什么是 HTTP Multipart 请求
HTTP 的普通 POST 请求通常以 application/x-www-form-urlencoded
格式发送键值对数据。
而文件上传这类场景,需要传输二进制流或大文本,就得用 multipart/form-data 类型的请求 —— 也就是常说的 Multipart 请求。
它的核心特点包括:
- 可同时上传文件和表单字段
- 将请求体分割成多个部分(part),每部分用 boundary 分隔
- 每个 part 可包含元数据(如文件名、MIME 类型)和实际内容
- 常用于文件上传、带附件的邮件发送等场景
📌 简单粗暴理解:multipart 就是把多个数据块打包成一个请求发出去。
想深入了解协议细节,可参考 RFC 1341 - Multipart。
3. Maven 依赖
客户端只需引入 spring-web
模块即可支持 multipart 功能:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
⚠️ 注意:如果你在 Spring Boot 项目中,通常已默认包含该依赖,无需额外添加。
4. 文件上传服务端接口
为了演示调用,我们假设有如下两个 REST 接口供客户端上传文件:
- ✅
POST /fileserver/singlefileupload/
:接收单个文件 - ✅
POST /fileserver/multiplefileupload/
:接收多个文件
服务端使用 MultipartFile
接收文件,这是 Spring MVC 的标准做法,此处不展开实现(读者应已熟悉)。
5. 单文件上传
使用 RestTemplate
上传单个文件的关键步骤如下:
- 设置请求头为
multipart/form-data
- 构造包含文件的请求体(使用
LinkedMultiValueMap
) - 封装为
HttpEntity
并发起 POST 请求
核心代码实现
// 设置 Content-Type 为 multipart/form-data
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 构建请求体,key "file" 对应服务端参数名
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", getTestFile()); // getTestFile() 返回 FileSystemResource
// 组装请求实体
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
// 发起请求
String serverUrl = "http://localhost:8082/spring-rest/fileserver/singlefileupload/";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(serverUrl, requestEntity, String.class);
关键点说明
FileSystemResource
是 Spring 提供的资源封装类,能自动识别文件名、大小、内容类型(如text/plain
)LinkedMultiValueMap
允许同一个 key 对应多个值(虽然单文件只加一次)- 当设置
Content-Type: multipart/form-data
后,RestTemplate
会自动处理 multipart 编码,无需手动拼接 boundary
✅ 成功上传后,服务端会返回响应结果(示例中为 String
类型)。
6. 多文件上传
多文件上传与单文件几乎一致,唯一区别在于:同一个 key 添加多个文件。
示例代码
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("files", getTestFile());
body.add("files", getTestFile());
body.add("files", getTestFile();
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = "http://localhost:8082/spring-rest/fileserver/multiplefileupload/";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(serverUrl, requestEntity, String.class);
注意事项
- key 名称
files
必须和服务端接收参数名匹配(如@RequestParam("files") MultipartFile[] files
) - 可以混合上传文件和其他表单字段,例如:
body.add("files", file1); body.add("files", file2); body.add("username", "zhangsan"); body.add("age", "25");
✅ 小技巧:单文件上传也可以统一走多文件逻辑,服务端做兼容即可,减少接口种类。
7. 总结
本文演示了如何使用 RestTemplate
实现文件上传,重点包括:
- 使用
MediaType.MULTIPART_FORM_DATA
触发自动 multipart 编码 - 利用
LinkedMultiValueMap
构建支持多值的请求体 - 通过
FileSystemResource
自动携带文件元信息 - 单文件与多文件仅在于 key 是否重复添加
⚠️ 踩坑提醒:
如果上传失败且报错 MissingServletRequestPartException
,检查客户端 key 名是否与服务端 @RequestParam
名完全一致!
完整示例代码已托管至 GitHub:
👉 https://github.com/eugenp/tutorials/tree/master/spring-web-modules/spring-resttemplate-3