zoukankan      html  css  js  c++  java
  • Spring MVC-------文件上传,单文件,多文件,文件下载

    Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过 Spring MVC 框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

    commons-fileupload组件

    由于 Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,因此需要将 commons-fileupload 组件相关的 JAR(commons-fileupload-1.3.1.jar 和 commons-io-2.4.jar)复制到 Spring MVC 应用的 WEB-INF/lib 目录下。下面讲解如何下载相关 JAR 包。

    Commons 是 Apache 开放源代码组织中的一个 Java 子项目,该项目包括文件上传、命令行处理、数据库连接池、XML 配置文件处理等模块。fileupload 就是其中用来处理基于表单的文件上传的子项目,commons-fileupload 组件性能优良,并支持任意大小文件的上传。

    commons-fileupload 组件可以从“http://commons.apache.org/proper/commons-fileupload/”下载,本教程采用的版本是 1.2.2。下载它的 Binares 压缩包(commons-fileupload-1.3.1-bin.zip),解压缩后的目录中有两个子目录,分别是 lib 和 site。

    在 lib 目录下有一个 JAR 文件——commons-fileupload-1.3.1.jar,该文件是 commons-fileupload 组件的类库。在 site 目录中是 commons-fileupload 组件的文档,也包括 API 文档。

    commons-fileupload 组件依赖于 Apache 的另外一个项目——commons-io,该组件可以从“http://commons.apache.org/proper/commons-io/”下载,本教程采用的版本是 2.4。下载它的 Binaries 压缩包(commons-io-2.4-bin.zip),解压缩后的目录中有 4 个 JAR 文件,其中有一个 commons-io-2.4.jar 文件,该文件是 commons-io 的类库。

    基于表单的文件上传

    标签 <input type="file"/> 会在浏览器中显示一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件。

    文件上传的表单例子如下:

    <form method="post" action="upload" enctype="multipart/form-data">
        <input type="file" name="myfile"/>
    </form>

    对于基于表单的文件上传,不要忘记使用 enctype 属性,并将它的值设置为 multipart/form-data,同时将表单的提交方式设置为 post。为什么要这样呢?下面从 enctype 属性说起。

    表单的 enctype 属性指定的是表单数据的编码方式,该属性有以下 3 个值。

    • application/x-www-form-urlencoded:这是默认的编码方式,它只处理表单域里的 value 属性值。
    • multipart/form-data:该编码方式以二进制流的方式来处理表单数据,并将文件域指定文件的内容封装到请求参数里。
    • text/plain:该编码方式只有当表单的 action 属性为“mailto:”URL 的形式时才使用,主要适用于直接通过表单发送邮件的方式。


    由上面 3 个属性的解释可知,在基于表单上传文件时 enctype 的属性值应为 multipart/form-data。

    MultipartFile接口

    在 Spring MVC 框架中上传文件时将文件相关信息及操作封装到 MultipartFile 对象中,因此开发者只需要使用 MultipartFile 类型声明模型类的一个属性即可对被上传文件进行操作。该接口具有如下方法。

    名称作用
    byte[] getBytes() 以字节数组的形式返回文件的内容
    String getContentType() 返回文件的内容类型
    InputStream getInputStream() 返回一个InputStream,从中读取文件的内容
    String getName() 返回请求参数的名称
    String getOriginalFillename() 返回客户端提交的原始文件名称
    long getSize() 返回文件的大小,单位为字节
    boolean isEmpty() 判断被上传文件是否为空
    void transferTo(File destination) 将上传文件保存到目标目录下


    在上传文件时需要在配置文件中使用 Spring 的 org.springframework.web.multipart.commons.CommonsMultipartResolver 类配置 MultipartResolver 用于文件上传。

    Spring MVC单文件上传

    1)创建应用并导入 JAR 包

    创建应用 springMVCDemo11,将 Spring MVC 相关的 JAR 包、commons-fileupload 组件相关的 JAR 包以及 JSTL 相关的 JAR 包导入应用的 lib 目录中,如图 1 所示。

    springMVCDemo11应用的JAR包
    图 1  springMVCDemo11


    2)创建 web.xml 文件

    在 WEB-INF 目录下创建 web.xml 文件。为防止中文乱码,需要在 web.xml 文件中添加字符编码过滤器,这里不再赘述。

    3)创建文件选择页面

    在 WebContent 目录下创建 JSP 页面 oneFile.jsp,在该页面中使用表单上传单个文件,具体代码如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    <form action="${pageContext.request.contextPath }/onefile"
    method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="myfile"><br>
    文件描述:<input type="text" name="description"><br>
    <input type="submit" value="提交">
    </form>
    </body>
    </html>

    4)创建 POJO 类

    在 src 目录下创建 pojo 包,在该包中创建 POJO 类 FileDomain。然后在该 POJO 类中声明一个 MultipartFile 类型的属性封装被上传的文件信息,属性名与文件选择页面 oneFile.jsp 中的 file 类型的表单参数名 myfile 相同。具体代码如下:

    package pojo;
    import org.springframework.web.multipart.MultipartFile;
    public class FileDomain {
    private String description;
    private MultipartFile myfile;
    
    public String getDescription() {
    return description;
    }
    
    public void setDescription(String description) {
    this.description = description;
    }
    
    public MultipartFile getMyfile() {
    return myfile;
    }
    
    public void setMyfile(MultipartFile myfile) {
    this.myfile = myfile;
    }
    }

    5)创建控制器类

    在 src 目录下创建 controller 包,并在该包中创建 FileUploadController 控制器类。具体代码如下:

    package controller;
    
    import java.io.File;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import pojo.FileDomain;
    
    @Controller
    public class FileUploadController {
    // 得到一个用来记录日志的对象,这样在打印信息时能够标记打印的是哪个类的信息
    private static final Log logger = LogFactory.getLog(FileUploadController.class);
    /**
    * 单文件上传
    */
    @RequestMapping("/onefile")
    public String oneFileUpload(@ModelAttribute FileDomain fileDomain,
    HttpServletRequest request) {
    /*
    * 文件上传到服务器的位置“/uploadfiles”,该位置是指
    * workspace.metadata.pluginsorg.eclipse
    * .wst.server.core	mp0wtpwebapps, 发布后使用
    */
    String realpath = request.getServletContext()
    .getRealPath("uploadfiles");
    String fileName = fileDomain.getMyfile().getOriginalFilename();
    File targetFile = new File(realpath, fileName);
    if (!targetFile.exists()) {
    targetFile.mkdirs();
    }
    // 上传
    try {
    fileDomain.getMyfile().transferTo(targetFile);
    logger.info("成功");
    } catch (Exception e) {
    e.printStackTrace();
    }
    return "showOne";
    }
    }

    6)创建 Spring MVC 的配置文件

    在上传文件时需要在配置文件中使用 Spring 的 CommonsMultipartResolver 类配置 MultipartResolver 用于文件上传,应用的配置文件 springmvc-servlet.xml 的代码如下:

    <?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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 使用扫描机制扫描包 -->
    <context:component-scan base-package="controller" />
    <!-- 完成视图的对应 -->
    <!-- 对转向页面的路径解析。prefix:前缀, suffix:后缀 -->
    <bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    </bean>
    
    <!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
    <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="5000000" />
    <property name="defaultEncoding" value="UTF-8" />
    </bean>
    </beans>

    7)创建成功显示页面

    在 WEB-INF 目录下创建 JSP 文件夹,并在该文件夹中创建单文件上传成功显示页面 showOne.jsp。具体代码如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    ${fileDomain.description }
    <br>
    <!-- fileDomain.getMyFile().getOriginalFilename()-->
    ${fileDomain.myfile.originalFilename }
    </body>
    </html>

      

    8)测试文件上传

    发布 springMVCDemo11 应用到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo11/oneFile.jsp”运行文件选择页面,运行结果如图 2 所示。

    单文件选择页面
                    图 2  单文件选择页面


    在图 2 中选择文件并输入文件描述,然后单击“提交”按钮上传文件,若成功则显示如图 3 所示的结果。

    单文件成功上传结果
                    图 3  单文件成功上传结果
     

    Spring MVC多文件上传

    1)创建多文件选择页面

    在 WebContent 目录下创建 JSP 页面 multiFiles.jsp,在该页面中使用表单上传多个文件,具体代码如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath }/multifile"
            method="post" enctype="multipart/form-data">
            选择文件1:<input type="file" name="myfile"><br>
            文件描述1:<input type="text" name="description"><br />
            选择文件2:<input type="file" name="myfile"><br>
            文件描述2:<input type="text" name="description"><br />
            选择文件3:<input type="file" name="myfile"><br>
            文件描述3:<input type="text" name="description"><br />
            <input type="submit" value="提交">
        </form>
    </body>
    </html>

    2)创建 POJO 类

    在上传多文件时需要 POJO 类 MultiFileDomain 封装文件信息,MultiFileDomain 类的具体代码如下:

    package pojo;
    import java.util.List;
    import org.springframework.web.multipart.MultipartFile;
    public class MultiFileDomain {
        private List<String> description;
        private List<MultipartFile> myFile;
        // 省略setter和getter方法
    }

    3)添加多文件上传处理方法

    在控制器类 FileUploadController 中添加多文件上传的处理方法 multiFileUpload,具体代码如下:

    /**
    * 多文件上传
    */
    @RequestMapping("/multifile")
    public String multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain,HttpServletRequest request) {
        String realpath = request.getServletContext().getRealPath("uploadfiles");
        File targetDir = new File(realpath);
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }
        List<MultipartFile> files = multiFileDomain.getMyFile();
        for (int i = 0; i < files.size(); i++) {
            MultipartFile file = files.get(i);
            String fileName = file.getOriginalFilename();
            File targetFile = new File(realpath, fileName);
            // 上传
            try {
                file.transferTo(targetFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        logger.info("成功");
        return "showMulti";
    }

    4)创建成功显示页面

    在 JSP 文件夹中创建多文件上传成功显示页面 showMulti.jsp,具体代码如下:
     
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <table>
            <tr>
                <td>详情</td>
                <td>文件名</td>
            </tr>
            <!-- 同时取两个数组的元素 -->
            <c:forEach items="${multiFileDomain.description}" var="description"
                varStatus="loop">
                <tr>
                    <td>${description}</td>
                    <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td>
                </tr>
            </c:forEach>
            <!-- fileDomain.getMyfile().getOriginalFilename() -->
        </table>
    </body>
    </html>

    5)测试文件上传

    发布 springMVCDemo11 应用到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo11/multiFiles.jsp”运行多文件选择页面,运行结果如图 1 所示。

    多文件选择页面
                    图 1  多文件选择页面


    在图 1 中选择文件并输入文件描述,然后单击“提交”按钮上传多个文件,若成功则显示如图 2 所示的结果。

    多文件成功上传结果
                    图 2  多文件成功上传结果  
     
     

    Spring MVC文件下载

    文件下载的实现方法

    实现文件下载有以下两种方法:

    • 通过超链接实现下载。
    • 利用程序编码实现下载。


    通过超链接实现下载固然简单,但暴露了下载文件的真实位置,并且只能下载存放在 Web 应用程序所在的目录下的文件。

    利用程序编码实现下载可以增加安全访问控制,还可以从任意位置提供下载的数据,可以将文件存放到 Web 应用程序以外的目录中,也可以将文件保存到数据库中。

    利用程序实现下载需要设置两个报头:

    1)Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为 application/x-msdownload。

    2)Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。

    该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

    设置报头的示例如下:

    response.setHeader("Content-Type", "application/x-msdownload");
    response.setHeader("Content-Disposition", "attachment;filename="+filename);

    文件下载的过程

    下面继续通过 springMVCDemo11 应用讲述利用程序实现下载的过程,要求从《Spring MVC单文件上传》上传文件的目录(workspace.metadata.pluginsorg.eclipse.wst.server.core mp0wtpwebappsspringMVCDemo11uploadfiles)中下载文件,具体开发步骤如下:

    1)编写控制器类

    首先编写控制器类 FileDownController,在该类中有 3 个方法,即 show、down 和 toUTF8String。其中,show 方法获取被下载的文件名称;down 方法执行下载功能;toUTF8String 方法是下载保存时中文文件名的字符编码转换方法。

    FileDownController 类的代码如下:

    package controller;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.UnsupportedEncodingException;
    import java.util.ArrayList;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    @Controller
    public class FileDownController {
        // 得到一个用来记录日志的对象,在打印时标记打印的是哪个类的信息
        private static final Log logger = LogFactory
                .getLog(FileDownController.class);
        /**
         * 显示要下载的文件
         */
        @RequestMapping("showDownFiles")
        public String show(HttpServletRequest request, Model model) {
            // 从 workspace.metadata.pluginsorg.eclipse.wst.server.core
            // tmp0wtpwebappsspringMVCDemo11下载
            String realpath = request.getServletContext()
                    .getRealPath("uploadfiles");
            File dir = new File(realpath);
            File files[] = dir.listFiles();
            // 获取该目录下的所有文件名
            ArrayList<String> fileName = new ArrayList<String>();
            for (int i = 0; i < files.length; i++) {
                fileName.add(files[i].getName());
            }
            model.addAttribute("files", fileName);
            return "showDownFiles";
        }
        /**
         * 执行下载
         */
        @RequestMapping("down")
        public String down(@RequestParam String filename,
                HttpServletRequest request, HttpServletResponse response) {
            String aFilePath = null; // 要下载的文件路径
            FileInputStream in = null; // 输入流
            ServletOutputStream out = null; // 输出流
            try {
                // 从workspace.metadata.pluginsorg.eclipse.wst.server.core
                // tmp0wtpwebapps下载
                aFilePath = request.getServletContext().getRealPath("uploadfiles");
                // 设置下载文件使用的报头
                response.setHeader("Content-Type", "application/x-msdownload");
                response.setHeader("Content-Disposition", "attachment; filename="
                        + toUTF8String(filename));
                // 读入文件
                in = new FileInputStream(aFilePath + "\" + filename);
                // 得到响应对象的输出流,用于向客户端输出二进制数据
                out = response.getOutputStream();
                out.flush();
                int aRead = 0;
                byte b[] = new byte[1024];
                while ((aRead = in.read(b)) != -1 & in != null) {
                    out.write(b, 0, aRead);
                }
                out.flush();
                in.close();
                out.close();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            logger.info("下载成功");
            return null;
        }
        /**
         * 下载保存时中文文件名的字符编码转换方法
         */
        public String toUTF8String(String str) {
            StringBuffer sb = new StringBuffer();
            int len = str.length();
            for (int i = 0; i < len; i++) {
                // 取出字符中的每个字符
                char c = str.charAt(i);
                // Unicode码值为0~255时,不做处理
                if (c >= 0 && c <= 255) {
                    sb.append(c);
                } else { // 转换 UTF-8 编码
                    byte b[];
                    try {
                        b = Character.toString(c).getBytes("UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        b = null;
                    }
                    // 转换为%HH的字符串形式
                    for (int j = 0; j < b.length; j++) {
                        int k = b[j];
                        if (k < 0) {
                            k &= 255;
                        }
                        sb.append("%" + Integer.toHexString(k).toUpperCase());
                    }
                }
            }
            return sb.toString();
        }
    }

    2)创建文件列表页面

    下载文件示例需要一个显示被下载文件的 JSP 页面 showDownFiles.jsp,代码如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        <table>
            <tr>
                <td>被下载的文件名</td>
            </tr>
            <!--遍历 model中的 files-->
            <c:forEach items="${files}" var="filename">
                <tr>
                    <td>
                        <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
                    </td>
                </tr>
            </c:forEach>
        </table>
    </body>
    </html>

    3)测试下载功能

    发布 springMVCDemo11 应用到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo11/showDownFiles”测试下载示例,运行结果如图 1 所示。

    被下载文件列表页面
                      图 1  被下载文件列表页面
     
  • 相关阅读:
    jQuery 删除元素
    jQuery 添加元素
    jQuery 捕获
    jQuery 链
    jQuery Callback
    jQuery 停止动画
    jQuery 动画
    jQuery 滑动
    jQuery 淡入淡出
    SP2010开发和VS2010专家"食谱"--第七章节--使用客户端对象模型
  • 原文地址:https://www.cnblogs.com/lowerma/p/11836780.html
Copyright © 2011-2022 走看看