🧩 一、整体上传流程(Spring MVC + commons-fileupload)
当用户通过浏览器上传文件(如 <form enctype="multipart/form-data">)时,整个流程如下:
[浏览器]
↓ (HTTP POST with multipart/form-data)
[Servlet 容器(如 Tomcat)]
↓ (原始 HttpServletRequest)
[Spring DispatcherServlet]
↓ (检测到 multipart 请求)
[CommonsMultipartResolver]
↓ (调用 commons-fileupload 解析请求体)
[生成 CommonsMultipartFile 对象]
↓ (注入到 Controller 方法参数或自定义 Bean 中)
[你的业务代码:importValuation(FileUpLoadBean file)]
⏱️ 二、commons-fileupload 在哪个阶段起作用?
✅ 关键阶段:请求解析阶段(在 Controller 执行之前)
具体来说:
-
DispatcherServlet 收到请求
判断
Content-Type是否为multipart/form-data。 -
调用 MultipartResolver
如果配置了
CommonsMultipartResolver,Spring 会委托它处理该请求。 -
CommonsMultipartResolver 内部使用 commons-fileupload
- 调用
ServletFileUpload.parseRequest(request)(来自commons-fileupload库) - 将原始字节流解析为一个个 FileItem(代表每个表单项,包括文件和普通字段)
- 把文件类型的
FileItem封装成CommonsMultipartFile对象
- 调用
-
替换原始 Request
Spring 会把原始的
HttpServletRequest包装成MultipartHttpServletRequest,其中包含解析好的文件和参数。 -
Controller 方法被调用
Spring 通过数据绑定(Data Binding),将
MultipartHttpServletRequest中的文件自动赋值给你的FileUpLoadBean.file字段(类型为CommonsMultipartFile)。
🔍 所以,
commons-fileupload的作用发生在 Controller 执行之前,是"幕后解析者"。
🛠️ 三、commons-fileupload 的核心作用是什么?
commons-fileupload 是 Apache 提供的一个 通用的 multipart/form-data 请求解析库。它的主要职责是:
| 功能 | 说明 |
|---|---|
| 解析 HTTP multipart 请求体 | 将原始字节流按 RFC 1867 标准拆分为多个"项"(FileItem) |
| 区分普通字段和文件字段 | 比如 <input name="username"> 和 <input type="file" name="file"> |
| 处理大文件上传 | 支持内存/磁盘混合存储(通过 DiskFileItemFactory) |
| 提供流式读取 | 可以通过 getInputStream() 逐块读取文件内容,避免 OOM |
| 支持文件名、ContentType 等元信息提取 | 如 getName(), getContentType(), getSize() |
💡 注意:
commons-fileupload本身与 Spring 无关 ,它是一个独立的工具库。Spring 只是封装 了它,通过
CommonsMultipartResolver和CommonsMultipartFile使其融入 MVC 框架。
📦 四、关键类关系图(简化)
text
commons-fileupload 库:
└── ServletFileUpload
└── parseRequest() → List<FileItem>
└── FileItem (代表一个表单项)
├── isFormField() → true/false
├── getName() → 字段名(如 "file")
├── getString() → 普通字段值
└── getInputStream() → 文件内容流
Spring 封装层:
└── CommonsMultipartResolver
└── 使用 ServletFileUpload 解析请求
└── 将 FileItem → CommonsMultipartFile
└── getFileItem() → 返回底层 FileItem
└── getInputStream() → 代理调用 FileItem.getInputStream()
🧪 五、你项目中的具体体现
- 你配置了
CommonsMultipartResolver→ 启用commons-fileupload解析。 - 你使用
CommonsMultipartFile→ 直接暴露了底层实现。 - 当用户 POST 到
/importValuation.action时:commons-fileupload已经在进入方法前完成了文件解析;file.getFile()返回的就是它解析出的文件对象;- 你可以安全地调用
.isEmpty(),.getInputStream(),.getOriginalFilename()等方法。
🆚 对比:不用 commons-fileupload 的情况(Servlet 3.0+)
如果使用 StandardServletMultipartResolver(Spring Boot 默认):
- 不需要
commons-fileupload依赖; - 文件类型是
StandardMultipartFile; - 解析工作由 Servlet 容器(如 Tomcat) 完成;
- 功能类似,但配置方式不同(通过
multipart-config或application.properties)。
✅ 总结
| 问题 | 回答 |
|---|---|
| 整个流程? | 浏览器 → Servlet 容器 → Spring → CommonsMultipartResolver → commons-fileupload 解析 → 生成 CommonsMultipartFile → 注入 Controller |
| 在哪个阶段起作用? | Controller 执行之前 ,在 Spring 的请求预处理阶段(由 DispatcherServlet 触发) |
| 作用是什么? | 解析 multipart/form-data 请求体,将原始 HTTP 流转换为结构化的文件和字段对象 |
如果你后续想优化性能(如限制内存使用、支持大文件分片)、或迁移到更现代的方案(如 Spring Boot + Servlet 3.0+),也可以继续问我!