Spring基础知识(19)- Spring MVC (九) | 文件上传、 文件下载


1. 文件上传

    Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

    1) MultipartResolver接口

        在 Spring MVC 中实现文件上传十分容易,它为文件上传提供了直接支持,即 MultpartiResolver 接口。MultipartResolver 用于处理上传请求,将上传请求包装成可以直接获取文件的数据,从而方便操作。

        MultpartiResolver 接口有以下两个实现类:

            StandardServletMultipartResolver:使用了 Servlet 3.0 标准的上传方式。
            CommonsMultipartResolver:使用了 Apache 的 commons-fileupload 来完成具体的上传操作。

        MultpartiResolver 接口具有以下方法。

名称 作用
byte[] getBytes() 以字节数组的形式返回文件的内容
String getContentType() 返回文件的内容类型
InputStream getInputStream() 返回一个InputStream,从中读取文件的内容
String getName() 返回请求参数的名称
String getOriginalFillename() 返回客户端提交的原始文件名称
long getSize() 返回文件的大小,单位为字节
boolean isEmpty() 判断被上传文件是否为空
void transferTo(File destination) 将上传文件保存到目标目录下

 

    2) 单文件上传

        在 “Spring基础知识(12)- Spring MVC (二)” 的示例里,更新过 springmvc-beans.xml 的 SpringmvcBasic 项目基础上,修改如下。

        (1) 导入 Apache Commons FileUpload 依赖包

            访问 http://www.mvnrepository.com/,查询 commons-io、commons-fileupload

            修改 pom.xml:

 1                 <project ... >
 2                     ...
 3 
 4                     <dependencies>
 5 
 6                         ...
 7 
 8                         <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
 9                         <dependency>
10                             <groupId>commons-io</groupId>
11                             <artifactId>commons-io</artifactId>
12                             <version>2.8.0</version>
13                         </dependency>
14                         <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
15                         <dependency>
16                             <groupId>commons-fileupload</groupId>
17                             <artifactId>commons-fileupload</artifactId>
18                             <version>1.4</version>
19                         </dependency>
20 
21                         ...
22 
23                     </dependencies>
24                 
25                     ...    
26 
27                 </project>


            在IDE中项目列表 -> SrpingmvcBasic -> 点击鼠标右键 -> Maven -> Reload Project

        (2) 修改 springmvc-beans.xml 文件,添加如下配置

1             <!-- 配置 MultipartResolver,用于上传文件,使用 spring 的 CommonsMultipartResolver -->
2             <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
3                 <property name="maxUploadSize" value="5000000" />
4                 <property name="defaultEncoding" value="UTF-8" />
5             </bean>

            defaultEncoding:请求的编码格式,默认为 ISO-8859-1,此处设置为 UTF-8(注:defaultEncoding 必须和 JSP 中的 pageEncoding 一致,以便正确读取表单的内容)。
            maxUploadSize:上传文件大小上限,单位为字节。

        (3) 创建 src/main/java/com/example/entity/FileObject.java 文件

 1             package com.example.entity;
 2 
 3             import org.springframework.web.multipart.MultipartFile;
 4 
 5             public class FileObject {
 6                 private MultipartFile file;
 7                 private String description;
 8 
 9                 public FileObject() {
10 
11                 }
12 
13                 public MultipartFile getFile() {
14                     return file;
15                 }
16 
17                 public void setFile(MultipartFile file) {
18                     this.file = file;
19                 }
20 
21                 public String getDescription() {
22                     return description;
23                 }
24 
25                 public void setDescription(String description) {
26                     this.description = description;
27                 }
28             }


        (4) View
        
            创建 src/main/webapp/WEB-INF/jsp/file.jsp 文件

 1                 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2                 <html>
 3                 <head>
 4                     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5                     <title>File</title>
 6                 </head>
 7                 <body>
 8                     <form action="${pageContext.request.contextPath }/file/post" method="POST" enctype="multipart/form-data">
 9                         <p>File: <input type="file" name="file"></p>
10                         <p>File Description: <input type="text" name="description"></p>
11                         <p><input type="submit" value="Submit"></p>
12                     </form>
13                 </body>
14                 </html>


            创建 src/main/webapp/WEB-INF/jsp/showfile.jsp 文件

 1                 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2                 <html>
 3                 <head>
 4                     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5                     <title>Show File</title>
 6                 </head>
 7                 <body>
 8                     <p>File Description: ${fileObject.description }</p>
 9                     <!-- fileObject.getFile().getOriginalFilename()-->
10                     <p>Filename:${fileObject.file().originalFilename }</p>
11                 </body>
12                 </html>


        (5) 创建 src/main/java/com/example/controller/UploadController.java 文件

 1             package com.example.controller;
 2 
 3             import java.io.File;
 4             import javax.servlet.http.HttpServletRequest;
 5             import org.springframework.stereotype.Controller;
 6             import org.springframework.web.bind.annotation.ModelAttribute;
 7             import org.springframework.web.bind.annotation.RequestMapping;
 8 
 9             import com.example.entity.FileObject;
10 
11             @Controller
12             @RequestMapping("/upload")
13             public class UploadController {
14 
15                 @RequestMapping("/file")
16                 public String file() {
17                     return "file";
18                 }
19 
20                 @RequestMapping("/file/post")
21                 public String filePost(@ModelAttribute FileObject fileObject, HttpServletRequest request) {
22 
23                     try {
24                         String realpath = request.getServletContext().getRealPath("/uploads");
25                         File targetFile = new File(realpath, fileObject.getFile().getOriginalFilename());
26                         if (!targetFile.exists()) {
27                             targetFile.mkdirs();
28                         }
29 
30                         fileObject.getFile().transferTo(targetFile);
31                     } catch (Exception e) {
32                         e.printStackTrace();
33                     }
34 
35                     return "showfile";
36                 }
37             }


        访问:http://localhost:9090/upload/file

    3) 多文件上传

        在 “Spring基础知识(12)- Spring MVC (二)” 的示例里,更新过 springmvc-beans.xml 的 SpringmvcBasic 项目基础上,修改如下。

        导入 Apache Commons FileUpload 依赖包和修改 springmvc-beans.xml 文件,参考上文 “单文件上传”。

        (1) 导入 JSTL 依赖包

            访问 http://www.mvnrepository.com/,查询 JSTL
        
            修改 pom.xml:

 1             <project ... >
 2 
 3                 <dependencies>
 4                     ...
 5 
 6                     <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
 7                     <dependency>
 8                     <groupId>javax.servlet</groupId>
 9                     <artifactId>jstl</artifactId>
10                     <version>1.2</version>
11                     </dependency>
12                     
13                     ...
14                 </dependencies>
15 
16             </project>


        (2) 创建 src/main/java/com/example/entity/FileListObject.java 文件

 1             package com.example.entity;
 2 
 3             import java.util.List;
 4             import org.springframework.web.multipart.MultipartFile;
 5 
 6             public class FileListObject {
 7                 private List<String> descriptionList;
 8                 private List<MultipartFile> fileList;
 9 
10                 public List<String> getDescriptionList() {
11                     return descriptionList;
12                 }
13 
14                 public void setDescriptionList(List<String> descriptionList) {
15                     this.descriptionList = descriptionList;
16                 }
17 
18                 public List<MultipartFile> getFileList() {
19                     return fileList;
20                 }
21 
22                 public void setFileList(List<MultipartFile> fileList) {
23                     this.fileList = fileList;
24                 }
25             }


        (3) View
        
            创建 src/main/webapp/WEB-INF/jsp/filelist.jsp 文件

 1                 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2                 <html>
 3                 <head>
 4                 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5                 <title>File List</title>
 6                 </head>
 7                 <body>
 8                     <form action="${pageContext.request.contextPath }/upload/filelist/post" method="post" enctype="multipart/form-data">
 9                         <p>File 1:<input type="file" name="fileList"></p>
10                         <p>File Description 1: <input type="text" name="descriptionList"></p>
11                         <p>File 2: <input type="file" name="fileList"></p>
12                         <p>File Description 2: <input type="text" name="descriptionList"></p>
13                         <p><input type="submit" value="Submit"></p>
14                     </form>
15                 </body>
16                 </html>


            创建 src/main/webapp/WEB-INF/jsp/showfilelist.jsp 文件

 1                 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2                 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 3                 <html>
 4                 <head>
 5                     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 6                     <title>Show File List</title>
 7                 </head>
 8                 <body>
 9                     <table border="1px">
10                         <tr>
11                             <td>Description</td>
12                             <td>Filename</td>
13                         </tr>
14                         <!-- 同时取两个数组的元素 -->
15                         <c:forEach items="${fileListObject.descriptionList}" var="description" varStatus="loop">
16                             <tr>
17                                 <td>${description}</td>
18                                 <td>${fileListObject.fileList[loop.count-1].originalFilename}</td>
19                             </tr>
20                         </c:forEach>
21                         <!-- fileListObject.getFileList()[loop.count-1].getOriginalFilename() -->
22                     </table>
23                 </body>
24                 </html>


        (4) 创建 src/main/java/com/example/controller/UploadController.java 文件

 1             package com.example.controller;
 2 
 3             import java.util.List;
 4             import java.io.File;
 5             import javax.servlet.http.HttpServletRequest;
 6             import org.springframework.stereotype.Controller;
 7             import org.springframework.web.bind.annotation.ModelAttribute;
 8             import org.springframework.web.bind.annotation.RequestMapping;
 9 
10             import org.springframework.web.multipart.MultipartFile;
11             import com.example.entity.FileListObject;
12 
13             @Controller
14             @RequestMapping("/upload")
15             public class UploadController {
16 
17                 @RequestMapping("/filelist")
18                 public String filelist() {
19                     return "filelist";
20                 }
21 
22                 @RequestMapping("/filelist/post")
23                 public String filelistPost(@ModelAttribute FileListObject fileListObject, HttpServletRequest request) {
24 
25                     String realpath = request.getServletContext().getRealPath("/uploads");
26                     File targetDir = new File(realpath);
27                     if (!targetDir.exists()) {
28                         targetDir.mkdirs();
29                     }
30 
31                     List<MultipartFile> files = fileListObject.getFileList();
32                     for (int i = 0; i < files.size(); i++) {
33                         
34                         try {
35                             File targetFile = new File(realpath, files.get(i).getOriginalFilename());
36                             files.get(i).transferTo(targetFile);
37                         } catch (Exception e) {
38                             e.printStackTrace();
39                         }
40                     }
41 
42                     return "showfilelist";
43                 }
44             } 


        访问:http://localhost:9090/upload/filelist


2. 文件下载


    文件下载就是将服务器中的文件下载到本地,下面主要介绍 Spring MVC 文件下载的实现方法和实现过程。

    1) 通过超链接实现下载

        实现简单,但暴露了下载文件的真实位置,并且只能下载 Web 应用程序所在目录下的文件,WEB-INF 目录除外。
        
    2) 利用程序编码实现下载
        
        增强安全访问控制,可以下载除 Web 应用程序所在目录以外的文件,也可以将文件保存到数据库中。

        需要设置以下两个报头:

            (1) Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为 application/x-msdownload。

                response.setHeader("Content-Type", "application/x-msdownload");

            (2) Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。

                response.setHeader("Content-Disposition", "attachment;filename="+filename);

                该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

        分为两个步骤:

            (1) 在客户端使用一个文件下载超链接,链接指向后台下载文件的方法以及文件名。
            (2)) 在控制器类中,提供文件下载方法进行下载。

    示例

        在 “Spring基础知识(12)- Spring MVC (二)” 的示例里,更新过 springmvc-beans.xml 的 SpringmvcBasic 项目基础上,修改如下。

        导入 JSTL 依赖包,参考上文 “多文件上传”。

        (1) 创建 src/main/webapp/WEB-INF/jsp/download.jsp 文件

 1             <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 2             <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 3             <head>
 4                 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 5                 <title>Download</title>
 6             </head>
 7             <body>
 8                 <p>Download files</p>
 9                 <!--遍历 model中的 files-->
10                 <c:forEach items="${files}" var="filename">
11                     <p><a href="${pageContext.request.contextPath }/download/files?filename=${filename}">${filename}</a></p>
12                 </c:forEach>
13             </body>
14             </html>


        (2) 创建 src/main/java/com/example/controller/DownloadController.java 文件

  1             package com.example.controller;
  2 
  3             import java.io.File;
  4             import java.io.FileInputStream;
  5             import java.io.UnsupportedEncodingException;
  6             import java.util.ArrayList;
  7             import javax.servlet.ServletOutputStream;
  8             import javax.servlet.http.HttpServletRequest;
  9             import javax.servlet.http.HttpServletResponse;
 10             import org.springframework.stereotype.Controller;
 11             import org.springframework.ui.Model;
 12             import org.springframework.web.bind.annotation.RequestMapping;
 13             import org.springframework.web.bind.annotation.RequestParam;
 14 
 15             @Controller
 16             @RequestMapping("/download")
 17             public class DownloadController {
 18 
 19                 @RequestMapping("show")
 20                 public String show(HttpServletRequest request, Model model) {
 21 
 22                     String realpath = request.getServletContext().getRealPath("/uploads");
 23                     File dir = new File(realpath);
 24                     File files[] = dir.listFiles();
 25 
 26                     // 获取该目录下的所有文件名
 27                     ArrayList<String> fileName = new ArrayList<String>();
 28                     for (int i = 0; i < files.length; i++) {
 29                         fileName.add(files[i].getName());
 30                     }
 31 
 32                     model.addAttribute("files", fileName);
 33                     return "download.jsp";
 34                 }
 35 
 36                 @RequestMapping("files")
 37                 public String files(@RequestParam String filename,
 38                                     HttpServletRequest request, HttpServletResponse response) {
 39 
 40                     try {
 41 
 42                         String filePath = request.getServletContext().getRealPath("/uploads");
 43 
 44                         // 设置下载文件使用的报头
 45                         response.setHeader("Content-Type", "application/x-msdownload");
 46                         response.setHeader("Content-Disposition", "attachment; filename=" + toUTF8String(filename));
 47 
 48                         // 读入文件
 49                         FileInputStream in = new FileInputStream(filePath + "/" + filename);
 50 
 51                         // 得到响应对象的输出流,用于向客户端输出二进制数据
 52                         ServletOutputStream out = response.getOutputStream();
 53                         out.flush();
 54 
 55                         int aRead = 0;
 56                         byte b[] = new byte[1024];
 57                         while ((aRead = in.read(b)) != -1 & in != null) {
 58                             out.write(b, 0, aRead);
 59                         }
 60 
 61                         out.flush();
 62                         in.close();
 63                         out.close();
 64                     } catch (Exception e) {
 65                         e.printStackTrace();
 66                     }
 67 
 68                     return null;
 69                 }
 70 
 71                 /**
 72                  * 中文字符编码转换方法
 73                  */
 74                 public String toUTF8String(String str) {
 75                     StringBuffer sb = new StringBuffer();
 76                     int len = str.length();
 77 
 78                     for (int i = 0; i < len; i++) {
 79                         // 取出字符中的每个字符
 80                         char c = str.charAt(i);
 81                         // Unicode码值为0~255时,不做处理
 82                         if (c >= 0 && c <= 255) {
 83                             sb.append(c);
 84                         } else { // 转换 UTF-8 编码
 85                             byte b[];
 86                             try {
 87                                 b = Character.toString(c).getBytes("UTF-8");
 88                             } catch (UnsupportedEncodingException e) {
 89                                 e.printStackTrace();
 90                                 b = null;
 91                             }
 92 
 93                             // 转换为%HH的字符串形式
 94                             for (int j = 0; j < b.length; j++) {
 95                                 int k = b[j];
 96                                 if (k < 0) {
 97                                     k &= 255;
 98                                 }
 99                                 sb.append("%" + Integer.toHexString(k).toUpperCase());
100                             }
101                         }
102                     }
103 
104                     return sb.toString();
105                 }
106             }


        访问:http://localhost:9090/download/show


posted @ 2022-04-02 21:16  垄山小站  阅读(224)  评论(0)    收藏  举报