从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

  • 主流框架

  • SpringMVC

    • SpringMVC 基本概念
    • SpringMVC 入门案例
    • SpringMVC 中的组件介绍
    • RequestMapping 注解的作用
    • 请求参数的绑定
    • 自定义类型转换器
    • 使用原生的 Servlet-API
    • SpringMVC 常用注解
    • 响应数据和结果视图
    • 文件上传
      • 文件上传的必要前提
      • 文件上传的原理分析
      • 借助第三方组件实现文件上传
      • SpringMVC 实现文件上传
      • 源码
    • 文件上传之跨服务器
    • SpringMVC 的异常处理
    • SpringMVC 的拦截器
    • SSM 整合
  • SpringBoot

  • Java
  • SpringMVC
2023-05-15
目录

文件上传

# 90.文件上传

下面我们来实现一个非常常用的功能:文件上传

# 文件上传的必要前提

  1. form 表单的 enctype 取值必须是:multipart/form-data,enctype: 是表单请求正文的类型,默认值是: application/x-www-form-urlencoded
  2. method 属性取值必须是 Post
  3. 提供一个文件选择域 ‍

# 文件上传的原理分析

当 form 表单的 enctype 取值为默认值,也就是 enctype=application/x-www-form-urlencoded 时,form 表单的正文内容是一组键值对:key = value&key = value&key = value

当 form 表单的 enctype 取值为 Mutilpart/form-data,不是默认值时,request.getParameter() 将失效,请求正文内容就变成:

-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file"; 
filename="C:\Users\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--
1
2
3
4
5
6
7
8
9

每一部分都是 MIME 类型描述的正文。此时我们得自己去解析这个正文内容。

# 借助第三方组件实现文件上传

我们可以用第三方工具帮我们解析,使用 Apache 提供的 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和 commons-io。该工具也是用的很多的

commons-io 不属于文件上传组件的开发 jar 文件,但 Commons-fileupload 组件从 1.1 版本开始,工作时需要 commons-io 包的支持。 ‍

# 搭建环境

为了不收之前的文件影响,我们删除所有的 JSP 页面 和 所有的 Java 代码,而配置文件我们可以留着不动

新建 JSP:我们重新新建一个 index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h3>文件上传</h3>
    </body>
</html>
1
2
3
4
5
6
7
8
9

‍ 新建 controller

package com.peterjxl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/fileUpload1")
    public String fileUpload1() {
        System.out.println("fileUpload1");
        return "success";
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

‍ 新建 success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h3>上传文件成功</h3>
    </body>
</html>
1
2
3
4
5
6
7
8
9

# 新建表单

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h3>文件上传</h3>
        <form action="/user/fileUpload1" method="post" enctype="multipart/form-data">
            选择文件:<input type="file" name="upload"/> <br/>
            <input type="submit" value="上传"/>
        </form>
    </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 借住 fileupload 组件实现上传

我们引用依赖:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11

‍ 前端提交的东西,最后都会封装到 request 中,所以我们首先使用 Servlet 原生的 API:

public String fileUpload1(HttpServletRequest request) 
1

然后我们定义文件上传后,要存放的文件夹是否存在,不存在则创建(这里以 upload 文件夹为例)

String realPath = request.getSession().getServletContext().getRealPath("/uploads/");

// 判断路径是否存在
File file = new File(realPath);
if (! file.exists()) {
    // 创建该文件夹
    file.mkdirs();
}
1
2
3
4
5
6
7
8

‍ 下一步就是解析 request 对象,获取到上传的文件,然后写入到磁盘里了,具体代码如下:

 // 解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);

// 解析request
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items){
    // 进行判断,当前item对象是否是上传文件项,如果不是则说明是表单内容
    if (item.isFormField()){
        // 是表单项
    }else {
        // 是上传文件项
        // 获取上传文件的名称
        String name = item.getName();
        // 完成文件上传
        item.write(new File(realPath, name));
        // 删除临时文件。当文件小于10kb,则文件是在内存中的;如果大于10kb,会有一个临时文件。
        item.delete();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

‍ 我们重启并测试,可以看到上传文件后,能在项目的路径里找到该文件。关于该文件具体的路径,是以部署后的为准,每个人的路径可能不一样,可以看看 IDE 里的配置。

‍

# 生成唯一的文件名

有时候我们可能会上传同名的文件,为了不覆盖,可以生成唯一的文件名,例如使用 UUID:

String name = item.getName();
String uuid = UUID.randomUUID().toString().replace("-", "");// 防止文件名重复
name = uuid + "_" + name;
item.write(new File(realPath, name));
1
2
3
4

‍

# SpringMVC 实现文件上传

接下来我们演示下如何使用 SpringMVC 上传文件。比起传统的方式,SpringMVC 实现起来更简单 ‍

# 原理

SpringMVC 框架提供了 MultipartFile 对象,该对象表示上传的文件,要求变量名称必须和表单 file 标签的 name 属性名称相同 ‍ 当我们上传文件时,request 对象首先会交给前端控制器:

‍

而 SpringMVC 是有很多组件的,其中有一个是文件解析器,当我们配置后,前端控制器就会去找该组件,负责解析 request 请求,然后拿到上传的文件项

‍

然后我们继续执行 controller 的方法,假设我们新增一个方法 fileupload2,然后我们可以通过参数绑定的方式,传入到该方法中。传入的是一个 MultipartFile 对象:

‍

注意点:要求变量名称必须和表单 file 标签的 name 属性名称相同。

# 配置文件解析器

CommonsMultipartResolver 还允许我们做一些配置:

  • maxUploadSize:上传的最大文件大小,字节为单位。例如限制为 10M,则 10 * 1024 * 1024 = 10485760 ‍ 我们在 springmvc.xml 中配置:
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/>
</bean>
1
2
3
4
5

‍

# 新增方法

@RequestMapping("/fileUpload2")
public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws IOException {

    System.out.println("fileUpload2");


    String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
    System.out.println("realPath: " + realPath);
    File file = new File(realPath);
    if (! file.exists()) {
        // 创建该文件夹
        file.mkdirs();
    }


    String originalFilename = upload.getOriginalFilename();
    String uuid = UUID.randomUUID().toString().replace("-", "");// 防止文件名重复,这里我们将减号替换为空字符串
    originalFilename = uuid + "_" + originalFilename;
    upload.transferTo(new File(realPath, originalFilename));
    return "success";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

‍ 注意方法中 MultipartFile 的参数名,必须和表单中的 file 属性名字一样,这里是 upload。最后我们也不用删除临时文件,SpringMVC 会帮我们删除

# 新增表单

‍

<h3>SpringMVC文件上传</h3>

<form action="/user/fileUpload2" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"/> <br/>
    <input type="submit" value="上传"/>
</form>
1
2
3
4
5
6

# 源码

本项目已将源码上传到 GitHub (opens new window) 和 Gitee (opens new window) 上。并且创建了分支 demo8,读者可以通过切换分支来查看本文的示例代码。 ‍

上次更新: 2025/5/17 12:26:09
响应数据和结果视图
文件上传之跨服务器

← 响应数据和结果视图 文件上传之跨服务器→

最近更新
01
学点统计学:轻松识破一本正经的胡说八道
06-05
02
2025 年 5 月记
05-31
03
《贫穷的本质》很棒,但可能不适合你
05-27
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式