实现思路:
后端:
准备好两个接口 1. 获取文件信息
2.分片获取文件信息
前端:
1.点击导出按钮拿到文件调用获取文件信息接口。
2.拿到文件信息按照1M(自定义大小一般为1m)大小切割文件大小,拿到文件得开始跟结束得数据push到数组。
3.根据数组得长度循环调用分片获取文件信息接口,使用Promise.all下载文件。
代码实现:
一、点击按钮
<el-button @click="downloadBtn(row)">下载导入文件</el-button>
//点击按钮
二、准备好两个接口,分片下载接口设置 ”responseType: "blob"“,该接口已经过封装只做展示作用。
//通过文件ID获取文件信息
export const getStatFileByFileId = (params) => {
return http.get(PORT + `/XXX/statFileByFileId`, params, { });
};
//分片下载文件接口
export const getRangeDownloadByFileId = (params) => {
return http.post(PORT + `/XXX/rangeDownloadByFileId`, params,{ responseType: "blob"});
};
三、文件类型匹配.js/.ts文件存放,使用得时候导入,文件类型可以由获取文件信息接口直接获取,本接口后端偷懒文件信息里面只有文件得大小信息,而且table列表中有文件类型字段。
/**
* 文件下载HHTS类型
*/
export const BlobMap: Map<string, string> = new Map([
["ppt", "application/vnd.ms-powerpoint"],
["pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"],
["xls", "application/vnd.ms-excel"],
["xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
["doc", "application/msword"],
["docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
["rar", "application/rar"],
["tar", "application/x-tar"],
["tgz", "application/x-tar"],
["zip", "application/zip"],
["7zip", "application/zip"],
["gz", "application/x-gzips"],
["gzip", "application/x-gzip"],
["rtf", "application/rtf"],
["js", "javascript/js"],
["css", "text/css"],
["pdf", "application/pdf"],
["gif", "image/gif"],
["jpg", "image/pjpeg"],
["jpg2", "image/jp2"],
["png", "image/jp2"],
["tif", "image/tiff"],
["tiff", "image/tiff"],
["bmp", "image/bmp"],
["svg", "image/svg+xml"],
["svgz", "image/svg+xml"],
["webp", "image/svg+xml"],
["ico", "image/x-icon"],
["wps", "application/kswps"],
["psd", "application/x-photoshop"],
["swf", "application/x-photoshop"],
["txt", "text/plain"],
["htm", "text/html"],
["html", "text/html"],
["xml", "text/xml"],
["jar", "application/java-archive"],
["DEFAULT", "application/octet-stream"],
]);
三、主要代码实现
import { BlobMap } from "@/enums/httpBlobType";//导入文件类型Map结构
import { getRangeDownloadByFileId, getStatFileByFileId }from"@/api/modules/XXXX"; //导入接口
const downloadLogic = async (row) => {
const { data } = await getStatFileByFileId({ fileId: row.id }); //获取文件大小接口
const length = data["length"]; //文件大小 单位字节
const chunk = 1024 * 1024; // 定义每个片段的大小为1M
let size = Math.ceil(length / chunk); // 定义文件需要分成多次片 文件大小 / 定义每个片段的大小为1M = 请求次数
// 文件分割为数组
const chunks = [];
let start = 0;
let end = 0;
for (let i = 0; i < size; i++) {
end = start + chunk;
if (end > length) {
end = length;
}
let item = {
fileId: row.id,//文件ID
startIndex: start,//起始下载游标
endIndex: end,//截止下载游标
};
chunks.push(getRangeDownloadByFileId({ data: item})); //分片下载文件接口
start = end;
}
let type = BlobMap.get(row.userType); //根据当前选中行 文件类型 字段匹配 下载文件类型
Promise.all(chunks)
.then((res) => {
let blob = new Blob(res, {
type,
});
// type是文件类,详情可以参阅blob文件类型
// 创建新的URL并指向File对象或者Blob对象的地址
const blobURL = window.URL.createObjectURL(blob);
// 创建a标签,用于跳转至下载链接
const tempLink = document.createElement("a");
tempLink.style.display = "none";
tempLink.href = blobURL;
let fileName = row.userName; 根据当前选中行 文件名称 字段匹配 下载文件名称
tempLink.setAttribute("download", fileName);
// 兼容:某些浏览器不支持HTML5的download属性
if (typeof tempLink.download === "undefined") {
tempLink.setAttribute("target", "_blank");
}
// 挂载a标签
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
// 释放blob URL地址
window.URL.revokeObjectURL(blobURL);
ElNotification.closeAll()
alert('下载完成')
})
}
注意!!
一定要跟后端说话分片请求数据起始下载游标跟截止下载游标的规则
一、[ {startIndex: 1, endIndex: 2},{startIndex: 2, endIndex: 3,}]
二、 [ {startIndex: 1, endIndex: 2},{startIndex: 3, endIndex: 4,}]
在有概率上的压缩包下载会有问题,导致多请求数据或者少请求数据!!!
四、嘿嘿嘿点赞写Bug-1,看到给个赞呗大佬!!!