- 后端: 使用 Java 代码(通常是 Servlet)来接收和处理从客户端上传的文件。
- 前端: 使用 HTML 的
<input type="file">元素来让用户选择文件,并通过表单提交。
下面我将提供一个完整、分步的示例,包括前端 HTML 和后端 Java Servlet 代码。

核心概念
-
<form>:method="post": 文件上传必须使用POST方法,因为GET方法有 URL 长度限制且不安全。enctype="multipart/form-data": 这是最关键的一步,它告诉浏览器要对表单数据进行特殊编码,以便能够以二进制流的形式上传文件,而不是将文件内容编码到 URL 中。
-
<input type="file">: 创建一个文件选择框,用户可以在此选择本地文件。 -
后端处理:
- 浏览器发送
multipart/form-data格式的请求,后端无法像普通表单数据那样用request.getParameter()来获取文件。 - 我们需要使用一个专门的库来解析这种复杂的请求体。Apache Commons FileUpload 是最经典和常用的选择,现在更推荐其升级版 Apache Commons FileUpload2 或 Servlet API 3.0+ 内置的支持。
- 浏览器发送
使用 Apache Commons FileUpload (经典方案,适用于 Servlet 2.x 和 3.x)
这个方案兼容性好,即使你的项目运行在较旧的 Servlet 容器中也能使用。

步骤 1: 添加依赖
如果你使用 Maven,在 pom.xml 中添加以下依赖:
<dependencies>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload2-jakarta</artifactId>
<version>2.0.0-M2</version>
</dependency>
<!-- Commons IO (FileUpload 依赖它) -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
注意:
commons-fileupload2-jakarta是 Jakarta EE 版本,适用于 Tomcat 10+ 等现代 Servlet 容器,如果你的项目是传统的 Java EE (Tomcat 9-),请使用commons-fileupload2(非 jakarta)。
步骤 2: 创建前端 HTML (upload.html)
创建一个简单的 HTML 文件,包含一个文件上传表单。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">文件上传示例</title>
<style>
body { font-family: sans-serif; margin: 20px; }
.container { max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ccc; border-radius: 8px; }
input[type="file"] { margin-bottom: 10px; }
input[type="submit"] { padding: 10px 15px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<div class="container">
<h2>上传文件</h2>
<form action="upload" method="post" enctype="multipart/form-data">
<!--
name="file" 必须与后端代码中获取的 field name 一致
multiple="multiple" 允许多选
-->
<input type="file" name="file" multiple required>
<br>
<input type="submit" value="上传">
</form>
</div>
</body>
</html>
步骤 3: 创建后端 Servlet (FileUploadServlet.java)
这是处理文件上传的核心逻辑。

import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload2.core.FileItemFactory;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@WebServlet("/upload") // 将 Servlet 映射到 /upload 路径
public class FileUploadServlet extends HttpServlet {
// 上传文件存储目录 (在 webapp 目录下创建一个 uploads 文件夹)
private static final String UPLOAD_DIRECTORY = "uploads";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 检查请求是否包含 multipart
boolean isMultipart = JakartaServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "请求必须是 multipart/form-data 类型");
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存中存储文件大小的阈值 (1MB)
factory.setSizeThreshold(1024 * 1024);
// 设置临时目录
File tempDir = (File) getServletContext().getAttribute("jakarta.servlet.context.tempdir");
factory.setRepository(tempDir);
JakartaServletDiskFileUpload upload = new JakartaServletDiskFileUpload(factory);
// 设置最大文件大小 (10MB)
upload.setFileSizeMax(1024 * 1024 * 10);
// 设置整个请求的最大大小 (20MB)
upload.setSizeMax(1024 * 1024 * 20);
// 解析请求,获取文件项列表
List<FileItem> formItems;
try {
formItems = upload.parseRequest(request);
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "解析请求失败: " + e.getMessage());
return;
}
// 处理上传的文件
for (FileItem item : formItems) {
// 检查当前 item 是否是普通表单字段还是文件
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY + File.separator + fileName;
// 确保上传目录存在
File uploadDir = new File(getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
// 保存文件到服务器
try {
item.write(new File(filePath));
System.out.println("文件 " + fileName + " 已成功上传到 " + filePath);
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "保存文件失败: " + e.getMessage());
return;
}
}
}
// 上传成功后,重定向到成功页面
response.sendRedirect("success.html");
}
}
步骤 4: 创建成功页面 (success.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">上传成功</title>
</head>
<body>
<h1>文件上传成功!</h1>
<p><a href="upload.html">返回上传页面</a></p>
</body>
</html>
使用 Servlet 3.0+ 内置 API (现代方案)
如果你使用的是 Servlet 3.0 或更高版本(Tomcat 7+, Jetty 8+, WildFly 8+ 等),可以直接使用 Servlet API 内置的功能,无需引入第三方库。
步骤 1 & 2: 前端 HTML 和依赖
前端 HTML (upload.html) 和 Maven 依赖中的 Servlet API 部分与方案一完全相同。
步骤 3: 创建后端 Servlet (ModernFileUploadServlet.java)
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
@WebServlet("/upload-modern")
// 使用 @MultipartConfig 注解来配置文件上传
@MultipartConfig(
fileSizeThreshold = 1024 * 1024, // 1 MB 内存缓存阈值
maxFileSize = 1024 * 1024 * 10, // 单个文件最大 10MB
maxRequestSize = 1024 * 1024 * 20 // 整个请求最大 20MB
)
public class ModernFileUploadServlet extends HttpServlet {
private static final String UPLOAD_DIRECTORY = "uploads";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 确保上传目录存在
String uploadPath = getServletContext().getRealPath("") + File.separator + UPLOAD_DIRECTORY;
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
// 获取所有上传的 Part
Collection<Part> parts = request.getParts();
for (Part part : parts) {
// 获取文件名
String fileName = getSubmittedFileName(part);
if (fileName != null && !fileName.isEmpty()) {
// 构建服务器上的文件路径
String filePath = uploadPath + File.separator + fileName;
// 将 Part 写入文件
part.write(filePath);
System.out.println("文件 " + fileName + " 已成功上传到 " + filePath);
}
}
response.sendRedirect("success.html");
}
/**
* 辅助方法:从 Part 对象中提取文件名
*/
private String getSubmittedFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
return fileName.substring(fileName.lastIndexOf(File.separator) + 1); // 处理不同操作系统的路径分隔符
}
}
return null;
}
}
注意: 这里我们使用了
@WebServlet("/upload-modern")和@MultipartConfig注解,使代码更加简洁。
总结与对比
| 特性 | 方案一 (Commons FileUpload) | 方案二 (Servlet 3.0+) |
|---|---|---|
| 依赖 | 需要添加 commons-fileupload 和 commons-io |
无需额外依赖,只需 Servlet API |
| 代码复杂度 | 较高,需要手动解析请求、创建工厂、设置参数 | 非常低,使用注解 @MultipartConfig 即可 |
| 兼容性 | 非常好,适用于所有 Servlet 2.x 和 3.x+ | 有限,仅适用于 Servlet 3.0 及以上版本 |
| 推荐度 | 对于旧项目或需要精细控制时使用 | 强烈推荐,对于新项目,这是最标准、最简洁的方式 |
重要注意事项
-
安全性:
- 文件名: 用户上传的文件名可能包含恶意字符或路径遍历攻击(如
../../../malicious.txt),在上传前,务必对文件名进行清理和验证。 - 文件类型: 不要仅依赖文件扩展名,检查文件的“魔数”(Magic Numbers)或使用专门的库(如 Apache Tika)来验证文件的真实类型,防止上传恶意脚本(如
.jsp,.php)。 - 病毒扫描: 对于生产环境,上传的文件应经过病毒扫描。
- 存储位置: 不要将文件存储在 Web 服务器的根目录下,以防止直接访问,最好放在
WEB-INF目录或其子目录下,这样它们就不能通过 URL 直接访问了。
- 文件名: 用户上传的文件名可能包含恶意字符或路径遍历攻击(如
-
性能:
- 对于非常大的文件,内存和临时文件的处理方式会影响性能。
@MultipartConfig和FileUpload都允许你配置内存缓存大小和临时目录。
- 对于非常大的文件,内存和临时文件的处理方式会影响性能。
-
配置:
- 在
web.xml中配置max-file-size和max-request-size(如果不用注解)也是一个好习惯,作为双重保障。
- 在
希望这个详细的指南能帮助你成功实现 Java Web 文件上传功能!
