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;
}
相关推荐
2401_857610032 分钟前
Spring Boot框架:电商系统的技术优势
java·spring boot·后端
LuckyLay17 分钟前
Spring学习笔记_34——@Controller
spring·controller
希忘auto18 分钟前
详解MySQL安装
java·mysql
冰淇淋烤布蕾29 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺35 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE1 小时前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)1 小时前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
ApiHug2 小时前
ApiSmart x Qwen2.5-Coder 开源旗舰编程模型媲美 GPT-4o, ApiSmart 实测!
人工智能·spring boot·spring·ai编程·apihug
杨哥带你写代码2 小时前
网上商城系统:Spring Boot框架的实现
java·spring boot·后端