首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JavaWeb 文件上傳下載完整實戰:Commons FileUpload 深度應用與生產級優化

     編輯:Java 相關知識

技術棧與依賴

  • 核心組件:Apache Commons FileUpload + Commons IO
  • Servlet 3.0+ 環境(亦可適用 2.5 配置 web.xml)
  • 編碼統一 UTF-8,防止中文文件名亂碼

基礎上傳流程實現

前端表單關鍵屬性

<form action="/servlet/UploadHandleServlet" 
      enctype="multipart/form-data" method="post">
    <input type="text" name="username"/>
    <input type="file" name="file1"/>
    <input type="file" name="file2"/>
</form>

enctype="multipart/form-data" 是文件上傳的前置條件,瀏覽器將文件以二進制流形式提交。

Servlet 核心處理邏輯

  1. 獲取存儲路徑:getServletContext().getRealPath("/WEB-INF/upload") —— 放在 WEB-INF 禁止外部直接訪問
  2. 創建 DiskFileItemFactory 工廠 + ServletFileUpload 解析器
  3. 設置 Header 編碼 UTF-8,判斷 isMultipartContent()
  4. parseRequest() 獲得 List<FileItem>,遍歷區分普通字段與文件流
  5. 文件流讀寫:item.getInputStream() → 緩衝區 1KB → FileOutputStream 寫入磁盤
  6. 清理臨時文件:item.delete()

生產級五大優化細節

問題風險解決方案
文件存儲路徑暴露用戶可直接 URL 訪問上傳文件存放於 WEB-INF 目錄下,Servlet 轉發下載
文件名衝突覆蓋同名文件導致數據丟失UUID + 原文件名:UUID.randomUUID() + "_" + filename
單目錄文件過多文件系統性能下降、inode 耗盡Hash 分散存儲:hashCode & 0xF 兩級子目錄
大文件佔用內存OOM、服務器響應超時工廠設置閾值 setSizeThreshold(100KB),超閾值自動寫臨時文件
惡意大文件/類型攻擊磁盤耗盡、腳本注入setFileSizeMax(1MB)、setSizeMax(10MB)、副驗證擴展名

進階功能實現

上傳進度監聽

upload.setProgressListener(new ProgressListener() {
    public void update(long pBytesRead, long pContentLength, int items) {
        System.out.println("進度: " + pBytesRead + "/" + pContentLength);
    }
});

可結合 AJAX 輪詢或 WebSocket 實現前端進度條。

異常精細處理

  • FileSizeLimitExceededException:單文件超限
  • SizeLimitExceededException:總大小超限
  • 統一轉發到提示頁,避免堆棧信息洩露

文件下載實現

列表頁構建

  1. 遞歸遍歷上傳目錄(或查詢數據庫元數據表)
  2. Map<原文件名, 顯示名> 傳遞給 JSP
  3. JSTL <c:forEach> 渲染下載鏈接,參數攜帶原文件名

下載 Servlet 核心邏輯

// 1. 獲取參數並解碼
String fileName = URLDecoder.decode(request.getParameter("filename"), "UTF-8");
// 2. 定位文件(Hash 反推路徑)
String path = findFileSavePathByFileName(fileName, rootPath);
// 3. 設置響應頭強制下載
response.setHeader("Content-Disposition", 
    "attachment;filename=" + URLEncoder.encode(displayName, "UTF-8"));
// 4. 流式傳輸
FileInputStream in = new FileInputStream(path + "/" + fileName);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) out.write(buffer, 0, len);
in.close(); out.close();

關鍵細節

  • 文件名解碼/編碼雙向處理,解決中文下載亂碼
  • 顯示名去除 UUID 前綴:fileName.substring(fileName.indexOf("_")+1)
  • 流式傳輸避免大文件載入內存
  • 文件不存在優雅降級提示

架構升級建議

  1. 元數據數據庫化:建表存儲 (id, original_name, store_path, size, uploader, upload_time, md5),避免遞歸掃描
  2. 雲存儲對接:上傳直傳 OSS/S3,服務端僅保存元數據與簽名
  3. 斷點續傳:前端分片 + 後端合併,支持大文件、弱網環境
  4. 安全掃描:集成 ClamAV 或內容識別,攔截惡意文件
  5. 權限控制:下載鏈接簽名時效、角色權限校驗、防盜鏈 Referer 檢查
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved