在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这个包的,所以还需要下载这个包。
<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性能
下载