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\.plugins\org.eclipse
* .wst.server.core\tmp0\wtpwebapps, 发布后使用
*/
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\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\springMVCDemo11\uploadfiles)中下载文件,具体开发步骤如下:

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\.plugins\org.eclipse.wst.server.core\
        // tmp0\wtpwebapps\springMVCDemo11\下载
        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\.plugins\org.eclipse.wst.server.core\
            // tmp0\wtpwebapps下载
            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  被下载文件列表页面

 

 
 
分类: SpringMVC
好文要顶 关注我 收藏该文 
1
0
 
 
 
« 上一篇: SpringMVC------异常处理
posted @ 2019-11-11 17:20 流氓大队长 阅读(29) 评论(0) 编辑 收藏

 

 
 

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\.plugins\org.eclipse
* .wst.server.core\tmp0\wtpwebapps, 发布后使用
*/
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\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\springMVCDemo11\uploadfiles)中下载文件,具体开发步骤如下:

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\.plugins\org.eclipse.wst.server.core\
        // tmp0\wtpwebapps\springMVCDemo11\下载
        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\.plugins\org.eclipse.wst.server.core\
            // tmp0\wtpwebapps下载
            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  被下载文件列表页面

 

 
 
 
posted on 2019-11-11 20:01  神剑战王  阅读(93)  评论(0编辑  收藏  举报