文件上傳是 Web 開發高頻需求。Apache Commons FileUpload 是經典、穩定的解析庫,支援大文件流式處理、進度條、多文件、表單字段混合。本文給出 Maven 依賴、web.xml、JSP 表單、Servlet 核心邏輯、異常處理與生產建議。
<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>
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.servlet.UploadServlet</servlet-class>
<init-param>
<param-name>filePath</param-name>
<param-value>/data/upload/</param-value> <!-- 存儲目錄 -->
</init-param>
<multipart-config> <!-- Servlet 3.0 原生支援,可替代 FileUpload -->
<max-file-size>52428800</max-file-size> <!-- 50MB -->
<max-request-size>104857600</max-request-size>
<file-size-threshold>1048576</file-size-threshold> <!-- 1MB 閾值寫磁盤 -->
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/servlet/UploadServlet</url-pattern>
</servlet-mapping>
<form action="servlet/UploadServlet" method="post" enctype="multipart/form-data"> <input type="file" name="file1"/><br/> <input type="file" name="file2"/><br/> <input type="text" name="description1" placeholder="文件1說明"/><br/> <input type="text" name="description2" placeholder="文件2說明"/><br/> <input type="submit" value="上傳"/> </form>
package com.servlet;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.List;
@WebServlet("/servlet/UploadServlet")
public class UploadServlet extends HttpServlet {
private String uploadPath;
@Override public void init() {
uploadPath = getServletConfig().getInitParameter("filePath");
new File(uploadPath).mkdirs();
}
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
// 1. 檢查是否 multipart
if (!ServletFileUpload.isMultipartContent(req)) {
out.println("請求不是 multipart/form-data"); return;
}
// 2. 工廠:設置內存閾值、臨時目錄
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1024 * 1024); // 1MB 以上寫臨時文件
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
// 3. 解析器:設置大小限制
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(50 * 1024 * 1024); // 50MB
upload.setSizeMax(100 * 1024 * 1024); // 總請求 100MB
try {
List items = upload.parseRequest(req);
for (FileItem item : items) {
if (item.isFormField()) { // 普通表單字段
String val = item.getString("UTF-8");
out.printf("字段: %s = %s<br/>", item.getFieldName(), val);
} else { // 文件字段
String fileName = new File(item.getName()).getName(); // 防路徑遍歷
File saveFile = new File(uploadPath, fileName);
try (InputStream in = item.getInputStream();
OutputStream outStream = new FileOutputStream(saveFile)) {
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) outStream.write(buf, 0, len);
}
out.printf("文件上傳成功: %s (%d bytes)<br/>", fileName, item.getSize());
}
}
} catch (FileUploadException e) {
out.println("解析失敗: " + e.getMessage());
} catch (Exception e) {
out.println("服務器錯誤: " + e.getMessage());
e.printStackTrace();
}
}
}
DiskFileItemFactory 設閾值,大文件自動落盤,不佔堆內存。new File(item.getName()).getName() 防止 `../../etc/passwd` 路徑遍歷;限制文件類型、大小、總請求大小。item.getString("UTF-8") 統一 UTF-8,避免中文亂碼。FileUploadException、SizeLimitExceededException 返回友好提示。req.getPart("file") 可完全替代 FileUpload,零依賴,推薦新項目使用。

掌握 FileUpload 核心流程,輕松應對從簡單表單到大文件斷點續傳的各類上傳場景。