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;
}
相关推荐
柯南二号7 分钟前
【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略
java·spring boot·mybatis
桦说编程7 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
lifallen7 小时前
Java Stream sort算子实现:SortedOps
java·开发语言
IT毕设实战小研7 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
没有bug.的程序员8 小时前
JVM 总览与运行原理:深入Java虚拟机的核心引擎
java·jvm·python·虚拟机
甄超锋9 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
阿华的代码王国9 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Zyy~9 小时前
《设计模式》装饰模式
java·设计模式
A尘埃9 小时前
企业级Java项目和大模型结合场景(智能客服系统:电商、金融、政务、企业)
java·金融·政务·智能客服系统
青云交9 小时前
Java 大视界 -- 基于 Java 的大数据可视化在城市交通拥堵治理与出行效率提升中的应用(398)
java·大数据·flink·大数据可视化·拥堵预测·城市交通治理·实时热力图