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 上传单个文件的关键步骤如下:

  1. 设置请求头为 multipart/form-data
  2. 构造包含文件的请求体(使用 LinkedMultiValueMap
  3. 封装为 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


原始标题:Uploading MultipartFile with Spring RestTemplate | Baeldung