JavaWeb四种文件上传方式(上篇)

文件上传是 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. 总结

  1. 依赖第三方 commons 包,不能脱离依赖单独使用
  2. 代码偏繁琐,需要手动区分普通字段和文件字段
  3. 兼容性老项目,现在新项目很少手写这套
  4. 必须表单指定 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. 总结

  1. 零第三方依赖,仅 Servlet3.0 原生支持
  2. 注解开发:@WebServlet + @MultipartConfig,无需 web.xml
  3. API 简洁:getPart() 直接获取文件
  4. 适合学习底层原理,不依赖工具包
  5. 同样必须表单加 enctype="multipart/form-data"
相关推荐
YikNjy6 分钟前
break和continue
java·开发语言·算法
SomeOtherTime7 分钟前
Geojson相关(AI回答)
java·前端·python
日月云棠19 分钟前
10 Integer —— 最常用的整数包装类深度解析
java·后端
秋923 分钟前
java项目中cpu飙升排查及解决方法
java·开发语言
野生技术架构师24 分钟前
牛客网2026最新大厂Java高频面试题精选(附标准答案)
java·开发语言
PH = 727 分钟前
JAVA的SPI机制
java·开发语言
一 乐28 分钟前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站
weelinking30 分钟前
【产品】11_实现后端接口——数据在背后如何流动
java·人工智能·python·sql·oracle·json·ai编程
摇滚侠37 分钟前
东方通替换tomcat,实战经验
java
IT猿手39 分钟前
多目标优化算法:多目标蛇优化算法(Multiple Objective Snake Optimizer,MOSO)(提供MATLAB代码)
开发语言·算法·matlab·动态路径规划·光伏模型参数估计