您好,我是湘王,这是我的51CTO博客。值此新春佳节,我给您拜年啦~祝您在新的一年中所求皆所愿,所行皆坦途,展宏“兔”,有钱“兔”,多喜乐,常安宁!
开发中有一类应用会出现的比较多,就是文件上传,尤其是图片上传。现在一般都用云存储的方式上传图片,然后返回给前端存储地址。但是如果需要将文件或图片存储到自己的服务器上去,也可以直接使用Commons库提供的commons-fileupload工具,不用自己造轮子。
首先创建SpringBoot项目,然后添加依赖:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
声明:版本随意,只要能正常运行就行。
然后写一个用于文件上传的Controller:
如果仅仅只是文件上传,那么整个功能就已经完成了。但是为了更友好的体验,需要直观的看到上传进度,所以需要继续加入能查看进度的接口:
在application.properties文件中加入一行属性:
file.path=/home/work/
表示文件上传后的物理存储路径。
接着创建上传进度监听器:
再自定义上传解析器:
创建解析器的配置:
用Postman测试,选择切换到Body -> 选择form-data -> key选择File类型:
再在Postman中测试进度获取接口:
测试时需要注意:
1、先调用/percent接口一次,之后再调用/upload接口。如果先调用/upload,再调用/percent,是看不到进度数据的。这是因为需要预先建立起会话,才能记录进度;而如果先上传的话,因为上传会占用整个进程,一直到上传结束,才会完成session会话的初始化;
2、最好上传大文件,方便观测效果;
3、在上传过程中,连续调用/percent接口,可以看到上传进度数据不断变化。
第一次也可以调用/upload,但直到/upload完成上传之前,调用/percent都没响应。第一次的/upload完成后,第二次调用/upload,再调用/percent就可以看到效果了
关于上传,还有两个比较重要的功能也顺带讲一下。
一是断点续传。例如迅雷的断点续传:
它的核心逻辑是:
1、传输开始时,前端/客户端会将传输文件按固定大小划分为若干个分块,每一个分块由一个线程负责完成传输过程,这些线程可以按照一定策略串行或并行执行传输,每个分块传输任务都有自己的传输状态;
2、传输之前,前端/客户端会将每个分块的校验和checksum发送给服务端保存,当某个分块传输完成后,服务端会将已传输分块的checksum与之前已保存的checksum进行比对,以判断传输是否真正完成,如果完成则更新任务传输状态为已完成;
3、如果在分块文件传输的过程中发生网络故障或系统异常需要重新传输时,服务端会给前端/客户端返回那些未完成的分块编码,前端/客户端只需要在本地将未完成的分块重新发送给服务端就行了;
4、当所有部分传输完成后,服务端依据编码排序将各个分块进行合并,最终形成一个完整的上传或下载文件;
5、分块大小必须适当,太小可能会给系统性能造成影响,太大又会使续传效果大打折扣。
实现断点续传的逻辑并不复杂,但是过程却比较麻烦,而且需要前端/客户端的紧密配合。目前比较主流的方案是前端webuploader + 后端commoms-io和commoms-fileupload,也有一些github开源的项目已经实现。
另一种是秒传。它的核心逻辑是:
1、每次上传文件时,服务器都会先做文件的MD5校验;
2、如果之前已经向服务器上传过一份文件,当再次重传这份文件,那么它的MD5肯定就和服务器上文件的MD5是一样的。
秒传的核心逻辑就是通过判断MD5是否相同来实现的,如果是同一份文件,那么MD5肯定相同,所以服务器会认为文件已上传完成,直接返回成功。反之,只要让待上传文件的MD5改变(就是对文件本身做一下修改,光改名字不行),例如文本文件,哪怕多加一个字,MD5就变了,秒传就无法实现了。
只要是实现了断点续传,那么秒传就已经等同于实现了,因为秒传只需要借助断点续传的checksum验证接口就行了。
节日期间,您仍然可以随时咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~再次祝您兔年吉祥,万事胜意!