Spring MVC同样支持文件上传功能,不过该功能默认未开启,因为可能有些开发者可能希望自己处理文件上传过程。
Spring的文件上传功能在org.springframework.web.multipart包下,有两个MultipartResolver实现用来支持文件上传功能:
- 一个是基于Commons FileUpload
- 另一个基于Servlet 3.0 multipart请求解析功能
这两个MultipartResolver差不多,一个需要添加Commons FileUpload的依赖,另一个需要在Servlet 3.0容器上运行。大家可以根据需要选择。
如果想要使用Spring的文件上传功能,需要在文件上下文中配置MultipartResolver。
定义MultipartResolver
使用Commons FileUpload MultipartResolver
在配置文件中添加如下一段,我们可以在Bean定义中配置上传文件大小等属性。
<!-- 文件上传 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸位30M -->
<property name="maxUploadSize" value="31457280" />
<property name="defaultEncoding" value="UTF-8" />
<!-- 是否延迟加载,在需要的时候才进行上传文件的解析 -->
<property name="resolveLazily" value="true" />
<!-- 文件上传的临时路径,文件上传完成后,临时目录中的临时文件会被自动清除 -->
<property name="uploadTempDir" value="upload/temp" />
</bean>
defaultEncoding必须和JSP的pageEncoding属性一致,以便正确读取表单的内容。
注意:引入commons-fileupload.jar、commons-io.jar 两个包。
使用Servlet 3.0 MultipartResolver
由于使用的是Servlet API提供的文件上传功能,所以文件大小等配置需要在web.xml中进行配置。我们需要在dispathcer-servlet中添加<multipart-config>标签,它有四个子标签来设置文件上传的属性。
这四个属性如下:
- location ,临时文件的存放位置,这个路径必须是绝对路径。
- fileSizeThreshold,文件起始值,大于该值文件才会被临时保存,单位是字节。
- MaxFileSize,单个文件的最大值,单位是字节,不管上传几个文件,只要有一个文件大小超过该值就会抛出IllegalStateException。
- maxRequestSize,文件上传请求的最大值,单位是字节,主要作用是当上传多个文件是配置整个请求的大小,当超出该值是抛出IllegalStateException。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
<multipart-config>
<max-file-size>100000</max-file-size>
</multipart-config>
</servlet>
然后我们在Spring配置文件中添加Servlet 3.0 MultipartResolver。
<bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean>
上传文件
配置好了Multipart解析器之后,我们就可以接收文件了。
首先定义一个页面fileupload.jsp,用于上传文件并显示服务器中的文件。
注意:在表单中我们必须添加<code>enctype="multipart/form-data"</code>才能正确的上传文件。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
<meta charset="utf-8">
</head>
<body>
<h2>文件上传</h2>
<form action="<c:url value="/mvc/uploadfile.html"/>"
method="post" enctype="multipart/form-data">
<label for="file">文件</label>
<input type="file" name="file" id="file"/>
<br>
<input type="submit" value="提交">${result}
</form>
</body>
</html>
然后就可以在控制器中获取文件了。由于MultipartFile和它对应的临时文件会在方法结束之后被Spring清除,所以我们必须在方法中将文件保存到合适的地方。
在请求方法中,我们可以像普通参数那样获取上传的文件,只不过文件对应的类型是MultipartFile,如果使用的是Servlet 3.0标准的,那么类型还可以是javax.servlet.http.Part。
下面写了两个处理方法,第一个将MultipartFile转化为File保存在web目录下的upload文件夹中,第二个方法用于获取保存在该文件夹的文件。
@RequestMapping("/uploadfile.html")
public String uploadFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
// 获取到web的根目录
String path = System.getProperty("tansungWeb.root");
if (!multipartFile.isEmpty()) {
// 获取到源文件名
String filename = multipartFile.getOriginalFilename();
// 获取文件的后缀名
String suffix = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
// 如果后缀为mp3的,一上传文件原名保存,否则以时间戳文文件名进行保存
if (!suffix.equals("mp3")) {
//FileUtils.copyInputStreamToFile(multipartFile.getInputStream(),new File(path + "//upload//", System.currentTimeMillis() + "." + suffix));
multipartFile.transferTo(new File(path + "//upload//", System.currentTimeMillis() + "." + suffix));
} else {
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(path + "//upload//", filename));
}
}
model.addAttribute("result", "上传成功!");
return "fileupload";
}
}
Spring MVC会将上传文件绑定到MultipartFile对象中。MultipartFile提供了获取上传文件内容、文件名等内容,通过其transferTo()方法还可将文件存储到硬件中。
// 获取文件数据
byte[] getBytes();
// 获取文件MIME类型,如image/jprg等
String getContentType();
// 获取文件流
InputStream getInputStream();
// 获取表单中文件组件的名字
String getName();
// 获取上传文件的原名
String getOriginalFilename();
// 获取文件的字节大小,单位为byte
long getSize();
// 是否有上传的文件
boolean isEmpty();
// 可以使用该文件将上传文件保存到一个目标文件中
void transferTo(File dest);
将上传的文件列出来,实现下载的功能。
@RequestMapping("/listfile")
public String listFile(Model model)
throws IOException, ServletException {
// 获取上传文件的目录
String uploadFilePath = System.getProperty("tansungWeb.root") + "upload";
// 存储要下载的文件名
Map<String, String> fileNameMap = new HashMap<String, String>();
// 递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
// File既可以代表一个文件也可以代表一个目录
listfile(new File(uploadFilePath), fileNameMap);
// 将Map集合发送到list.jsp页面进行显示
model.addAttribute("fileNameMap", fileNameMap);
return "list";
}
/**
* @Method: listfile
* @Description: 递归遍历指定目录下的所有文件
* @param file
* 即代表一个文件,也代表一个文件目录
* @param map
* 存储文件名的Map集合
*/
public void listfile(File file, Map<String, String> map) {
// 如果file代表的不是一个文件,而是一个目录
if (!file.isFile()) {
// 列出该目录下的所有文件和目录
File files[] = file.listFiles();
// 遍历files[]数组
for (File f : files) {
// 递归
listfile(f, map);
}
} else {
/*
* 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
* file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:
* 9349249849-88343-8344_阿凡达.avi
* 那么file.getName().substring(file.getName().indexOf("_")+1)
* 处理之后就可以得到阿凡达.avi部分
*/
String realName = file.getName().substring(file.getName().indexOf("_") + 1);
// file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
map.put(file.getName(), realName);
}
}
编写list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>下载列表显示页面</title>
</head>
<body>
<!-- 遍历Map集合 -->
<c:forEach var="files" items="${fileNameMap}">
<c:url value="/mvc/download" var="downurl">
<c:param name="filename" value="${files.key}"></c:param>
</c:url>
${files.value}<a href="${downurl}">下载</a>
<!--
<a href="<c:url value="/mvc/download?filename=${files.value}"/>">${files.value}</a>
-->
<br/>
</c:forEach>
</body>
</html>
下载文件
下载功能的实现
@RequestMapping("/download")
public void downloadFile(@RequestParam("filename") String filename, Model model, HttpServletRequest req, HttpServletResponse resp)
throws IOException {
filename = new String(filename.getBytes("iso8859-1"), "UTF-8");
//上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
String fileSaveRootPath = System.getProperty("tansungWeb.root") + "upload";
// 得到要下载的文件
File file = new File(fileSaveRootPath + "\\" + filename);
// 如果文件不存在
if (!file.exists()) {
model.addAttribute("message", "您要下载的资源已被删除!!");
}
// 处理文件名
String realname = filename.substring(filename.indexOf("_") + 1);
// 设置响应头,控制浏览器下载该文件
resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
// 读取要下载的文件,保存到文件输入流
FileInputStream in = new FileInputStream(fileSaveRootPath + "\\" + filename);
// 创建输出流
OutputStream out = resp.getOutputStream();
// 创建缓冲区
byte buffer[] = new byte[1024];
int len = 0;
// 循环将输入流中的内容读取到缓冲区当中
while ((len = in.read(buffer)) > 0) {
// 输出缓冲区的内容到浏览器,实现文件下载
out.write(buffer, 0, len);
}
// 关闭文件输入流
in.close();
// 关闭输出流
out.close();
}
网友评论