四、上传与下载

1. 导入文件上传jar包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5fpDJsJ3-1619746061969)(images/mvc_upload_jar.jpg)]

maven依赖配置

<dependencies>
    <!-- spring核心包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springbean包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springcontext包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring表达式包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAOP包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAspects包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring对web的支持 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springwebMVC -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>

    <!-- 配置javaweb环境 -->
    <!-- servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- jstl -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- 上传组件包 -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
</dependencies>

2. 配置

  • SpringMVC为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的
  • SpringMVC用Commons FileUpload技术实现了一个实现类:CommonsMultipartResovler
  • SpringMVC中默认没有装配MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用需要配置CommonsMultipartResovler
<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- springmvc的注解式开发 -->
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.newcapec.controller"/>

    <!-- MVC注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 配置文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 文件上传的属性设置 -->
        <!-- 设置上传文件的大小: 文件的总字节数 -->
        <property name="maxUploadSize" value="104857600"/>
        <!-- 设置上传的字符编码 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 设置缓存大小 -->
        <property name="maxInMemorySize" value="10240"/>
    </bean>
</beans>

3. 页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center;">
        <h1>首页</h1>
        <p><a href="views/upload.jsp">文件上传</a></p>
        <p><a href="views/uploads.jsp">批量上传</a></p>
        <p><a href="views/show.jsp">文件展示</a></p>
        <p><a href="views/download.jsp">文件下载</a></p>
    </div>
</body>
</html>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center;">
        <h1>上传成功!!!</h1>
    </div>
</body>
</html>

upload.jsp

  • form表单提交类型改为enctype=“multipart/form-data”
  • 提交方式为post请求,method=“post”
  • 在表单中添加type="file"的input表单元素,用来选择需要上传的文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>文件上传</h1>
        <!--
        在前端或页面中需要注意的:
        1.文件上传时提交的请求方法必须为post
        2.在form标签中enctype
        enctype="application/x-www-form-urlencoded"为默认值:将数据转换为key/value格式,用于普通数据的提交
        上传时需要修改enctype为enctype="multipart/form-data": 告知服务器请求中包含二进制的数据(文件)
        3.使用上传组件(上传表单元素) <input type="file">
        -->
        <form action="upload.do" method="post" enctype="multipart/form-data">
            <p>请选择文件:<input type="file" name="file"></p>
            <p><button>上传</button></p>
        </form>
    </div>
</body>
</html>

4. Controller

在Controller的方法中添加MultipartFile类型的参数,用来接收上传文件

@Controller
public class UploadController {

    /**
     * 文件上传: 将本地文件传输至服务端
     * 在springmvc中通过MultipartFile对象来接收上传的文件
     * MultipartFile对象就是通过文件上传解析器创建的
     */
    @RequestMapping("/upload.do")
    public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
        /**
         * 处理上传文件:
         * 1.获取文件的基本信息
         * 2.指定文件的保存目录
         * 3.防止文件名称重复
         * 4.复制文件
         */
        //获取文件大小
        long fileSize = file.getSize();
        //获取文件名称
        String fileName = file.getOriginalFilename();
        System.out.println(fileSize);
        System.out.println(fileName);

        /**
         * 2.指定文件的保存目录
         * 第一种:当前项目目录下(不是工作空间中,而是项目发布后的目录)
         *      优点:属于项目内部资源,方便访问
         *      问题:文件在项目中,如果文件数据量大,不利于项目迁移
         * 第二种:服务器的文件系统中的目录
         *      优点:项目资源与上传文件分离
         *      问题:无法直接访问,需要配置虚拟目录,或搭建文件服务器
         */
        String rootPath = request.getServletContext().getRealPath("/upload");
//        String rootPath = "c:/upload";
        /**
         * 3.防止文件名称重复
         * 使用新建目录,分开存放文件
         * 使用UUID来生成新的文件名称
         */
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy");
        SimpleDateFormat sdf2 = new SimpleDateFormat("MM");
        Date today = new Date();
        String year = sdf1.format(today);
        String month = sdf2.format(today);

        File dir = new File(rootPath + "/" + year + "/" + month);
        if(!dir.exists()){
            dir.mkdirs();
        }

        String newName = UUID.randomUUID().toString().replace("-","") +
                            fileName.substring(fileName.lastIndexOf("."));

        //目标文件
        File resultFile = new File(dir.getAbsolutePath() + "/" + newName);

        //文件传输
        file.transferTo(resultFile);
        System.out.println("文件上传成功...");
        return "success";
    }
}

MultipartFile类中常用方法如下:

方法

作用

getOriginalFilename()

获取上传文件的原名

getSize()

获取文件的字节大小,单位byte

transferTo(File dest)

通过i/o流,将文件存放到指定位置

getName()

获取表单中文件组件的名字

getContentType()

获取文件MIME类型

getInputStream()

获取文件流

isEmpty()

是否为空

处理上传文件:

  • 文件的保存目录
  • 第一种:当前项目目录下(不是工作空间中,而是项目发布后的目录)
    优点:属于项目内部资源,方便访问
    问题:文件在项目中,如果文件数据量大,不利于项目迁移
  • 第二种:服务器的文件系统中的目录
    优点:项目资源与上传文件分离
    问题:无法直接访问,需要配置虚拟目录,或搭建文件服务器
  • 防止文件名称重复
  • 使用新建目录,分开存放文件
  • 使用UUID来生成新的文件名称

5. 批量上传

upload.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>批量上传</h1>
        <form action="uploadBatch.do" method="post" enctype="multipart/form-data">
            <p>请选择文件1:<input type="file" name="file"></p>
            <p>请选择文件2:<input type="file" name="file"></p>
            <p>请选择文件3:<input type="file" name="file"></p>
            <p><button>上传</button></p>
        </form>
    </div>
</body>
</html>

接收上传文件的参数为MultipartFile类型的数组即可

/**
  * 批量上传
  * 将MultipartFile对象定义为数组类型
  */
@RequestMapping("/uploadBatch.do")
public String uploadBatch(MultipartFile[] file) throws IOException {
    for (MultipartFile multipartFile : file) {
        multipartFile.transferTo(new File("c:/upload/" +  multipartFile.getOriginalFilename()));
    }
    System.out.println("批量上传成功...");
    return "success";
}

6. 下载

download.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <a href="download.do?name=a.jpg">图片1</a>
        <a href="download.do?name=b.jpg">图片2</a>
        <a href="download.do?name=c.jpg">图片3</a>
        <a href="download.do?name=中文.txt">文件</a>
    </div>
</body>
</html>

设置响应头即可

@Controller
public class DownloadController {

    /**
     * 文件下载:将服务端的文件传输至客户端
     * 页面无需跳转,需要设置下载响应头
     */
    @RequestMapping("/download.do")
    public void download(String name, HttpServletResponse response) throws Exception {
        /**
         * 设置下载响应头
         * 1.content-disposition对应的值为attachment
         * 告知浏览器客户端,响应为回传文件(附件)
         * 2.设置下载时文件名称
         * "attachment;fileName="+name
         * 3.文件名称中文处理
         * 使用URLEncoder对象进行转码
         */
//        response.addHeader("content-disposition", "attachment");
//        response.addHeader("content-disposition", "attachment;fileName="+name);
        String filename = URLEncoder.encode(name,"UTF-8");
        response.addHeader("content-disposition", "attachment;fileName="+filename);

        //通过流进行文件传输
        FileInputStream inputStream = new FileInputStream("c:/upload/" + name);
        OutputStream outputStream = response.getOutputStream();
        byte[] buffer = new byte[1024];
        while(inputStream.read(buffer) != -1) {
            outputStream.write(buffer);
        }
        outputStream.flush();
        inputStream.close();
        outputStream.close();
    }
}

7. 加载资源

show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center;">
        <h1>图片展示</h1>
        <p><img src="upload/a.jpg"></p>
        <p><img src="/up/a.jpg"></p>
        <p><img src="/up/b.jpg"></p>
        <p><img src="/up/c.jpg"></p>
    </div>
</body>
</html>

在页面中无法访问物理目录(硬盘中的真实目录),所以需要在服务器中配置相对应的虚拟目录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6odaeWeA-1619746061973)(images/mvc_img.jpg)]

在eclipse中配置

  1. 双击服务列表中的tomcat
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aO36YAVA-1619746061975)(images/mvc_eclipse_servers.jpg)]
  2. 打开tomcat配置的Modules
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FjRHjRfF-1619746061984)(images/mvc_eclipse_tomcat.jpg)]
  3. 在Web Modules中配置虚拟路径
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yAhRcOrS-1619746061986)(images/mvc_eclipse_modules.jpg)]

在idea中配置

  1. 在菜单栏找到Run菜单,选择其中的Edit Configurations…
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGTD8UP8-1619746061987)(images/mvc_idea_run.jpg)]
  2. 选择Deployment选项卡,点击加号,选择External Source…
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9nqj38H-1619746061991)(images/mvc_idea_tomcat.jpg)]
  3. 选择虚拟路径对应的物理目录
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3l8GRV4y-1619746061993)(images/mvc_idea_dir.jpg)]
  4. 在Application context中配置虚拟路径
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0bZU9r5D-1619746061994)(images/mvc_idea_context.jpg)]

在tomcat中配置

在配置目录conf的server.xml文件中找到<Host>标签,在其中添加如下代码即可。docBase为物理目录,path为虚拟路径

<Context docBase="c:\upload" path="/up" reloadable="true"/>