文件上传是 Java Web 的“入门仪式”,它能把你虐得死去活来,也能让你瞬间开窍

今天咱们就从远古时代(Servlet)一路聊到现代文明(SSM/SpringBoot),看看这玩意儿到底进化出了几种姿势。


第一种姿势:Apache Commons FileUpload(远古巨兽级,手动挡开坦克)

年代:2005年左右~至今(老项目还在用,兼容性满分)

核心武器:commons-fileupload + commons-io 两个 jar 包

典型代码(准备好纸巾,这段能把你看哭)

Java

// 1. 创建工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. 创建解析器
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 解析请求(这一步最容易爆内存)
List<FileItem> items = upload.parseRequest(request);

// 4. 手动遍历,一个一个判断是普通表单还是文件
for (FileItem item : items) {
    if (item.isFormField()) {
        // 普通表单字段
        String value = item.getString("UTF-8");
    } else {
        // 文件!终于等到你!
        InputStream in = item.getInputStream();
        FileOutputStream out = new FileOutputStream("/upload/" + item.getName());
        IOUtils.copy(in, out);  // 还得自己拷贝流...
        item.delete(); // 记得删临时文件,不然磁盘炸了
    }
}

优点:能跑!哪儿都能跑!连 Tomcat 5 都能跑! 缺点:代码量感人,还得自己判断是文件还是普通字段,临时文件还得自己删,稍微不注意就 OOM。

评价:这就像手动挡拖拉机,油门离合全靠手,新手十个有九个熄火,剩下一个直接翻车。


第二种姿势:Servlet 3.0+ 原生 Part API(国家终于出手了)

年代:2010年以后(Tomcat 7+ 开始支持)

核心武器:零依赖!只要在 Servlet 上加一个注解就行!

Java

@WebServlet("/upload")
@MultipartConfig(                 // ← 这行注解是灵魂!
    location = "/tmp",
    maxFileSize = 1024*1024*10,   // 单文件最大10M
    maxRequestSize = 1024*1024*50 // 总请求最大50M
)
public class UploadServlet extends HttpServlet {
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
        Part part = request.getPart("file");           // 直接拿!
        String fileName = getSubmittedFileName(part);  // 自己写个工具方法提取文件名
        part.write("/upload/" + fileName);             // 一行存文件!爽!
    }
}

优点

  • 零 jar 包,原生支持
  • 性能最好(官方实现的还能有假?)
  • part.write() 一行存文件,优雅得我哭了

缺点

  • 必须在 Servlet 上加 @MultipartConfig,忘了就寄
  • 获取文件名还得自己写工具方法(浏览器不同实现不一样)
  • 多文件要 request.getParts() 自己遍历

评价:这就像从拖拉机换成了自动挡桑塔纳,虽然车身还是有点硬,但至少不用老踩离合了!


第三种姿势:SpringMVC 的 MultipartFile(现代文明,自动挡豪车)

年代:2012年以后(SSM 项目99%都在用这个)

核心武器:Spring 内置的两种解析器(你根本不用管底层是啥)

最优雅代码(准备尖叫)

Java

@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
    
    if (!file.isEmpty()) {
        file.transferTo(new File("/upload/" + file.getOriginalFilename()));
        // 一行搞定!连流都不用管!
    }
    return "success";
}

// 多文件?更简单!
@PostMapping("/batch")
public String batch(@RequestParam("files") MultipartFile[] files) {
    for (MultipartFile file : files) {
        file.transferTo(...);
    }
}

Spring 还偷偷帮你干了这些事

  • 自动判断是不是 multipart 请求
  • 自动创建临时文件
  • 自动删除临时文件
  • 自动限流限大小(配置文件里写两行就行)
  • SpringBoot 甚至连配置都给你省了!

评价:这就像特斯拉自动驾驶,你只管说“上传”,剩下的它全给你安排得明明白白。 我现在写文件上传就两行代码,领导看了直呼内行。


真相揭秘:其实底层就两种解析器!

很多人以为有三种,其实 SpringMVC 偷偷把前两种都封装了:

Spring 的解析器类底层实际用的是什么时候用
CommonsMultipartResolver第一种(Commons FileUpload)老项目、SpringBoot 1.x 默认
StandardServletMultipartResolver第二种(Servlet 3.0 Part)SpringBoot 2.x+ 默认(推荐!)

所以你写 MultipartFile 的时候,SpringBoot 其实在背后默默用了 Servlet 3.0 的 Part,性能拉满!


2025 年了,你还用哪种?

  • 新项目/SpringBoot:直接 MultipartFile,连想都别想别的!
  • 老项目升级不了:用 Part API,至少别再写 Commons 了
  • 博物馆级古董项目:Commons FileUpload(看到请默哀三秒)

总结(金句送给你们)

“文件上传的最高境界,就是让别人看不出你写了文件上传。”

从 200 行哭着敲,到现在 2 行笑着传。 这,就是 Java Web 的成长!

喜欢记得点赞收藏评论转发。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐