SpringMVC框架06——文件上传与下载
1、文件上传
Spring MVC框架的文件上传是基于commons-fileupload组件的文件上传,只不过Spring MVC框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现。
1.1、单文件上传
需要commons-fileupload组件相关依赖
<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>
页面中的form表单上添加多部件属性,fileupload.jsp
<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>
enctype属性指定的是表单数据的编码方式,该属性有以下3个值:
- application/x-www-form-urlencoded:默认的编码方式,只处理表单域里的value属性值;
- multipart/form-data:以二进制流的方式来处理表单数据,并将文件域指定文件的内容封装到请求参数里;
- text/plain:只有当表单的action属性为mailto:URL的形式时才使用,主要适用于直接通过表单发送邮件的方式。
创建POJO实体类
import org.springframework.web.multipart.MultipartFile; public class FileDomain { private String description; private MultipartFile myfile; //getter和setter }
在实体类中声明MultipartFile类型的属性封装被上传的文件信息,属性名与文件上传页面fileupload.jsp中的file类型的表单参数名myfile相同。
创建控制器类
@Controller public class FileUploadController { @RequestMapping("/onefile") public String oneFileUpload(@ModelAttribute FileDomain fileDomain, HttpServletRequest request){ //文件上传的位置 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); System.out.println("文件上传成功"); } catch (Exception e){ e.printStackTrace(); } return "showFile"; } }
配置springmvc.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
创建showFile.jsp用于展示结果:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>文件上传信息</title> </head> <body> 文件名称:${fileDomain.myfile.originalFilename}<br> 文件描述:${fileDomain.description} </body> </html>
上传页面展示:
上传结果展示:
注意事项:
- 在上传页面fileupload.jsp中,form表单一定要加enctype属性,值为multipart/form-data,表单提交方式设置为post;
- form表单中的file标签的name属性要和实体类的MultipartFile属性的名称保持一致;
- 要在springmvc.xml中使用CommonsMultipartResolver类配置multipartResolver用于文件上传;
1.2、多文件上传
创建multifiles.jsp文件上传页面:
<form action="${pageContext.request.contextPath}/multifile" method="post" enctype="multipart/form-data"> <p> 选择文件1:<input type="file" name="myfile"><br> 文件描述1:<input type="text" name="description"> </p> <p> 选择文件2:<input type="file" name="myfile"><br> 文件描述2:<input type="text" name="description"> </p> <p> 选择文件3:<input type="file" name="myfile"><br> 文件描述3:<input type="text" name="description"> </p> <p> <input type="submit" value="提交"> </p> </form>
创建POJO类:
public class MultiFileDomain { private List<String> description; private List<MultipartFile> myfile; //getter和setter }
创建Controller类,接收上传参数:
@Controller public class FileUploadController { //多文件上传 @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(); } } System.out.println("文件上传成功!"); return "showMulti"; } }
创建成功信息页面showMulti.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>多文件上传结果</title> </head> <body> <table width="50%" border="1"> <tr> <td>文件名</td> <td>详情</td> </tr> <c:forEach var="des" items="${multiFileDomain.description}" varStatus="loop"> <tr> <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td> <td>${des}</td> </tr> </c:forEach> </table> </body> </html>
测试多文件上传
上传结果:
2、文件下载
2.1、文件下载相关介绍
实现文件下载有两种方法:一种是通过超链接实现下载,另一种是利用程序编码实现下载。通过超链接实现下载比较简单,但是会暴露下载文件的真实位置,利用程序编码实现下载可以增加安全访问控制。
利用程序实现下载需要设置两个报头:
(1)设置Content-Type的值为application/x-msdownload
这项设置主要是为了告诉浏览器,其所输出内容的类型不是普通文本文件或HTML文件,而是一个要保存到本地的下载文件。
(2)设置Content-Disposition的值为attachment,并且在后面指定filename参数
这项设置主要是让浏览器不要直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中。该报头指定了接收程序处理数据内容的方式,在HTTP应用中只有attachment是标准方式,attachment表示要求用户干预。在attachment后面还可以指定filename参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。
设置报头的示例代码如下:
//设置下载文件使用的报头 response.setHeader("Content-Type","application/x-msdownload"); response.setHeader("Content-Disposition","attachment;filename="+filename);
2.2、文件下载的功能实现
创建FileDownController类,并编写下载功能的方法:
@Controller public class FileDownController { @RequestMapping("/down") public String down(@RequestParam String filename, HttpServletRequest request, HttpServletResponse response){ String filePath = null; //要下载的文件路径 FileInputStream in = null; //输入流 ServletOutputStream out = null; //输出流 try { //文件下载路径 filePath = request.getServletContext().getRealPath("uploadfiles"); //设置下载文件使用的报头 response.setHeader("Content-Type","application/x-msdownload"); response.setHeader("Content-Disposition","attachment;filename="+toUTF8String(filename)); //读入文件 in = new FileInputStream(filePath+"\\"+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 (Exception e) { e.printStackTrace(); } System.out.println("下载成功!"); 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 (Exception 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(); } }
创建页面展示可下载文件的Controller类和方法:
@RequestMapping("/show") public String show(HttpServletRequest request, Model model){ //文件下载路径 String realPath = request.getServletContext().getRealPath("uploadfiles"); File dir = new File(realPath); File[] files = dir.listFiles(); //获取该目录下的所有文件名 ArrayList<String> fileNames = new ArrayList<String>(); for (int i=0;i<files.length;i++) { fileNames.add(files[i].getName()); } model.addAttribute("files",fileNames); return "showDown"; }
创建用于文件下载展示的showDown.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>文件下载</title> </head> <body> <table width="50%" border="1"> <tr> <th>文件名</th> <th>操作</th> </tr> <c:forEach var="filename" items="${files}"> <tr> <td>${filename} </td> <td> <a href="${pageContext.request.contextPath}/down?filename=${filename}">下载</a> </td> </tr> </c:forEach> </table> </body> </html>
效果展示:
点击下载链接