开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天。点击查看活动详情
🍓 1 前端部分
-  上传附件:可上传多个,上传将会触发多次进度条。
-  批量下载:选择需要下载的多个附件。
-  批量删除:选择需要删除的多个附件。
-  文件下载:可直接在列表下载对应附件。
-  文件重命名:重命名附件名称,直接在列表标题触发input修改。
-  文件删除:可直接在列表删除对应附件。
-  文件预览:由于xlsx、pdf插件的兼容性问题,本组件只支持docx(插件实现)、pdf(浏览器预览)的预览。
-  文件上传进度:监听每个分片上传进度,及时渲染当前进度数值。
🍓 2 后端部分
-  验证附件分片api:验证是否已存在已上传的分片,不用再次请求,只上传未上传的分片。api响应回来的是两个字段:是否已上传所有分片,以及已上传的分片数组。
-  上传附件分片api:附件验证后触发的api,作用于上传分片。
-  合并附件分片api:所有附件分片上传后触发的api,作用于合并附件分片。
-  删除附件api:删除附件信息,以及存在本地服务器的文件。
-  获取附件列表api:获取所有附件。
-  获取附件信息api:获取存到数据库的一些附件信息。
-  下载附件api:需要响应种类为'blob'。
1 前端部分:
1.1 上传附件
- 
handleFileChange:input支持批量上传,所以需要在回调函数进行遍历上传附件,触发handleUpload函数。Array.prototype.slice.call(arguments)能将具有length属性的对象(key值为数字)转成数组<input type="file" multiple="multiple" class="upload-input" @change="handleFileChange($event)"/>
- 
handleUpload方法:获取文件的hash值、创建附件分片、验证上传的文件、上传分片。
1.2 获取文件的hash值
- 
spark-MD5:从文件0字节开始切片,按照设定的分片长度,一般为2MB。原理是计算文件分片数,创建SparkMD5对象调用ArrayBuffer存储分片,通过全局对象File的slice方法对文件从头到尾进行切片,直到扫描完文件的所有字节,才去获取文件Hash值(全量hash值)。
- 
spark-MD5+Worker(线程):通过Worker创建线程,在主线程中通过PostMessage传递需要处理的文件数据,在子线程中通过onMessage监听主线程传来的文件数据,对相关数据进行spark-MD5。(不展示详细的子线程代码,后面有源码),其实这种方法就是把spark-Md5生成hash值的计算放在了子线程中,大大提升主线程执行效率。 
- 
sample(抽样hash,用法最优):通过抽样提取文件的字节,对提取的字节进行拼接,最终通过ArrayBuffer对象对拼接字节储存,最后也是通过spark-MD5生成文件相应的hash值。抽样提取分片字节原理如图所示:通过抽取开头结尾分片长度字节,中间取小部分字节块,这样就大大提升解析文件获取Hash值的效率了。 
- 
sample+Worker(线程):主线程实现与全量hash使用worker是类似的,同样是把抽样获取hash的值计算放在线程中执行了。 
1.3 附件分片
- 
创建附件的分片:很简单,通过把文件切成多个分片长度的文件块,命名按照hash+index进行命名然后存到数组中。 
- 
验证上传的附件分片:通过传递文件hash值、文件名称在本地服务器中查询相关已上传的相关分片文件,api会响应两个字段,当前附件所有分片是否已上传或者文件已存在,如果只是上传了一部分会响应已上传的分片名称数组。验证上传分片一般是用来验证中断上传后恢复、上传一般出现网络问题导致上传中断后恢复、一开始上传附件验证文件是否上传三种情况需要调用验证方法。 
1.4 上传分片
上传分片:判断当前已上传的分片数组长度是否与当前文件分片数组长度是否一致,一致就已上传,否则取未上传的分片。
- 
并发控制:在上传分片的过程中会对分片上传做一些并发控制,为什么需要并发控制(并发控制是确保及时纠正由并发操作导致的错误的一种机制)?假如文件以G为单位时,分片可能存在几百个,如果几百个分片上传请求一起执行可能会导致一些问题的出现,而附件业务往往都需要并发控制频繁请求上传执行。 
- 
监听进度:通过axios所封装的onUploadProgress上传进度事件实时监听每个分片上传占文件百分比。 
- 
合并已上传的分片: 
2 后端部分:
- 运用Nodejs+MongoDB封装了上传附件过程需要用到的一系列api:由于代码量不少,这里就不一一展开说了,主要讲一下上传分片与合并分片,(其他代码可以直接拿后面源码)
2.1 上传分片api
- 
上传分片api:由于前端是formData对象存的文件数据,所以后端需要通过multiparty解析文件相关数据,这里用到fs-extra插件(对path二次封装,有很多丰富文件处理方法)对文件进行存储,这里有两个路径一个临时存储分片文件和一个存储最终合并的文件。通过fs内置方法判断上传的分片信息是否已存在有合并的文件以及当前上传分片是否存在。 
2.1 合并分片api
- 
对分片进行排序,防止目录获取的分片错乱。 
- 
读取分片当前路径下的所有内容数组。 
- 
把目录下的所有分片转化成文件路径数组,方便访问。 
- 
把所有分片逐一些入最终存储目录也就是attachment目录下。 
- 
调用Promise.all异步方法保证等所有分片已完成合并。 
- 
通过前端提交的文件信息,利用hash值拼接合并文件路径,判断当前路径是否已存在当前文件。 
- 
合并分片并删除temp临时分片路径目录。 
3 组件源码
gitee地址:gitee.com/wusheng_z/v…