<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" 是文件上傳的前置條件,瀏覽器將文件以二進制流形式提交。
getServletContext().getRealPath("/WEB-INF/upload") —— 放在 WEB-INF 禁止外部直接訪問DiskFileItemFactory 工廠 + ServletFileUpload 解析器isMultipartContent()parseRequest() 獲得 List<FileItem>,遍歷區分普通字段與文件流item.getInputStream() → 緩衝區 1KB → FileOutputStream 寫入磁盤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:總大小超限<c:forEach> 渲染下載鏈接,參數攜帶原文件名// 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();
fileName.substring(fileName.indexOf("_")+1)