Spring MVC框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过SpringMVC 框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。
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 的类库。
基于表单的文件上传
标签 会在浏览器中显示一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件。
文件上传的表单例子如下:
对于基于表单的文件上传,不要忘记使用 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,将SpringMVC 相关的 JAR 包、commons-fileupload 组件相关的 JAR 包以及 JSTL相关的 JAR 包导入应用的 lib 目录中,如图 1 所示。
图 1 springMVCDemo11
2)创建 web.xml 文件
在 WEB-INF 目录下创建 web.xml 文件。为防止中文乱码,需要在 web.xml 文件中添加字符编码过滤器,这里不再赘述。
3)创建文件选择页面
在 WebContent 目录下创建JSP页面 oneFile.jsp,在该页面中使用表单上传单个文件,具体代码如下:
Insert title here选择文件:文件描述:
4)创建 POJO 类
在 src 目录下创建 pojo 包,在该包中创建 POJO 类 FileDomain。然后在该 POJO 类中声明一个 MultipartFile 类型的属性封装被上传的文件信息,属性名与文件选择页面 oneFile.jsp 中的 file 类型的表单参数名 myfile 相同。具体代码如下:
package pojo;
import org.springframework.web.multipart.MultipartFile;public classFileDomain {privateString description;privateMultipartFile myfile;publicString getDescription() {returndescription;
}public voidsetDescription(String description) {this.description =description;
}publicMultipartFile getMyfile() {returnmyfile;
}public voidsetMyfile(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;
@Controllerpublic classFileUploadController {//得到一个用来记录日志的对象,这样在打印信息时能够标记打印的是哪个类的信息
private static final Log logger = LogFactory.getLog(FileUploadController.class);/**
* 单文件上传*/@RequestMapping("/onefile")publicString 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= newFile(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 的代码如下:
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
7)创建成功显示页面
在 WEB-INF 目录下创建 JSP 文件夹,并在该文件夹中创建单文件上传成功显示页面 showOne.jsp。具体代码如下:
Insert title here${fileDomain.myfile.originalFilename }
8)测试文件上传
发布 springMVCDemo11 应用到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo11/oneFile.jsp”运行文件选择页面,运行结果如图 2 所示。
图 2 单文件选择页面
在图 2 中选择文件并输入文件描述,然后单击“提交”按钮上传文件,若成功则显示如图 3 所示的结果。
图 3 单文件成功上传结果
Spring MVC多文件上传
1)创建多文件选择页面
在 WebContent 目录下创建JSP页面 multiFiles.jsp,在该页面中使用表单上传多个文件,具体代码如下:
Insert title here选择文件1:文件描述1:
选择文件2:
文件描述2:
选择文件3:
文件描述3:
2)创建 POJO 类
在上传多文件时需要 POJO 类 MultiFileDomain 封装文件信息,MultiFileDomain 类的具体代码如下:
package pojo;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;public classMultiFileDomain {private Listdescription;private ListmyFile;//省略setter和getter方法
}
3)添加多文件上传处理方法
在控制器类 FileUploadController 中添加多文件上传的处理方法 multiFileUpload,具体代码如下:
/**
* 多文件上传*/@RequestMapping("/multifile")publicString multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain,HttpServletRequest request) {
String realpath= request.getServletContext().getRealPath("uploadfiles");
File targetDir= newFile(realpath);if (!targetDir.exists()) {
targetDir.mkdirs();
}
List files =multiFileDomain.getMyFile();for (int i = 0; i < files.size(); i++) {
MultipartFile file= files.get(i);
String fileName=file.getOriginalFilename();
File targetFile= newFile(realpath, fileName);//上传
try{
file.transferTo(targetFile);
}catch(Exception e) {
e.printStackTrace();
}
}
logger.info("成功");return "showMulti";
}
4)创建成功显示页面
在 JSP 文件夹中创建多文件上传成功显示页面 showMulti.jsp,具体代码如下:
Insert title here详情 | 文件名 |
${description} | ${multiFileDomain.myfile[loop.count-1].originalFilename} |
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;
@Controllerpublic classFileDownController {//得到一个用来记录日志的对象,在打印时标记打印的是哪个类的信息
private static final Log logger =LogFactory
.getLog(FileDownController.class);/**
* 显示要下载的文件*/@RequestMapping("showDownFiles")publicString show(HttpServletRequest request, Model model) {//从 workspace\.metadata\.plugins\org.eclipse.wst.server.core\//tmp0\wtpwebapps\springMVCDemo11\下载
String realpath =request.getServletContext()
.getRealPath("uploadfiles");
File dir= newFile(realpath);
File files[]=dir.listFiles();//获取该目录下的所有文件名
ArrayList fileName = new ArrayList();for (int i = 0; i < files.length; i++) {
fileName.add(files[i].getName());
}
model.addAttribute("files", fileName);return "showDownFiles";
}/**
* 执行下载*/@RequestMapping("down")publicString 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;
}/**
* 下载保存时中文文件名的字符编码转换方法*/
publicString toUTF8String(String str) {
StringBuffer sb= newStringBuffer();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 编码
byteb[];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());
}
}
}returnsb.toString();
}
}
2)创建文件列表页面
下载文件示例需要一个显示被下载文件的JSP页面 showDownFiles.jsp,代码如下:
Insert title here被下载的文件名 |
${filename} |