上一篇
在Java中实现文件上传通常使用Servlet的
Part接口或第三方库如Apache Commons FileUpload处理HTTP请求流;下载文件则通过设置响应头
Content-Disposition并读取文件流写入响应输出流完成,核心步骤包括解析请求、读写文件流和异常处理。
在Web应用中,文件上传与下载是高频需求,本文详细讲解Java实现方案,涵盖核心API、安全实践及完整代码示例,帮助开发者构建健壮的文件传输功能。
环境准备
- 基础环境:JDK 8+、Servlet 3.0+(支持
Part接口)、Tomcat 9+ - 可选库:Apache Commons FileUpload(传统表单上传)
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency>
文件上传实现
方案1:Servlet API原生实现(推荐)
@WebServlet("/upload")
@MultipartConfig(maxFileSize = 1024 * 1024 * 10) // 限制10MB
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
try {
Part filePart = request.getPart("file"); // "file"为表单字段名
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
InputStream fileContent = filePart.getInputStream();
// 存储到服务器(示例路径)
Files.copy(fileContent, Paths.get("/uploads/" + fileName));
response.getWriter().print("上传成功: " + fileName);
} catch (Exception e) {
response.sendError(500, "上传失败: " + e.getMessage());
}
}
}
关键参数说明:
@MultipartConfig:配置上传限制maxFileSize:单文件最大字节数maxRequestSize:总请求最大字节数location:临时存储目录
方案2:Apache Commons FileUpload(兼容旧版)
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setSizeMax(10 * 1024 * 1024); // 10MB限制
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) { // 跳过普通表单字段
String fileName = new File(item.getName()).getName();
File storeFile = new File("/uploads/" + fileName);
item.write(storeFile); // 保存文件
}
}
文件下载实现
@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String fileName = request.getParameter("filename");
Path filePath = Paths.get("/uploads/", fileName);
try (InputStream in = Files.newInputStream(filePath);
OutputStream out = response.getOutputStream()) {
// 设置响应头
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename="" + fileName + """);
// 流复制
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
response.sendError(404, "文件不存在");
}
}
}
响应头解析:

Content-Type: application/octet-stream:强制浏览器下载Content-Disposition: attachment:指定默认文件名
安全实践
-
文件类型校验
使用文件头(Magic Number)而非扩展名:byte[] header = Files.readAllBytes(filePath); if (!Arrays.equals(header, 0, 4, new byte[]{0x25, 0x50, 0x44, 0x46}, 0, 4)) { // PDF示例 throw new SecurityException("非规文件类型"); } -
路径安全

- 使用
Paths.get("/safe_dir/", fileName).normalize()防止路径遍历攻击 - 禁止用户自定义存储路径
- 使用
-
大小限制
- 服务端双重校验:前端表单限制 + 后端
@MultipartConfig或setSizeMax()
- 服务端双重校验:前端表单限制 + 后端
-
重命名策略

String safeName = UUID.randomUUID() + "_" + fileName; // 避免文件名冲突
前端表单示例
<!-- 上传表单 -->
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" accept=".pdf,.jpg,.png"> <!-- 前端过滤 -->
<button type="submit">上传</button>
</form>
<!-- 下载链接 -->
<a href="/download?filename=report.pdf">下载报告</a>
- 上传:优先使用Servlet 3.0+的
Part接口,简洁高效 - 下载:重点控制响应头与流复制
- 安全:类型校验、路径规范、大小限制缺一不可
- 扩展建议:
- 大文件上传:分片传输(如Dropzone.js + 后台合并)
- 云存储:集成AWS S3或阿里云OSS SDK
引用说明:
- Servlet 3.0规范:Oracle官方文档
- Apache Commons FileUpload:Apache 2.0协议开源库
- 安全实践参考:OWASP文件上传防护指南
