Spring MVC 文件上传和下载

文章目录

  • [Spring MVC 中文件上传](#Spring MVC 中文件上传)
    • [利用 commons-fileupload 文件上传](#利用 commons-fileupload 文件上传)
    • [使用 Servlet 3.1 内置的文件上传功能](#使用 Servlet 3.1 内置的文件上传功能)
  • [Spring MVC 中文件下载](#Spring MVC 中文件下载)

Spring MVC 中文件上传

为了能上传文件,必须将 from 表单的 method 设置为 POST ,并将 enctype 设置为 multipart/form-data

实现文件上传的 "底层" 方案有 2 种:

  • 使用 Apache Commons FileUpload 包

  • 使用 Servlet 3.1 内置的文件上传功能

无论你的底层是使用上述的哪种方案,Spring MVC 都对它们作出了『包装』,让 Spring MVC 中的上传文件的代码简化而统一:提供一个 MultipartResolver ,并将 <input type="file" ...> 类型的请求参数绑定到请求处理方法的 MultipartFile 类型的参数上。(两者具体的类型有所不同)

这需要提前说明以下,Spring MVC 利用 Servlet 3.1 内置的文件上传功能上传文件时,有个小问题。有人发现无法将它所用到的 StandardMultipartResolver 的编码从默认的 iso-8859-1 改为 UTF-8 。也有人分析,在使用 tomcat 7 时会出现这个问题,并认为这是 tomcat 7 的 bug 。所有,简单起见,建议优先考虑 commons-fileupload 方案。

具体讨论可参见:stakoverflow

利用 commons-fileupload 文件上传

利用 commons-fileupload 文件上传需要利用引入 commons-fileupload 包(它依赖于 commons-io 包)

xml 复制代码
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.5</version> 
</dependency>

Spring MVC 是通过 MultipartResolver 的 JavaBean 提供、支持文件上传功能。commons-fileupload 中该接口的实现类是 CommonsMultipartResolver

简单来说,CommonsMultipartResolver 是 Spring MVC 去利用 commons-fileupload 实现上传功能的『桥梁』。

spring-web.xml 中添加如下配置,让 Spring 负责创建并初始化该 Bean 。

xml 复制代码
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  <property name="maxUploadSize" value="104857600" />
  <property name="maxInMemorySize" value="4096" />
  <property name="defaultEncoding" value="UTF-8"/>
  <!-- 更多配置根据具体需求进一步再学习/使用 -->
</bean>

至此,配置结束。在 Spring MVC 的 Controller 中,Spring MVC 就可以将用户上传的数据绑定到 CommonsMultipartFile 类型的参数上。

注意

此处的 @RequestParam() 不能省略,即便是 name 与 name 一致。

java 复制代码
@RequestMapping("/upload.do")
public String upload(String username, 
                     String password,
                     @RequestParam("uploadfile") CommonsMultipartFile uploadfile) throws IOException {
    log.info("{}", uploadfile.getName());
    log.info("{}", uploadfile.getOriginalFilename());
    
    String path = "D:/" + new Date().getTime() + uploadfile.getOriginalFilename();
    
    uploadfile.transferTo(new File(path));
    
    return "";
}

CommonsMultipartFile 支持如下功能:

方法 说明
byte[] getBytes() 以字节数组的形式返回文件的内容
String getContentType() 返回文件的内容类型
InputStream getInputStream() 返回一个 InputStream,可以从中去读文件内容
String getName() 返回请求参数的 name
String getOriginalFilename() 返回文件原本的文件名
long getSize() 返回文件大小(单位字节)
boolean isEmpty() 判断上传的文件是否为空
void transferTo(File destination) 将上传的文件保存到指定位置

如果从页面上同时上传多个文件,那么页面上的 file 可以使用同一个 name,而代码中则使用 CommonsMultipartFile 的数组类型的参数接受。数组中的每一个 MultipartFile 就代表着一个上传的文件。

html 复制代码
<p><input type="file" name="files"></p>
<p><input type="file" name="files"></p>
<p><input type="file" name="files"></p>
java 复制代码
@RequestParam("files") CommonsMultipartFile[] files

使用 Servlet 3.1 内置的文件上传功能

补充,其实 Servlet 3.0 就已经开始提供内置的上传功能,只不过该功能在 Servlet 3.1 中进一步增强/改进/完成。因此一般的说法是 Servlet 3.1 支持内置的文件上传功能。

利用 Servlet 3.1 实现文件上传的概念和使用过程和利用 commons-fileupload 本质上并无太大区别。只不过有几处小区别:

  1. 提供文件上传功能的是 StandardServletMultipartResolver ,不再是 CommonsMultipartResolver

spring-web.xml:

xml 复制代码
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
  1. 对上传过程中的相关配置,是配置在 web.xml 中的 DispacherServlet 下,而非 spring-web.xml 中的 MultipartResolver 下。

web.xml:

xml 复制代码
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>...</init-param>
    <load-on-startup>...</load-on-startup>
    <multipart-config>
        <location>d:/</location> <!-- 临时文件的目录。该目录必须存在 -->
        <max-file-size>2097152</max-file-size> <!-- 一次请求上传的单个文件最大2M -->
        <max-request-size>4194304</max-request-size> <!-- 一次请求上传的多个文件整体大小不超过4M -->
    </multipart-config>
</servlet>
  1. Controller 代码中使用的注解是 @RequestPart("file") ,而非 @RequestParam;绑定的参数类型是 MultipartFile,而不是 CommonsMultipartFile 。
java 复制代码
@RequestMapping("/upload.do")
public String upload(String username, 
                     String password,
                     @RequestPart("files") MultipartFile[] files) 

MultipartFile 对象的功能与 CommonsMultipartFile 基本类似。

Spring MVC 中文件下载

Spring MVC 提供了一个 ResponseEntity 类型,使用它可以很方便地定义返回 HttpHeadersHttpStatus ,以实现下载功能。

java 复制代码
@RequestMapping("/download")
public ResponseEntity<byte[]> download(
        HttpServletRequest req,
        @RequestParam("filename") String filename, 
        Model model) throws Exception {

    // 1. 准备一个字节数组(字节数组的内容来源于一个文件)。
    //    这个字节数组,就是在本次 HTTP 请求中 Tomcat 要回给客户端浏览器的内容、数据。
    String path = req.getServletContext().getRealPath("upload");
    File file = new File(path + File.separator + filename);
    byte[] bytes = FileUtils.readFileToByteArray(file);

    // 2. 创建一个 ResponseEntity 对象。它代表着一个 HTTP 响应。
    //    而一个 HTTP 响应又有行-头-体。其中『体』里存放的就是上述的代表文件内容的字节数组
    HttpHeaders headers = new HttpHeaders();
    // 解决文件名乱码问题
    // String downloadFileName = new String(filename.getBytes("UTF-8"), "iso-8859-1");
    // 第一个放在 header 中的键值对 attachment=xxx
    headers.setContentDispositionFormData("attachment", filename);
    // 第二个放在 header 中的键值对 media-type=xxxx
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(
            bytes,          // 响应体中携带的数据
            headers,        // 响应头
            HttpStatus.OK); // 响应行中的状态码

    return responseEntity;
}
相关推荐
liu_chunhai11 分钟前
设计模式(3)builder
java·开发语言·设计模式
ya888g1 小时前
GESP C++四级样题卷
java·c++·算法
【D'accumulation】1 小时前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
小叶学C++1 小时前
【C++】类与对象(下)
java·开发语言·c++
2401_854391081 小时前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss1 小时前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
wxin_VXbishe1 小时前
springboot合肥师范学院实习实训管理系统-计算机毕业设计源码31290
java·spring boot·python·spring·servlet·django·php
Cikiss1 小时前
微服务实战——平台属性
java·数据库·后端·微服务
无敌の星仔1 小时前
一个月学会Java 第2天 认识类与对象
java·开发语言
OEC小胖胖2 小时前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web