| 套件 | 版本 | 說明 |
| commons-fileupload | 1.1-dev | 核心上傳處理 |
| commons-io | 1.1-dev | 必須,缺少會拋 ClassNotFoundException: DeferredFileOutputStream |
二、應用伺服器檔案系統權限
WebLogic 等容器預設安全策略限制檔案讀寫。需在 weblogic.policy 加入:
permission java.io.FilePermission "<<ALL FILES>>", "read,write,delete";
否則會噴 FileUploadException: InvocationTargetException 錯誤堆疊。
三、標準 Servlet 寫法 (FileUpload 1.1+)
舊版 parseRequest(request) 回傳 List<FileItem>,新版建議搭配 ServletFileUpload 與 DiskFileItemFactory。
public class FileUploadServlet extends HttpServlet {
private String uploadPath = "D:/addnetFile/";
private File tempPath = new File("D:/addnetFile/tmp/");
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html; charset=GB2312");
PrintWriter out = res.getWriter();
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(4096); // 4KB 以上存臨時檔
factory.setRepository(new File("d:/File/addnetFile/temp"));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(1000000); // 限制 1MB
try {
List<FileItem> items = upload.parseRequest(req);
Iterator<FileItem> iter = items.iterator();
// 正則取檔名 (去除路徑)
Pattern p = Pattern.compile(".+\\\\(.+)$");
String[] errorTypes = {".exe", ".com", ".cgi", ".asp"};
while (iter.hasNext()) {
FileItem item = iter.next();
if (item.isFormField()) continue; // 忽略一般表單欄位
String name = item.getName();
if (name == null || name.isEmpty() || item.getSize() == 0) continue;
Matcher m = p.matcher(name);
if (!m.find()) throw new IOException("檔名解析失敗");
String fileName = m.group(1);
// 檢查副檔名黑名單
for (String ext : errorTypes) {
if (fileName.toLowerCase().endsWith(ext)) {
throw new IOException("禁止上傳執行檔:" + fileName);
}
}
// 儲存檔案
File savedFile = new File(uploadPath + fileName);
item.write(savedFile);
out.print(fileName + " " + item.getSize() + "<br>");
}
} catch (FileUploadException | IOException e) {
out.println("上傳失敗:" + e.getMessage());
}
}
}
四、前端表單關鍵點
<form action="FileUploadServlet" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
<input type="file" name="file2">
<input type="submit" value="上傳">
</form>
- enctype="multipart/form-data" 必須設定
name 屬性對應後端 FileItem.getFieldName()
五、不同容器的行為差異
Tomcat、WebLogic、Resin 對臨時目錄、請求解析行為略有不同,建議:
- 明確指定
factory.setRepository(...)
- 測試時觀察
req.getContentType() 與 req.getContentLength()
- 大檔案上傳調整
setSizeThreshold 與 setSizeMax
總結
- 引對依賴:
fileupload + io,別信舊文檔加 beanutils。
- 給權限:Policy 檔加
FilePermission。
- 用新 API:
ServletFileUpload + DiskFileItemFactory。
- 防惡意:副檔名白/黑名單、檔案大小限制、病毒掃描整合。
- 上一篇文章: Java 實作軟體試用期控制:登入次數與到期時間雙重驗證
- 下一篇文章: Spring 環境下業務層單元測試實戰:脫離容器的 TDD 之路
Copyright ©
程式碼之家 All Rights Reserved