文件上傳下載是 Web 開發高頻需求。本文基於 Apache Commons FileUpload 組件,構建完整的上傳解析、存儲、列表展示、下載響應全鏈路。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
enctype="multipart/form-data" method="post"<input type="file" name="file">web.xml context-param,便於維護。
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(maxMemSize); // 內存閾值
factory.setRepository(new File(tempPath)); // 臨時目錄
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(maxFileSize); // 最大文件限制
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) { // 過濾普通表單字段
String fileName = item.getName();
File saveFile = new File(uploadPath, fileName);
item.write(saveFile); // 核心寫入方法
}
}
Map<原始文件名, 顯示名> 傳給 JSP,JSTL 遍歷生成下載鏈接。
// 1. 獲取參數、解決中文亂碼
String fileName = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
// 2. 定位文件(支持散列子目錄)
String realPath = findFilePath(fileName, rootPath);
File file = new File(realPath, fileName);
// 3. 設置響應頭:關鍵在於 Content-Disposition
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(displayName, "UTF-8"));
response.setContentType("application/octet-stream");
// 4. 流式傳輸,避免大文件 OOM
try (FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) out.write(buffer, 0, len);
}
| 問題 | 解決方案 |
|---|---|
| 大文件上傳超時/斷點續傳 | 前端分片上傳 + 後端合併,或引入 Resumable.js/Uppy |
| 文件類型驗證 | 檢查 Magic Number (文件頭) 而非僅靠擴展名 |
| 存儲擴展性 | 對接 MinIO / S3 / OSS,數據庫只存元數據 |
| 下載限速/權限控制 | Token 鑒權 + ThrottledOutputStream |
掌握原生 Servlet 處理流,能深入理解框架封裝本質,排查疑難雜症時更得心應手。