文件上传是 Java Web 开发必学核心知识点,日常项目、后台管理系统都高频用到。整体一共四种主流实现方式,分上下两篇:
上篇:Servlet2.5传统上传、Servlet3.0原生无依赖上传
下篇 :SpringMVC 两种文件上传写法(直接接收 MultipartFile、强转 MultipartHttpServletRequest)JavaWeb四种文件上传方式(下篇)-CSDN博客
环境:Tomcat 8.5 + JDK8 + Maven 所有代码可直接复制运行
一、Servlet2.5传统文件上传(commons 工具版)
1. 原理
早期 Servlet 没有内置文件上传功能,必须依赖 commons-fileupload + commons-io 两个第三方工具包。:
DiskFileItemFactory:磁盘文件工厂,设置内存阈值、临时缓存目录ServletFileUpload:上传解析器,解析请求参数FileItem:封装每一个表单字段,区分普通文本字段 和文件字段
流程:表单携带文件 → 解析请求 → 遍历表单项 → 提取文件名 → UUID 重命名 → 写入磁盘
2. Maven依赖
XML
<dependencies>
<!-- Servlet 原生依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- 文件上传核心依赖 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
3. 上传表单jsp
XML
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Servlet2.5 文件上传</title>
</head>
<body>
<%-- 文件上传必须加 enctype="multipart/form-data" --%>
<form action="/updateFile" method="post" enctype="multipart/form-data">
文件选择:<input type="file" name="file"/><br>
<input type="submit" value="提交上传">
</form>
</body>
</html>
4. Servlet
java
package com.qcby.servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
req.setCharacterEncoding("UTF-8");
// 1. 判断当前请求是否为文件上传类型
if (!ServletFileUpload.isMultipartContent(req)) {
resp.getWriter().write("错误:表单不是文件上传类型!");
return;
}
try {
// 2. 创建磁盘工厂 + 上传解析器
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 解析请求,获取所有表单项
List<FileItem> fileItems = upload.parseRequest(req);
// 4. 遍历表单项
for (FileItem item : fileItems) {
// 判断:不是普通文本字段 = 文件字段
if (!item.isFormField() && "file".equals(item.getFieldName())) {
// 获取原始文件名
String originalFilename = item.getName();
// 截取文件后缀
String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
// UUID 生成唯一文件名,防止重名覆盖
String newFileName = UUID.randomUUID().toString().replace("-","") + ext;
// 5. 定义保存目录,不存在则自动创建
File uploadDir = new File("D:/Aupload");
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
// 6. 保存文件到磁盘
File saveFile = new File(uploadDir, newFileName);
item.write(saveFile);
resp.getWriter().write("Servlet2.5 上传成功!新文件名:" + newFileName);
}
}
} catch (Exception e) {
e.printStackTrace();
resp.getWriter().write("上传失败:" + e.getMessage());
}
}
}
5. web.xml配置
XML
<servlet>
<servlet-name>fileServlet</servlet-name>
<servlet-class>com.qcby.servlet.FileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fileServlet</servlet-name>
<url-pattern>/updateFile</url-pattern>
</servlet-mapping>
6. 总结
- 依赖第三方 commons 包,不能脱离依赖单独使用
- 代码偏繁琐,需要手动区分普通字段和文件字段
- 兼容性老项目,现在新项目很少手写这套
- 必须表单指定
enctype="multipart/form-data"
二、Servlet3.0原生文件上传(无依赖版)
1. 原理
Servlet3.0 开始内置文件上传功能 ,无需导入 commons-fileupload、commons-io 依赖。
@MultipartConfig:注解开启 Servlet3.0 上传支持request.getPart("file"):直接获取上传文件对象- 不用手动解析表单项,API 更简洁
适合学习基础原理,不用引入额外依赖,代码极简。
2. Maven依赖
只需要原生 servlet 依赖即可:
XML
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
3. 上传表单jsp
XML
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Servlet3.0 原生上传</title>
</head>
<body>
<form action="upload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="file"/><br>
<input type="submit" value="原生上传提交">
</form>
</body>
</html>
4. Servlet3.0完整代码
java
package com.qcby.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
// 路径注解配置
@WebServlet("/upload3")
// 开启文件上传功能
@MultipartConfig
public class Upload3Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 1. 根据表单name获取文件Part对象
Part part = request.getPart("file");
// 2. 解析请求头,提取原始文件名
String header = part.getHeader("content-disposition");
String fileName = header.substring(header.lastIndexOf("filename=") + 10);
fileName = fileName.replace("\"","");
// 3. 截取后缀 + UUID 重命名
String suffix = fileName.substring(fileName.lastIndexOf("."));
String newName = UUID.randomUUID().toString().replace("-","") + suffix;
// 4. 定义保存目录,自动创建
File saveDir = new File("D:/Aupload3");
if(!saveDir.exists()){
saveDir.mkdirs();
}
// 5. 写入磁盘
part.write(saveDir + File.separator + newName);
response.getWriter().write("Servlet3.0 原生上传成功!文件名:" + newName);
}
}
5. 总结
- 零第三方依赖,仅 Servlet3.0 原生支持
- 注解开发:
@WebServlet+@MultipartConfig,无需 web.xml - API 简洁:
getPart()直接获取文件 - 适合学习底层原理,不依赖工具包
- 同样必须表单加
enctype="multipart/form-data"