需要计算文件MD5和、分片MD5:
封装公共方法代码如下:
import SparkMD5 from "spark-md5"
/**
* 计算文件MD5
* @param file
* @returns
*/
export function calculateFileMD5(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = function (e) {
const spark = new SparkMD5.ArrayBuffer();
spark.append(e.target.result);
resolve(spark.end());
};
reader.readAsArrayBuffer(file);
})
}
/**
* 计算分片MD5
* @param chunk 当前切切片
* @returns
*/
export function calculateChunkMD5(chunk) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = function (e) {
const spark = new SparkMD5.ArrayBuffer();
spark.append(e.target.result);
resolve(spark.end());
};
reader.readAsArrayBuffer(chunk);
})
}
在上传页面调用:
<template>
<form id="uploadForm">
<div class="fileBox">
<span class="fileLabel">文件: </span>
<input type="file" id="file" name="file">
</div>
<el-progress id="progressBar" :percentage="progress" style="width: 335px;"></el-progress>
<button type="submit">提交</button>
</form>
</template>
<script setup>
import { calculateFileMD5, calculateChunkMD5 } from './calculateMd5'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import { getToken } from "@/utils/auth";
const emit = defineEmits(['send-upload'])
const uploadChunkUrl = ref(import.meta.env.VITE_APP_BASE_API + "/dbms/file/chunk"); //上传接口
const mergeUrl = ref(import.meta.env.VITE_APP_BASE_API + "/dbms/file/merge"); //合并接口
const file = ref(null)
const progress = ref(0)
async function uploadFile(file) {
const chunkSize = 5 * 1024 * 1024; // 5MB每片
const totalChunks = Math.ceil(file.size / chunkSize);
const fileMd5 = await calculateFileMD5(file); // 计算整个文件的MD5
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(file.size, start + chunkSize);
const chunk = file.slice(start, end);
const chunkMd5 = await calculateChunkMD5(chunk); // 计算当前分片的MD5
progress.value = Math.round((i / totalChunks) * 100) // 计算上传进度
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkNumber', i + 1);
formData.append('totalChunks', totalChunks);
formData.append('fileMd5', fileMd5);
formData.append('chunkMd5', chunkMd5);
formData.append('fileName', file.name);
await axios.post(uploadChunkUrl.value, formData, {
headers: { 'Content-Type': 'multipart/form-data', 'Authorization': 'Bearer ' + getToken() }
});
}
// 所有分片上传完成后,通知后端合并
const res = await axios.post(mergeUrl.value, {
fileMd5: fileMd5,
fileName: file.name,
totalChunks: totalChunks
});
// console.log(res)
if (res.status == 200) {
progress.value = 100
ElMessage.success('文件上传成功!')
// 上传成功 通知父组件关闭弹窗,清空下拉表单,更新列表数据
emit('send-upload')
}
}
onMounted(async () => {
/**触发上传**/
document.getElementById("uploadForm").onsubmit = async function (event) {
event.preventDefault();
const fileInput = document.getElementById("file");
file.value = fileInput.files[0];
if (!file.value) {
ElMessage.warning("请选择文件!")
return;
}
uploadFile(file.value)
}
})
</script>