- 作者简介
- 内容提要
- 关于本书
- 路线图
- 代码规范与下载
- 作者在线
- 封面插图简介
- 前言
- 译者序
- 致谢
- 第1部分 Spring 的核心
- 第1章 Spring 之旅
- 第2章 装配 Bean
- 第3章 高级装配
- 第4章 面向切面的 Spring
- 第2部分 Web 中的 Spring
- 第5章 构建 Spring Web 应用程序
- 第6章 渲染 Web 视图
- 第7章 Spring MVC 的高级技术
- 第8章 使用 Spring Web Flow
- 第9章 保护 Web 应用
- 第3部分 后端中的 Spring
- 第10章 通过 Spring 和 JDBC 征服数据库
- 第11章 使用对象-关系映射持久化数据
- 第12章 使用 NoSQL 数据库
- 第13章 缓存数据
- 第14章 保护方法应用
- 第4部分 Spring 集成
- 第15章 使用远程服务
- 第16章 使用 Spring MVC 创建 REST API
- 第17章 Spring消息
- 第18章 使用 WebSocket 和 STOMP 实现消息功能
- 第19章 使用 Spring 发送 Email
- 第20章 使用 JMX 管理 Spring Bean
- 第21章 借助 Spring Boot 简化 Spring 开发
7.2.2 处理 multipart 请求
现在已经在Spring中(或Servlet容器中)配置好了对mutipart请求的处理,那么接下来我们就可以编写控制器方法来接收上传的文件。要实现这一点,最常见的方式就是在某个控制器方法参数上添加@RequestPart注解。
假设我们允许用户在注册Spittr应用的时候上传一张图片,那么我们需要修改表单,以允许用户选择要上传的图片,同时还需要修改SpitterController 中的processRegistration()方法来接收上传的图片。如下的代码片段来源于Thymeleaf注册表单视图(registrationForm.html),着重强调了表单所需的修改:
<form>标签现在将enctype属性设置为multipart/form-data,这会告诉浏览器以multipart数据的形式提交表单,而不是以表单数据的形式进行提交。在multipart中,每个输入域都会对应一个part。
除了注册表单中已有的输入域,我们还添加了一个新的<input>域,其type为file。这能够让用户选择要上传的图片文件。accept属性用来将文件类型限制为JPEG、PNG以及GIF图片。根据其name属性,图片数据将会发送到multipart请求中的profilePicture part之中。
现在,我们需要修改processRegistration()方法,使其能够接受上传的图片。其中一种方式是添加byte数组参数,并为其添加@RequestPart注解。如下为示例:
当注册表单提交的时候,profilePicture属性将会给定一个byte数组,这个数组中包含了请求中对应part的数据(通过@RequestPart指定)。如果用户提交表单的时候没有选择文件,那么这个数组会是空(而不是null)。获取到图片数据后,processRegistration()方法剩下的任务就是将文件保存到某个位置。
我们将会稍后讨论如何保存文件。但首先,想一下,对于提交的图片数据我们都了解哪些信息呢。或者,更为重要的是,我们还不知道些什么呢?尽管我们已经得到了byte数组形式的图片数据,并且根据它能够得到图片的大小,但是对于其他内容我们就一无所知了。我们不知道文件的类型是什么,甚至不知道原始的文件名是什么。你需要判断如何将byte数组转换为可存储的文件。
接受MultipartFile
使用上传文件的原始byte比较简单但是功能有限。因此,Spring还提供了MultipartFile接口,它为处理multipart数据提供了内容更为丰富的对象。如下的程序清单展现了MultipartFile接口的概况。
程序清单7.5 Spring所提供的MultipartFile接口,用来处理上传的文件
我们可以看到,MultipartFile提供了获取上传文件byte的方式,但是它所提供的功能并不仅限于此,还能获得原始的文件名、大小以及内容类型。它还提供了一个InputStream,用来将文件数据以流的方式进行读取。
除此之外,MultipartFile还提供了一个便利的transferTo()方法,它能够帮助我们将上传的文件写入到文件系统中。作为样例,我们可以在process-Registration()方法中添加如下的几行代码,从而将上传的图片文件写入到文件系统中:
将文件保存到本地文件系统中是非常简单的,但是这需要我们对这些文件进行管理。我们需要确保有足够的空间,确保当出现硬件故障时,文件进行了备份,还需要在集群的多个服务器之间处理这些图片文件的同步。
将文件保存到Amazon S3中
另外一种方案就是让别人来负责处理这些事情。多加几行代码,我们就能将图片保存到云端。例如,如下的程序清单所展现的saveImage()方法能够将上传的文件保存到Amazon S3中,我们在processRegistration()中可以调用该方法。
程序清单7.6 将MultipartFile保存到Amazon S3中
saveImage()方法所做的第一件事就是构建Amazon Web Service(AWS)凭证。为了完成这一点,你需要有一个S3 Access Key和S3 Secret Access Key。当注册S3服务的时候,Amazon会将其提供给你。它们会通过值注入的方式提供给Spitter-Controller。
AWS凭证准备好后,saveImage()方法创建了一个JetS3t的RestS3Service实例,可以通过它来操作S3文件系统。它获取spitterImages bucket的引用并创建用来包含图片的S3Object对象,接下来将图片数据填充到S3Object。
在调用putObject()方法将图片数据写到S3之前,saveImage()方法设置了S3Object的权限,从而允许所有的用户查看它。这是很重要的——如果没有它的话,这些图片对我们应用程序的用户就是不可见的。最后,如果出现任何问题的话,将会抛出ImageUploadException异常。
以Part的形式接受上传的文件
如果你需要将应用部署到Servlet 3.0的容器中,那么会有MultipartFile的一个替代方案。Spring MVC也能接受javax.servlet.http.Part作为控制器方法的参数。如果使用Part来替换MultipartFile的话,那么processRegistration()的方法签名将会变成如下的形式:
就主体来言(不开玩笑地说),Part接口与MultipartFile并没有太大的差别。在如下的程序清单中,我们可以看到Part接口的有一些方法其实是与MultipartFile相对应的。
程序清单7.7 Part接口:Spring MultipartFile的替代方案
在很多情况下,Part方法的名称与MultipartFile方法的名称是完全相同的。有一些比较类似,但是稍有差异,比如getSubmittedFileName()对应于getOriginalFilename()。类似地,write()对应于transferTo(),借助该方法我们能够将上传的文件写入文件系统中:
值得一提的是,如果在编写控制器方法的时候,通过Part参数的形式接受文件上传,那么就没有必要配置MultipartResolver了。只有使用MultipartFile的时候,我们才需要MultipartResolver。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论