网站建设需要哪些硬件,软文价格,电子商务网站建设与规划教案,短视频分享网站开发此处后端使用的是前期封装的自定义starter#xff0c;具体链接可参考#xff1a;minio对象存储spring boot starter封装组件 这里主要针对前期封装的组件#xff0c;做一个简单的应用#xff0c;前端直传可查看之前的文章
秒传
秒传的逻辑比较简单#xff0c;在前传上传…此处后端使用的是前期封装的自定义starter具体链接可参考minio对象存储spring boot starter封装组件 这里主要针对前期封装的组件做一个简单的应用前端直传可查看之前的文章
秒传
秒传的逻辑比较简单在前传上传之前先获取到对应文件的md5传给后端后端校验md5是否已经存在存在则直接提示上传成功否则发起文件上传请求
获取文件MD5前端可以使用spark-md5或者crypto-js
el-upload classupload-demo drag action# :http-requestsparkUploadHandle :show-file-listfalseel-icon classel-icon--uploadUploadFilled //el-icondiv classel-upload__text将文件拖到此处或em点击上传/em/div
/el-upload对应的处理逻辑
script setup langts
import { ElMessage } from element-plus
import SparkMD5 from spark-md5
import { checkMd5 } from /api/file
import { UploadFilled } from element-plus/icons-vueconst sparkUploadHandle (param: any) {const file param.fileconst fileReader new FileReader()const Spark new SparkMD5.ArrayBuffer()fileReader.readAsArrayBuffer(file)fileReader.onload function (e) {Spark.append(e.target.result)const md5 Spark.end()ElMessage.success(文件MD5 md5)//上传逻辑处理const data {md5: md5,fileName: file.name}checkMd5(data).then(resp {if (resp.code 201) {ElMessage.success(秒传成功)} else {ElMessage.info(后台无数据正在上传中....)//请求上传接口}})}
}
/scriptcheckMd5就是请求后端接口查看是否存在
分片上传
这里使用的是前端直传方式的分片上传处理逻辑前端根据指定的大小对文件进行分片分片完成后根据文件名和分片数量去请求后端获得对应的分片上传地址集合再根据返回的地址集合进行前端直传传完后调用后端接口合并分片
后端接口
后端拿到对应的文件名称分片大小和文件类型然后返回给前端对应的put直传地址集合每个直传地址默认10分钟的有效期 Autowiredprivate MinioService minioService;GetMapping(/part-url)public RestResultMultiPartUploadInfo partUrl(RequestParam String fileName,RequestParam int partSize, RequestParam String contentType) throws MinioException {MultiPartUploadInfo uploadInfo minioService.initMultiPartUploadId(bucketName, fileName, partSize, contentType);return RestResult.ok(uploadInfo);}GetMapping(/merge-part)public RestResultString mergePart(RequestParam String fileName, RequestParam String uploadId) throws MinioException {String merge minioService.mergeMultiPartUpload(bucketName, fileName, uploadId);return RestResult.ok(merge);}前端
el-upload classupload-demo drag action# :http-requestpartUploadHandle :show-file-listfalseel-icon classel-icon--uploadUploadFilled //el-icondiv classel-upload__text将文件拖到此处或em点击上传/em/div
/el-uploadimport { reactive } from vue
import service from /utils/request
import { getPartUrl, mergePart } from /api/file
import { UploadFilled } from element-plus/icons-vueconst state reactive({uploadId:
})
//分片大小
const chunkSize 50 * 1024 * 1024const partUploadHandle (param: any) {let file param.file// 正在创建分片let fileChunks createFileChunk(file)let data {fileName: file.name,partSize: fileChunks.length,contentType: file.type}//获得上传的urlgetPartUrl(data).then(resp {state.uploadId resp.data.uploadIdlet uploadUrls resp.data.uploadUrlsif (fileChunks.length ! uploadUrls.length) {ElMessage.error(文件分片上传地址获取错误)return}let chunkList []fileChunks.map((chunkItem, index) {chunkList.push({chunkNumber: index 1,chunk: chunkItem,uploadUrl: uploadUrls[index],progress: 0,status: —})})//上传分片uploadChunkBase(chunkList, file.type).then(resp {console.log(分片上传完成)let par {fileName: file.name,uploadId: state.uploadId}//请求后端合并分片mergePart(par).then(resp {ElMessage.info(上传成功访问地址 resp.data)})})})
}/*** 文件分片*/
const createFileChunk (file, size chunkSize) {const fileChunkList []let count 0while (count file.size) {fileChunkList.push({file: file.slice(count, count size)})count size}return fileChunkList
}
//分片上传
const uploadChunkBase (chunkList, contentType application/octet-stream) {let successCount 0let totalChunks chunkList.lengthreturn new Promisevoid((resolve, reject) {const handler () {if (chunkList.length) {const chunkItem chunkList.shift()// 直接上传二进制不需要构造 FormData否则上传后文件损坏service.put(chunkItem.uploadUrl, chunkItem.chunk.file, {headers: {Content-Type: contentType}}).then(response {if (response.status 200) {console.log(分片 chunkItem.chunkNumber 上传成功)successCount// 继续上传下一个分片handler()} else {// 注意这里没有针对失败做处理请根据自己需求修改console.log(上传失败 response.status response.statusText)}}).catch(error {// 更新状态console.log(分片 chunkItem.chunkNumber 上传失败 error)// 重新添加到队列中chunkList.push(chunkItem)handler()})}if (successCount totalChunks) {resolve()}}// 支持10个并发for (let i 0; i 10; i) {handler()}})
}utils/request是对axios的封装比如超时返回体错误码判断等等
对应的 api/file.ts
import service from /utils/request/** MD5校验 */
export const checkMd5 (params?: object) {return service.get(/oss/check, { params: params })
}/** 获取分片上传地址 */
export const getPartUrl (params?: object) {return service.get(/oss/part-url, { params: params })
}/** 分片合并 */
export const mergePart (params?: object) {return service.get(/oss/merge-part, { params: params, timeout: 10000 })
}至此分片上传即可使用
断点续传
这个其实就是在分片上传的基础做一个改进将上传完成的分片反馈给后端做记录再次续传时只传对应的未上传分片即可上传完成再请求后端合并。