springmvc文件上传下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下Spring中的文件上传和下载功能的实现,文件上传必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。 一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。而Spring MVC则提供了更简单的封装。
Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件,common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。
一、pom.xml
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
二、springmvc.xml中配置MultipartFile解析器
SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。在springmvc-config.xml进行配置文件如下
<!-- 配置文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设置最大上传文件为5M -->
<property name="maxUploadSize">
<value>10510925824 </value>
</property>
</bean>
三、创建一个FileUploadController类
Spring MVC会将上传的文件绑定到MultipartFile对象中。MultipartFile提供了获取上传文件内容、文件名等方法。通过transferTo()方法还可以将文件存储到硬件中,MultipartFile对象中的常用方法如下:
byte[] getBytes():获取文件数据
String getContentType[]:获取文件MIME类型,如image/jpeg等
InputStream getInputStream():获取文件流
String getName():获取表单中文件组件的名字
String getOriginalFilename():获取上传文件的原名
Long getSize():获取文件的字节大小,单位为byte
boolean isEmpty():是否有上传文件
void transferTo(File dest):将上传文件保存到一个目录文件中
文件上传的细节
1、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
2、为提高io性能,上传文件夹以年月日创建
3、要限制上传文件的最大值。
4、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
5、页面必须设置enctype="multipart/form-data" 提交方式为POST
package com.htf.controller;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Controller
public class FileUploadController {
private final static Logger logger = LoggerFactory.getLogger(FileUploadController.class);
private Map resultMap = new HashMap<>();
@RequestMapping("/Upload.do")
public String uploadFiles(@RequestParam("file") MultipartFile[] files, HttpServletRequest request,
HttpServletResponse response, Model mv) throws IOException {
Long startTime = System.currentTimeMillis();
String rootPath = "D:\\Software\\upload";
if (files != null && files.length > 0) {
try {
for (MultipartFile mu : files) {
if (!mu.isEmpty()) {
// String rootPath=request.getSession().getServletContext().getRealPath("/upload");
// 原始名称
String originalFileName = mu.getOriginalFilename();
// 新文件名
String qb = UUID.randomUUID() + "";
qb = qb.substring(0, 5);
String newFileName = originalFileName.substring(0, originalFileName.lastIndexOf(".")) + "_" + qb
+ originalFileName.substring(originalFileName.lastIndexOf("."));
// list.add(newFileName);
// 创建年月文件夹
Calendar date = Calendar.getInstance();
File dateDirs = new File(date.get(Calendar.YEAR) + File.separator
+ (date.get(Calendar.MONTH) + 1) + File.separator + date.get(Calendar.DAY_OF_MONTH));
// 新文件
File newFile = new File(rootPath + File.separator + dateDirs + File.separator + newFileName);
// 判断目标文件所在目录是否存在
if (!newFile.getParentFile().exists()) {
// 如果目标文件所在的目录不存在,则创建父目录
newFile.getParentFile().mkdirs();
}
// MultipartFile自带的解析方法
mu.transferTo(newFile);
}
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
Map mapTmp = new HashMap();
mapTmp = readFile(rootPath);
// List list = new ArrayList<>();
// for (Object key : mapTmp.keySet()) {
// list.add(key);
// }
mv.addAttribute("message", mapTmp);
Long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:" + (endTime - startTime) + "ms");
return "message";
}
@RequestMapping("/down.do")
public String down(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
try {
// String path =request.getSession().getServletContext().getRealPath("/upload");
String path = "D:\\Software\\upload";
Map fileMap = readFile(path);
String name = request.getParameter("name");
File fileEnd = (File) fileMap.get(name);
response.addHeader("content-disposition", "attachment;filename=" + name);
ServletOutputStream out = response.getOutputStream();
FileUtils.copyFile(fileEnd, out);
out.flush();
out.close();
// return null: 解决getOutputStream() has already been called for this response,
return null;
} catch (Exception e) {
e.printStackTrace();
}
model.addAttribute("msg", "下载成功!!!");
return "message";
}
private Map readFile(String path) {
File file = new File(path);
if (file.exists()) {
File[] files = file.listFiles();
if (null == files || files.length == 0) {
System.out.println("文件夹是空的!");
} else {
for (File file2 : files) {
if (file2.isDirectory()) {
System.out.println("文件夹:" + file2.getAbsolutePath());
readFile(file2.getAbsolutePath());
} else {
this.resultMap.put(file2.getName(), file2);
}
}
}
} else {
System.out.println("文件不存在!");
}
return this.resultMap;
}
}
四、文件上传页面
在页面form表单中提交数据时,必须设置enctype="multipart/form-data" ,提交方式post
<%@ page 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">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/Upload.do" method="post" enctype="multipart/form-data">
上传文件1:<input type="file" name="file"> <br/>
上传文件2:<input type="file" name="file"><br/>
上传文件3:<input type="file" name="file"><br/>
上传文件4:<input type="file" name="file"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
五、文件下载页面
<%@ page 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">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1><a href="jsp/upload.jsp">上传</a></h1>
<c:forEach var="file" items="${message}">
${file.key} <a href="down.do?name=${file.key}">文件下载</a><br/>
</c:forEach>
</body>
</html>
六、效果如图所示
上传成功
文件夹是以年月日创建的,提高io性能
下载