Springboot + Vue实现大文件切片上传

大文件切片上传原理就是将一个大文件分成若干份大小相等的块文件,等所有块上传成功后,再将文件进行合并。

一、Springboot后端

1.实体TChunkInfo.java

import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable;
@Data
public class TChunkInfo implements Serializable {private static final long serialVersionUID = 1L;private String id;// 当前文件块,从1开始private Integer chunkNumber;// 每块大小private Long chunkSize;// 当前分块大小private Long currentChunkSize;// 总大小private Long totalSize;// 文件标识private String identifier;// 文件名private String filename;// 相对路径private String relativePath;// 总块数private Integer totalChunks;// 文件类型private String type;// 块内容private transient MultipartFile upfile;}

2.实体TFileInfoVO.java

import java.io.Serializable;
/*** 文件模型参数* @author YouZ*/
@Data
public class TFileInfoVO implements Serializable {private static final long serialVersionUID = 1L;//附件编号private String id;//附件类型private String fileType;//附件名称private String name;//附件总大小private Long size;//附件地址private String relativePath;//附件MD5标识private String uniqueIdentifier;//附件所属项目IDprivate String refProjectId;}

3.文件切片上传及切片合并接口

@RestController
@RequestMapping("/uploader")
public class FileController {private static String FILENAME = "";@Value("${YouZ.upload.file.path}")private String decryptFilePath;@Value("${YouZ.upload.file.temp}")private String decryptFilePathTemp;/*** 上传文件块* @param chunk* @return*/@PostMapping("/chunk")public String uploadChunk(TChunkInfo chunk) throws IOException{String apiRlt = "200";MultipartFile file = chunk.getUpfile();String guid = chunk.getIdentifier();Integer chunkNumber = chunk.getChunkNumber();System.out.println("guid:" + guid);File outFile = new File(decryptFilePathTemp+File.separator+guid, chunkNumber + ".part");if ("".equals(FILENAME)) {FILENAME = chunk.getFilename();}InputStream inputStream = file.getInputStream();FileUtils.copyInputStreamToFile(inputStream, outFile);return apiRlt;}@PostMapping("/mergeFile")public String mergeFile(@RequestBody TFileInfoVO fileInfoVO) throws Exception{String rlt = "FALURE";String guid = fileInfoVO.getUniqueIdentifier();System.out.println("merge:"+guid);File file = new File(decryptFilePathTemp+File.separator+guid);if (file.isDirectory()) {File[] files = file.listFiles();if (files != null && files.length > 0) {File partFile = new File(decryptFilePath + File.separator + FILENAME);for (int i = 1; i <= files.length; i++) {File s = new File(decryptFilePathTemp+File.separator+guid, i + ".part");FileOutputStream destTempfos = new FileOutputStream(partFile, true);FileUtils.copyFile(s,destTempfos );destTempfos.close();}FileUtils.deleteDirectory(file);FILENAME = "";}}return rlt;}
}

二、Vue前端

1.注册组件(main.js)

使用vue-uploader;一个基于vue的uploader组件,缺省就是分片上传。

import uploader from 'vue-simple-uploader'
Vue.use(uploader)

2.上传器

<!-- 上传器 -->
<uploaderref="uploader":options="options":autoStart=false:file-status-text="fileStatusText"@file-added="onFileAdded"@file-success="onFileSuccess"@file-error="onFileError"class="uploader-ui"><uploader-unsupport></uploader-unsupport><uploader-drop><div><uploader-btn id="global-uploader-btn" :attrs="attrs" ref="uploadBtn">选择文件<i class="el-icon-upload el-icon--right"></i></uploader-btn></div></uploader-drop><uploader-list></uploader-list>
</uploader>

变量

import SparkMD5 from 'spark-md5';
import { getToken } from '@/utils/auth'
import {mergeFile} from "@/api/fastLoader/uploadFile";
data() {return {options: {headers: {Authorization: 'Bearer ' + getToken()},//目标上传 URL,默认POSTtarget: process.env.VUE_APP_BASE_API+'/uploader/chunk',//分块大小(单位:字节)chunkSize: '20480000',//上传文件时文件内容的参数名,对应chunk里的Multipart对象名,默认对象名为filefileParameterName: 'upfile',//失败后最多自动重试上传次数maxChunkRetries: 3,//是否开启服务器分片校验,对应GET类型同名的target URLtestChunks: false,/*服务器分片校验函数,判断秒传及断点续传,传入的参数是Uploader.Chunk实例以及请求响应信息reponse码是successStatuses码时,才会进入该方法reponse码如果返回的是permanentErrors 中的状态码,不会进入该方法,直接进入onFileError函数 ,并显示上传失败reponse码是其他状态码,不会进入该方法,正常走标准上传checkChunkUploadedByResponse函数直接return true的话,不再调用上传接口*/checkChunkUploadedByResponse: function (chunk, response_msg) {let objMessage = JSON.parse(response_msg);if (objMessage.skipUpload) {return true;}return (objMessage.uploadedChunks || []).indexOf(chunk.offset + 1) >= 0;}},attrs: {accept: ACCEPT_CONFIG.getAll()},fileStatusText: {success: '上传成功',error: '上传失败',uploading: '上传中',paused: '暂停',waiting: '等待上传'},}
}

回调函数

methods: {// 上传onFileAdded(file) {this.computeMD5(file);},/*第一个参数 rootFile 就是成功上传的文件所属的根 Uploader.File 对象,它应该包含或者等于成功上传文件;第二个参数 file 就是当前成功的 Uploader.File 对象本身;第三个参数就是 message 就是服务端响应内容,永远都是字符串;第四个参数 chunk 就是 Uploader.Chunk 实例,它就是该文件的最后一个块实例,如果你想得到请求响应码的话,chunk.xhr.status就是*/onFileSuccess(rootFile, file, response, chunk) {//refProjectId为预留字段,可关联附件所属目标,例如所属档案,所属工程等file.refProjectId = "123456789";mergeFile(file).then( response=> {if(responseData.data.code === 200){console.log("合并操作未成功,结果码:"+responseData.data.code);}}).catch(function (error){console.log("合并后捕获的未知异常:"+error);});},onFileError(rootFile, file, response, chunk) {console.log('上传完成后异常信息:'+response);},error(msg) {this.$notify({title: '错误',message: msg,type: 'error',duration: 2000})}
}

计算md5,实现断点续传及秒传

/*** 计算md5,实现断点续传及秒传* @param file*/
computeMD5(file) {file.pause();//单个文件的大小限制2Glet fileSizeLimit = 2 * 1024 * 1024 * 1024;console.log("文件大小:"+file.size);console.log("限制大小:"+fileSizeLimit);if(file.size > fileSizeLimit){this.$message({showClose: true,message: '文件大小不能超过2G'});file.cancel();}let fileReader = new FileReader();let time = new Date().getTime();let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;let currentChunk = 0;const chunkSize = 20 * 1024 * 1000;let chunks = Math.ceil(file.size / chunkSize);let spark = new SparkMD5.ArrayBuffer();//由于计算整个文件的Md5太慢,因此采用只计算第1块文件的md5的方式let chunkNumberMD5 = 1;loadNext();fileReader.onload = (e => {spark.append(e.target.result);if (currentChunk < chunkNumberMD5) {loadNext();} else {let md5 = spark.end();console.log(md5);file.uniqueIdentifier = md5;file.resume();console.log(`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);}});fileReader.onerror = function () {this.error(`文件${file.name}读取出错,请检查该文件`)file.cancel();};function loadNext() {let start = currentChunk * chunkSize;let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));currentChunk++;console.log("计算第"+currentChunk+"块");}
},

前后端分离的大文件切片上传就完成了;这里需要注意的是因为合并方法需要的时间久,会超时;需要将超时时间写大一点。

// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 30000
})

Springboot + Vue实现大文件切片上传相关推荐

  1. Vue实现大文件分片上传,包括断点续传以及上传进度条

    首先解释一下什么是分片上传 分片上传就是把一个大的文件分成若干块,一块一块的传输.这样做的好处可以减少重新上传的开销.比如:如果我们上传的文件是一个很大的文件,那么上传的时间应该会比较久,再加上网络不 ...

  2. vue实现大文件分片上传断点续传并展示上传进度条

    最近有一个上传视频到服务器的功能,然后发现视频太大了,比如1个G的视频文件基本都是上传失败的,我之前都是上传阿里云的,所以面对大文件上传服务器就做了分片上传和断点续传. 首先解释什么是分片上传:比如一 ...

  3. 大文件切片上传、视频切片上传转m3u8播放

    一.故事 前不久干项目,涉及到在线学习,简单来说就是对文章.视频进行在线学习,这个时候问题出现了,就是在上传视频的时候,速度很是慢,除此之外,视频播放也是卡的鸭皮,然后就开始疯狂网上搜刮知识,最终解决 ...

  4. chrome java上传文件_springboot+webuploader 实现大文件切片上传,兼容IE8+,chrome等浏览器,可运行...

    [实例简介] https://blog.csdn.net/weifangzjx/article/details/83898265 [实例截图] [核心代码] 上传例子 └── 上传例子 └── fil ...

  5. jquery 分片上传php,jquery 大文件分片上传插件 fcup.js

    软件介绍 fcup.js fcup 是一款支持大文件切片上传插件.该jquery插件使用简单,配置简单明了,支持上传类型指定,进度条查看上传进度.. 安装 直接下载源码,上传功能需要php环境,演示地 ...

  6. Vue项目中遇到了大文件分片上传的问题

    Vue项目中遇到了大文件分片上传的问题,之前用过webuploader,索性就把Vue2.0与webuploader结合起来使用,封装了一个vue的上传组件,使用起来也比较舒爽. 上传就上传吧,为什么 ...

  7. vue大文件分片上传插件

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  8. 请问:怎么实现大文件快速上传?

    关注公众号 前端开发博客,领27本电子书 回复加群,自助秒进前端群 前言 大文件快速上传的方案,相信你也有过了解,其实无非就是将 文件变小,也就是通过 压缩文件资源 或者 文件资源分块 后再上传. 本 ...

  9. 大文件分片上传前端框架_基于Node.js的大文件分片上传

    基于Node.js的大文件分片上传 我们在做文件上传的时候,如果文件过大,可能会导致请求超时的情况.所以,在遇到需要对大文件进行上传的时候,就需要对文件进行分片上传的操作.同时如果文件过大,在网络不佳 ...

最新文章

  1. freebsd+postfix+mysql+authdaemon+sasl2+bind9
  2. android sqlite 自增长序列号归0
  3. python扫描端口脚本_Python端口扫描简单程序
  4. 利用colab保存模型_在Google Colab上训练您的机器学习模型中的“后门”
  5. 阿里云三维可视化使用初体验
  6. 为什么遇见逆水寒服务器维修,《遇见逆水寒》4月23日更新公告
  7. SAP License:SAP关键用户职责
  8. Julia: readdlm
  9. 清除Mac电脑缓存的方法,非常实用哦
  10. SpringBoot整合Redis + SpringCache + Protobuf,优雅地实现key-value键值对存储DEMO。
  11. 通配符 或 怎么浓_浓咖啡的咖啡渣新鲜度
  12. 达人评测 i7 13700和i7 12700选哪个
  13. 搭建Vue3 后台管理框架 —— 登录页面
  14. ubuntu 22.04下载wine及一些问题
  15. GSM Communication on EBox4300--(3)
  16. springBoot启动事件监听机制
  17. 如何让一个div水平垂直居中
  18. 移动硬盘插入提示需要格式化RAW_超级硬盘数据恢复格式化数据还原免注册版,回011获取...
  19. 如何得到PyTorch中张量的值?
  20. 阿里Mycat 和京东ShardingSphere:分布式数据库中间件哪家强?

热门文章

  1. 【Linux】浅谈线程
  2. OpenSSL密码库算法笔记——第6.2.1章 ECDSA_SIG结构体
  3. 《网络空间内生安全》读书笔记:第四章 防御理念与技术新进展
  4. Valens VS2000 系列HDBaseT2.0延长芯片
  5. TortoiseGit 使用ssh相关问题
  6. 智能电视聚好看连接服务器失败,海信电视不能使用当贝市场的两种解决办法,亲测推荐分享...
  7. java仿qq 界面_界面--仿qq登录界面
  8. 趣味点名软件_趣味点名 妙趣横生——三都中心幼儿园趣味点名活动
  9. 最新 Ubuntu20.04 配置安装 | 虚拟机配置及各类软件安装(wps,pycharm, mysql,docker等)
  10. 如果在基类中将show声明为不带返回值的纯虚函数,正确的写法是()。