7.1 文件上传
文件上传是项目开发当中最常用的功能。为了能上传文件,必须将表单的method
设置为POST
,并将enctype
设置为multipart/form-data
。只有在这种情况下,浏览器才会把用户选择的文件二进制数据发送给服务器。
一旦将enctype
设置为multipart/form-data
,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP
响应。2003年,Apache Software Foundation
发布了开源的Commons File Upload
组件,其很快成为Servlet/JSP
程序员上传文件的最佳选择。
Servlet3.0
规范的HttpServletRequest
已经提供了方法来处理文件上传,但这种上传需要在Servlet
中完成。而Spring MVC
则提供了更简单的封装。
Spring MVC
为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver
实现的。SpringMVC
使用ApacheCommonsFileUpload
技术实现了一个MultipartResolver
实现类:CommonsMultipartResolver
。因此,SpringMVC
的文件上传还需要依赖Apache Commons File Upload
的组件。
Apache Commons File Upload
的组件共有两个,最新版本分别是commons-fileupload-1.3.3.jar
和commons-io-2.6.jar
。
commons-fileupload-1.3.3.jar
的官网下载地址为:http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
。
commons-io-2.6.jar
的官网下载地址为:http://commons.apache.org/proper/commons-io/download_io.cgi
示例 Spring MVC的文件上传
Spring配置文件中添加配置
Spring MVC
上下文中默认没有装配MultipartResolver
,因此默认情况下其不能处理文件上传工作。**如果想使用Spring
的文件上传功能,则需要在上下文中配置MultipartResolver
**。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize"> <value>10485760</value> </property> <property name="defaultEncoding"> <value>UTF-8</value> </property> </bean>
|
引入CommonsFileUpload的jar包
需要注意的是,CommonsMultipartResolver
必须依赖于ApacheCommonsFileUpload
的组件,所以需要将Apache
的CommonsFileUpload
的jar
包放到项目的类路径下。
MultipartFile对象
Spring MVC
会将上传文件绑定到MultipartFile
对象。MultipartFile
提供了获取上传文件内容、文件名等方法。通过transferTo()
方法可以将文件上传。MultipartFile
对象中的常用方法如下:
方法 |
描述 |
byte[] getBytes() |
获取文件数据 |
String getContentType() |
获取文件MIME 类型,如image/jpeg 等 |
InputStream getInputStream() |
获取文件流 |
String getName() |
获取表单中文件组件的名称 |
Stringg etOriginalFilename() |
获取上传文件的原名 |
long getSize() |
获取文件的字节大小,单位为byte 。 |
boolean isEmpty() |
是否有上传的文件 |
void transferTo(Filedest) |
将上传文件保存到一个目标文件中。 |
error.jsp
1 2 3 4 5 6 7 8 9 10 11 12
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>测试文件上传</title> </head> <body> <strong>上传文件失败!</strong> </body> </html>
|
success.jsp
1 2 3 4 5 6 7 8 9 10 11 12
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>测试文件上传</title> </head> <body> <strong>上传文件成功!</strong> </body> </html>
|
负责上传文件的表单和一般表单有一些区别,**负责上传文件的表单的编码类型(enctype
)必须是”multipart/form-data
“**。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文件上传</title> </head> <body> <h2>文件上传</h2> <form action="upload" enctype="multipart/form-data" method="post"> <table> <tr> <td>文件描述:</td> <td><input type="text" name="description"></td> </tr> <tr> <td>请选择文件:</td> <td><input type="file" name="file"></td> </tr> <tr> <td><input type="submit" value="上传"></td> </tr> </table> </form> </body> </html>
|
测试链接
1
| <a href="uploadForm">Spring MVC的文件上传功能</a>
|
上传文件
输入文件描述信息并选择上传文件,如下图所示:
单击”上传
“按钮,文件会被上传并保存到服务器部署项目的images
文件夹下面。
上传效果
控制台输出
1 2
| 使用Spring MVC上传 上传文件路径:E:\apache-tomcat-8.5.35\webapps\FileUploadTest\images\2-2.jpg
|
进入该目录可以看到上传后的图片:
示例 使用对象接收上传文件
在实际的项目开发中,很多时候上传的文件会作为对象的属性被保存。Spring MVC
的处理也非常简单。
域对象
上传的图片将作为User对象的属性,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class User implements Serializable { private static final long serialVersionUID = 1L; private String username; private MultipartFile image; public User() { super(); } }
|
测试链接
1
| <a href="registerForm">用户头像上传功能</a>
|
请求处理方法
1 2 3 4 5 6
| @GetMapping(value = "/registerForm") public String registerForm() { return "registerForm"; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>用户注册</title> </head> <body> <h2>用户注册</h2> <form action="register" enctype="multipart/form-data" method="post"> <table> <tr> <td>用户名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>请上传头像:</td> <td><input type="file" name="image"></td> </tr> <tr> <td><input type="submit" value="注册"></td> </tr> </table> </form> </body> </html>
|
设置用户名和头像
注册请求处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @PostMapping(value = "/register")
public String register(HttpServletRequest request, @ModelAttribute User user, Model model) throws Exception { System.out.println(user.getUsername()); if (!user.getImage().isEmpty()) { String path = request.getServletContext().getRealPath("/images"); String filename = user.getImage().getOriginalFilename(); File filepath = new File(path, filename); if (!filepath.getParentFile().exists()) { filepath.getParentFile().mkdirs(); } user.getImage().transferTo(filepath); model.addAttribute("filename", user.getImage().getOriginalFilename()); System.out.println("上传文件路径:" + filepath.getAbsolutePath()); return "userInfo"; } else { return "error"; } }
|
userInfo.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文件下载</title> </head> <body> <h3>文件下载</h3> <br> <a href="javascript:window.location.href = 'download?filename=' + encodeURIComponent( '${requestScope.filename }' )"> ${requestScope.filename } </a> </body> </html>
|
点击链接,download请求处理方法将会被调用,实现下载图片.
示例 SpringMVC的文件下载
download请求处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @GetMapping(value = "/download") public ResponseEntity<byte[]> download(HttpServletRequest request, @RequestParam("filename") String filename, @RequestHeader("User-Agent") String userAgent) throws Exception { String path = request.getServletContext().getRealPath("/images"); File file = new File(path + File.separator + filename); BodyBuilder builder = ResponseEntity.ok(); builder.contentLength(file.length()); builder.contentType(MediaType.APPLICATION_OCTET_STREAM); filename = URLEncoder.encode(filename, "UTF-8"); if (userAgent.indexOf("MSIE") > 0) { builder.header("Content-Disposition", "attachment; filename=" + filename); } else { builder.header("Content-Disposition", "attachment; filename*=UTF-8''" + filename); } return builder.body(FileUtils.readFileToByteArray(file)); }
|
下载效果
SpringMVC
提供了一个ResponseEntity
类型,使用它可以很方便地定义返回的BodyBuilder
、HttpHeaders
和HttpStatus
。
download
处理方法接收到页面传递的文件名 filename
后,使用 Apache CommonsFileUpload
组件的 FileUtils
读取项目的 images
文件夹下的该文件,并将其构建成ResponseEntity
对象返回客户端下载。
使用 ResponseEntity
对象,可以很方便地定义返回的 BodyBuilder
、 HttpHeaders
和HttpStatus
,BodyBuilder
对象用来构建返回的Body
;类型代表的是Http
协议中的头信息;
在Http
协议消息头中,使用Content-Type
来表示具体请求中的媒体类型信息。有关BodyBuilder
、 MediaType
和HttpStatus
类的详细信息参考Spring MVC
的API
文档。