【SpringMVC从入门到实战教程】第四章 SpringMVC 上传与下载

四、SpringMVC 上传与下载

    文件上传:本质就是通过IO实现文件的复制,将本地文件复制到服务器端。
    
    文件下载:本质就是通过IO实现文件的复制,将服务器端文件复制到本地。
    
    Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

4.1 导入文件上传jar包

方式一:引入jar包

 方式二: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>

4.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">
        <!-- 文件上传的属性设置 -->
        <!-- 设置上传文件的大小: 文件的总字节数 -->
        <!-- 
 			1KB = 1024B
			1MB = 1024KB
			1GB = 1024MB
			1TB = 1024GB
			...
		-->
        <property name="maxUploadSize" value="104857600"/>
        <!-- 设置上传的字符编码 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 设置缓存大小 -->
        <property name="maxInMemorySize" value="10240"/>
    </bean>
</beans>

4.3 单文件上传

4.3.1 页面

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.3.2 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);

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

MultipartFile类中常用方法如下:

方法 作用
getOriginalFilename() 获取上传文件的原名
getSize() 获取文件的字节大小,单位byte
transferTo(File dest) 通过i/o流,将文件存放到指定位置
getName() 获取表单中文件组件的名字
getContentType() 获取文件MIME类型
getInputStream() 获取文件流
isEmpty() 是否为空

处理上传文件:

  • 文件的保存目录

    • 第一种:当前项目目录下(不是工作空间中,而是项目发布后的目录)。 优点:属于项目内部资源,方便访问; 问题:文件在项目中,如果文件数据量大,不利于项目迁移;

    • 第二种:服务器的文件系统中的目录。 优点:项目资源与上传文件分离; 问题:无法直接访问,需要配置虚拟目录,或搭建文件服务器;

  • 防止文件名称重复。

    • 使用新建目录,分开存放文件;

    • 使用UUID来生成新的文件名称;

4.4 批量上传

uploads.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";
}

4.5 下载

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();
    }
}

4.6 加载资源

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="c:/upload/a.jpg"></p>
			错误写法
		-->
        <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>

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

4.6.1 在Eclipse中配置

1、双击服务列表中的tomcat;

 2、打开tomcat配置的Modules;

 3、在Web Modules中配置虚拟路径;

4.6.2 在IDEA中配置

1、在菜单栏找到Run菜单,选择其中的Edit Configurations;

 2、选择Deployment选项卡,点击加号,选择External Source;

 3、选择虚拟路径对应的物理目录;

 4、在Application context中配置虚拟路径;

4.6.3 在tomcat中配置

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

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

猜你喜欢

转载自blog.csdn.net/ligonglanyuan/article/details/125167791