上周接了一个老 JSP 项目的改造,需求列表里有一条看着很简单:上传整个文件夹到服务器。我一开始没当回事,直到测试拿着一份几十层的设备图纸目录,拖到页面上才发现,普通 file input 根本不支持选文件夹。那一刻我才意识到,JSP 里的文件夹上传,和普通文件上传完全是两码事:前端要拿到目录结构,后端要按目录结构落盘,中间还要处理中文路径、重名覆盖、大目录超时这类问题。这篇文章就梳理一下我实际调研和测试过的开源文件夹上传组件,以及最后真正跑通的方案。
1. 先搞清楚“文件夹上传”到底难在哪
1.1 普通文件上传组件为什么处理不了文件夹
HTML 里最标准的 <input type="file"> 虽然有 multiple 属性,但它的语义是“多个文件”,不是“一个文件夹”。用户点击选择文件时,浏览器弹出的系统对话框并没有提供目录树选择模式,你只能按 Ctrl 键一个个点选文件。很多开源上传组件本质上还是在操作这个 input 标签,顶多做了拖拽、队列、进度条这些外围功能,并没有真正解决“目录结构”的问题。
文件夹上传的核心难点在于:浏览器默认不会告诉你文件在哪个目录。服务器收到一堆文件流之后,根本不知道它们原本的层级关系;就算能把名字对上,也没有办法还原多层目录。所以“开源文件夹上传组件”这个概念,拆开来看其实是两部分:前端负责拿到目录结构和文件列表,后端负责根据结构把文件落盘。单靠一个组件很难包办。
1.2 浏览器给的上传能力边界:webkitdirectory 是核心
后来我做了一轮技术验证,发现浏览器其实提供了原生能力,只是很多项目没用过。给 input 加上 webkitdirectory 和 multiple,Chrome、Edge、Firefox 会弹出目录选择器,选中整个文件夹之后,input.files 里会返回该目录下所有文件。关键属性是每个 File 对象上的 webkitRelativePath,它会返回类似 设备图纸/0305批次/结构图/001.dwg 这样的相对路径,这正是服务端重建目录结构的关键信息。
这个原生能力已经存在很多年了,比很多开源组件都稳定。但问题在于,它只解决了“选择文件夹”这一步,后面的队列管理、路径拼接、安全校验、大目录分批上传,都需要自己写。所以我们可以用原生 API 做地基,再配上开源的服务端库,形成一套完整方案。
1.3 选型之前先画一条边界
我在动手之前给自己画了一条边界:前端负责把“相对路径”传给后端,后端负责安全地按相对路径创建目录和写文件,组件只负责解决“选择目录”和“上传流程”。带着这个边界再去调研开源组件,就会非常清楚哪些能用、哪些需要改造。
选型时我会问三个问题:这个组件支持不支持读取 webkitRelativePath?社区还在维护吗?和当前 JSP 项目里的 jQuery、Bootstrap 老一套能不能兼容?这三个问题卡下来,很多组件其实已经被淘汰了。接下来我把实际调研到的几款开源组件列出来,说清楚它们的优缺点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 亲身用过和调研过的开源组件横评
2.1 百度 WebUploader:最契合但已停止维护
提到文件夹上传,很多做 Java Web 的老工程师第一反应就是百度 FEX 团队开源出来的 WebUploader。它在 GitHub 上的仓库是 fex-team/webuploader,MIT 协议,支持文件夹选择、拖拽上传、分片上传、并发控制和上传进度,底层同时封装了 HTML5 和 Flash 两种模式,当年就是为了兼容 IE8+ 设计的。它对文件夹的支持逻辑就是基于 webkitRelativePath 的,拿到相对路径之后,可以在 beforeUpload 回调里把它放到上传请求里,后端再按这个路径存文件。
我在一个老 ERP 项目里确实用过 WebUploader,当时的感觉是功能很全,配置项多到可以满足大部分需求。但后来再看,这个项目基本已经处于停更状态,仓库常年没有新提交,官方文档里推荐你下载的 JS 文件也是很多年前编译的。它依赖 jQuery 1.x,在现代浏览器里偶尔会碰到按钮点击无响应、上传队列闪烁这类问题。如果你手里的 JSP 项目刚好是 Bootstrap 3 + jQuery 1.12 + IE 这种古董组合,WebUploader 仍然值得考虑;但如果用户已经切换到 Chrome 或者 Edge,我更建议别再往里面引了。
2.2 Blueimp jQuery-File-Upload:文件上传神器,文件夹能力弱
Blueimp 的 jQuery-File-Upload 在 GitHub 上 Star 数量很多,也是 MIT 协议,jQuery 时代文件上传库里的“事实标准”。它支持多文件选择、拖拽上传、进度条、缩略图、分块上传,服务端还提供了 Java 示例,集成很方便。
但它是文件上传组件,不是文件夹上传组件。你把 webkitdirectory 加到它的 input 上,它也能把文件夹下的所有文件塞进队列,但每个文件不会自动携带目录路径。你必须自己读 file.webkitRelativePath,在 add 回调里把路径塞到 formData 里,后端再单独取出来用。等于说,你只是借了它的队列、重试、进度 UI,核心的文件夹逻辑还是自己写。如果你的 JSP 项目已经在用 jQuery,并且不想引入太多新库,Blueimp 是一个不错的底子,但不要指望它开箱即用。
2.3 Plupload / Dropzone.js / Fine Uploader:各有侧重,但都需要二次开发
Plupload 是老牌开源上传组件,授权是 GPLv2 或者商业授权。它支持 HTML5、Flash、Silverlight 等多种运行时,早年兼容性很强。我实际用过之后的感觉是,它的队列交互很成熟,分片上传也稳定,但文件夹支持同样是短板,目录树的信息不会自动带过来。
Dropzone.js 是一个轻量库,MIT 协议,界面简洁好看,适合快速搭一个拖拽上传区。它的文件上传交互做得非常舒服,但默认也只是多文件上传,文件夹支持需要通过自定义事件读取 webkitRelativePath,能力属于“可以改”的级别。Fine Uploader 有开源版,协议是 GPLv3,原生支持部分文件夹上传,但 GPLv3 对商业项目有协议传染风险,在对接 JSP 商业系统之前一定要先和法务确认许可证。
这几款开源组件的共同问题,都不是“能不能用”,而是“帮你做了一半就让你自己去填剩下的一半”。与其这样,不如直接用原生方案,代码完全可控,排查问题也更容易。
2.4 横向对比表格
| 组件名称 | 开源协议 | 文件夹上传支持 | 维护状态 | 适合场景 |
|---|---|---|---|---|
| 百度 WebUploader | MIT | 原生支持 | 基本停更 | 兼容 IE8+ 的旧 JSP 系统 |
| Blueimp jQuery-File-Upload | MIT | 需二次开发 | 较活跃 | jQuery 技术栈的多文件上传 |
| Plupload | GPLv2/商业 | 仅多文件 | 已归档 | 老浏览器兼容场景 |
| Dropzone.js | MIT | 需二次开发 | 活跃 | 轻量界面,快速集成 |
| Fine Uploader | GPLv3/商业 | 原生支持,协议需评估 | 维护中 | 对协议合规有把握的项目 |
| 原生 |
