本文提供基於 Apache Commons FileUpload 組件的文件上傳完整 Demo,包含前端 JSP、後端 Servlet、結果頁面與 web.xml 配置,可直接部署至 Tomcat 等 Servlet 容器運行。
| 組件 | 特點 | 適用場景 |
|---|---|---|
| Apache Commons FileUpload | 標準、輕量、社群活躍 | 通用 Servlet/JSP 專案、Spring MVC 底層實作 |
| JavaZoom UploadBean | 功能豐富、商業授權 | 企業級需進階功能 (壓縮、水印、轉檔) |
| jspSmartUpload | 早期經典、已停止維護 | 舊系統維護、不建議新專案採用 |
WebApp/
├── WebContent/
│ ├── upload.jsp # 上傳表單頁面
│ ├── uploadResult.jsp # 上傳結果頁面
│ └── WEB-INF/
│ ├── web.xml # 部署描述檔
│ └── lib/
│ ├── commons-fileupload-1.2.2.jar
│ └── commons-io-1.4.jar
└── src/
└── com/b510/example/
└── FileUploadServlet.java
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Commons FileUpload 文件上傳</title>
<meta charset="UTF-8">
<style>
body { font-family: "微軟正黑體", sans-serif; font-size: 14px; }
.container { max-width: 600px; margin: 50px auto; padding: 20px; border: 1px solid #ddd; }
.form-group { margin-bottom: 15px; }
label { display: inline-block; width: 80px; text-align: right; margin-right: 10px; }
input[type="file"] { border: 1px solid #ccc; padding: 5px; }
.btn { padding: 8px 20px; margin-right: 10px; cursor: pointer; }
</style>
</head>
<body>
<div class="container">
<h2 align="center">文件上傳測試</h2>
<form id="uploadForm" action="servlet/fileServlet" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>上傳人:</label>
<input type="text" name="uploader" id="uploader" size="30" required/>
</div>
<div class="form-group">
<label>選擇檔案:</label>
<input type="file" name="uploadFile" id="uploadFile" required/>
</div>
<div class="form-group">
<label></label>
<input type="submit" class="btn" value="提交上傳">
<input type="reset" class="btn" value="重置">
</div>
</form>
</div>
</body>
</html>
package com.b510.example;
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.*;
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletContext servletContext;
private String savePath; // 從 web.xml 讀取
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.servletContext = config.getServletContext();
this.savePath = config.getInitParameter("savePath"); // 如 "uploads"
// 初始化時建立目錄
File uploadDir = new File(servletContext.getRealPath("/") + savePath);
if (!uploadDir.exists()) uploadDir.mkdirs();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8"); // 解決中文檔名
try {
List<FileItem> items = upload.parseRequest(request);
Iterator<FileItem> iter = items.iterator();
String uploadMessage = "上傳失敗!";
while (iter.hasNext()) {
FileItem item = iter.next();
if (item.isFormField()) {
// 處理一般表單欄位
String fieldName = item.getFieldName();
String fieldValue = item.getString("UTF-8");
System.out.println("表單參數: " + fieldName + " = " + fieldValue);
} else {
// 處理上傳文件
String fileName = item.getName();
if (fileName != null && !fileName.isEmpty()) {
System.out.println("上傳檔案大小: " + item.getSize() + " bytes");
System.out.println("檔案類型: " + item.getContentType());
System.out.println("原始檔名: " + fileName);
// 取得純檔名 (去除客戶端路徑)
File tempFile = new File(fileName);
String onlyFileName = tempFile.getName();
// 為避免同名覆蓋,可加入 UUID 前綴
String savedName = UUID.randomUUID().toString() + "_" + onlyFileName;
File savedFile = new File(servletContext.getRealPath("/") + savePath, savedName);
item.write(savedFile); // 自動清理暫存檔
uploadMessage = "上傳成功!檔案已儲存為: " + savedName;
} else {
uploadMessage = "未選擇上傳檔案!";
}
}
}
request.setAttribute("uploadMessage", uploadMessage);
request.getRequestDispatcher("/uploadResult.jsp").forward(request, response);
} catch (FileUploadException e) {
e.printStackTrace();
request.setAttribute("uploadMessage", "解析上傳請求失敗: " + e.getMessage());
request.getRequestDispatcher("/uploadResult.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("uploadMessage", "系統錯誤: " + e.getMessage());
request.getRequestDispatcher("/uploadResult.jsp").forward(request, response);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>上傳結果</title>
<meta charset="UTF-8">
<style>
.result-box { padding: 20px; border: 1px solid #4CAF50; background: #f1f8f4; margin: 20px auto; max-width: 600px; }
.back-link { display: inline-block; margin-top: 15px; color: #2196F3; text-decoration: none; }
</style>
</head>
<body>
<div class="result-box">
<h3>上傳處理結果</h3>
<p><strong>${requestScope.uploadMessage}</strong></p>
<a href="upload.jsp" class="back-link">← 返回繼續上傳</a>
</div>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="https://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://xmlns.jcp.org/xml/ns/javaee
https://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<servlet>
<servlet-name>FileUploadServlet</servlet-name>
<servlet-class>com.b510.example.FileUploadServlet</servlet-class>
<init-param>
<param-name>savePath</param-name>
<param-value>uploads</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FileUploadServlet</servlet-name>
<url-pattern>/servlet/fileServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>upload.jsp</welcome-file>
</welcome-file-list>
</web-app>
<dependencies>
<!-- Servlet API (provided 由容器提供) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- Commons IO (FileUpload 依賴) -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
<input type="file" name="files" multiple>,後端遍歷同名 FileItem@MultipartConfig + HttpServletRequest.getPart() 或 Spring MVC MultipartFile| 現象 | 可能原因 | 解決方案 |
|---|---|---|
| item.isFormField() 全為 true | 表單缺少 enctype="multipart/form-data" | 檢查 form 標籤屬性 |
| 中文檔名亂碼 | 未設定 Header 編碼 | upload.setHeaderEncoding("UTF-8") |
| 大檔上傳失敗 | 超過預設大小限制 | 調整 upload.setSizeMax() 或容器配置 |
| 暫存檔殘留 | 未呼叫 item.write() 或 item.delete() | 務必使用 item.write(File) 自動清理 |
| 權限拒絕 | 目錄寫入權限不足 | 確保 Servlet 容器進程有目錄寫入權限 |
本 Demo 展示了 Commons FileUpload 的標準用法,涵蓋從表單提交、Servlet 解析、檔案儲存到結果回饋的完整流程。實際專案中建議封裝為通用工具類或整合 Spring MVC 的 MultipartResolver,並加入檔案類型驗證、大小限制、防毒掃描等安全機制。