vue-simple-uploader上傳成功之後的response獲取程式碼
阿新 • • 發佈:2020-09-08
我就廢話不多說了,大家還是直接看程式碼吧~
<template> <uploader :options="options" :file-status-text="statusText" class="uploader-example" ref="uploader" @file-success="fileSuccess"></uploader> </template> <script> export default { data () { return { options: { target: '//localhost:3000/upload',// '//jsonplaceholder.typicode.com/posts/',testChunks: false },attrs: { accept: 'image/*' },statusText: { success: '成功了',error: '出錯了',uploading: '上傳中',paused: '暫停中',waiting: '等待中' } } },methods: { //上傳成功的事件 fileSuccess (rootFile,file,message,chunk) { console.log('complete',rootFile,chunk) } },mounted () { // 獲取uploader物件 this.$nextTick(() => { window.uploader = this.$refs.uploader.uploader }) } } </script>
補充知識:利用SpringBoot和vue-simple-uploader進行檔案的分片上傳
效果【上傳Zip檔案為例,可以自行擴充套件】
引入vue-simple-uploader
1.安裝上傳外掛
npm install vue-simple-uploader --save
2.main.js全域性引入上傳外掛
import uploader from 'vue-simple-uploader'
Vue.use(uploader)
3.安裝md5校驗外掛(保證上傳檔案的完整性和一致性)
npm install spark-md5 --save
頁面
<template> <div> <uploader :key="uploader_key" :options="options" class="uploader-example" :autoStart="false" @file-success="onFileSuccess" @file-added="filesAdded"> <uploader-unsupport></uploader-unsupport> <uploader-drop> <uploader-btn :single="true" :attrs="attrs">選擇Zip檔案</uploader-btn> </uploader-drop> <uploader-list></uploader-list> </uploader> </div> </template> <script> import SparkMD5 from 'spark-md5'; export default { data() { return { uploader_key: new Date().getTime(),options: { target: '/chunk/chunkUpload',testChunks: false,},attrs: { accept: '.zip' } } },methods: { onFileSuccess: function (rootFile,response,chunk) { console.log(JSON.parse(response).model); },computeMD5(file) { const loading = this.$loading({ lock: true,text: '正在計算MD5',spinner: 'el-icon-loading',background: 'rgba(0,0.7)' }); 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 = 10 * 1024 * 1000; let chunks = Math.ceil(file.size / chunkSize); let spark = new SparkMD5.ArrayBuffer(); file.pause(); loadNext(); fileReader.onload = (e => { spark.append(e.target.result); if (currentChunk < chunks) { currentChunk++; loadNext(); this.$nextTick(() => { console.log('校驗MD5 ' + ((currentChunk / chunks) * 100).toFixed(0) + '%') }) } else { let md5 = spark.end(); loading.close(); this.computeMD5Success(md5,file); console.log(`MD5計算完畢:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用時:${new Date().getTime() - time} ms`); } }); fileReader.onerror = function () { this.error(`檔案${file.name}讀取出錯,請檢查該檔案`); loading.close(); 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)); } },computeMD5Success(md5,file) { file.uniqueIdentifier = md5;//把md5值作為檔案的識別碼 file.resume();//開始上傳 },filesAdded(file,event) { //大小判斷 const isLt100M = file.size / 1024 / 1024 < 10; if (!isLt100M) { this.$message.error(this.$t("error.error_upload_file_max")); } else { this.computeMD5(file) } } } } </script> <style> .uploader-example { width: 90%; padding: 15px; margin: 40px auto 0; font-size: 12px; box-shadow: 0 0 10px rgba(0,.4); } .uploader-example .uploader-btn { margin-right: 4px; } .uploader-example .uploader-list { max-height: 440px; overflow: auto; overflow-x: hidden; overflow-y: auto; } </style>
後臺
引入工具
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
控制類
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; @RestController @RequestMapping("/chunk") public class ChunkController { @RequestMapping("/chunkUpload") public StdOut chunkUpload(MultipartFileParam param,HttpServletRequest request,HttpServletResponse response) { StdOut out = new StdOut(); File file = new File("C:\\chunk_test");//儲存路徑 ChunkService chunkService = new ChunkService(); String path = file.getAbsolutePath(); response.setContentType("text/html;charset=UTF-8"); try { //判斷前端Form表單格式是否支援檔案上傳 boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (!isMultipart) { out.setCode(StdOut.PARAMETER_NULL); out.setMessage("表單格式錯誤"); return out; } else { param.setTaskId(param.getIdentifier()); out.setModel(chunkService.chunkUploadByMappedByteBuffer(param,path)); return out; } } catch (NotSameFileExpection e) { out.setCode(StdOut.FAIL); out.setMessage("MD5校驗失敗"); return out; } catch (Exception e) { out.setCode(StdOut.FAIL); out.setMessage("上傳失敗"); return out; } } }
StdOut類(只是封裝的返回類)
public class StdOut { public static final int SUCCESS = 200; public static final int FAIL = 400; public static final int PARAMETER_NULL = 500; public static final int NO_LOGIN = 600; private int code = 200; private Object model = null; private String message = null; public StdOut() { this.setCode(200); this.setModel((Object)null); } public StdOut(int code) { this.setCode(code); this.setModel((Object)null); } public StdOut(List<Map<String,Object>> model) { this.setCode(200); this.setModel(model); } public StdOut(int code,List<Map<String,Object>> model) { this.setCode(code); this.setModel(model); } public int getCode() { return this.code; } public void setCode(int code) { this.code = code; } public String toString() { return JSON.toJSONString(this); } public Object getModel() { return this.model; } public void setModel(Object model) { this.model = model; } public String getMessage() { return this.message; } public void setMessage(String message) { this.message = message; } }
MultipartFileParam類(檔案資訊類)
import org.springframework.web.multipart.MultipartFile; public class MultipartFileParam { private String taskId; private int chunkNumber; private long chunkSize; private int totalChunks; private String identifier; private MultipartFile file; public String getTaskId() { return taskId; } public void setTaskId(String taskId) { this.taskId = taskId; } public int getChunkNumber() { return chunkNumber; } public void setChunkNumber(int chunkNumber) { this.chunkNumber = chunkNumber; } public long getChunkSize() { return chunkSize; } public void setChunkSize(long chunkSize) { this.chunkSize = chunkSize; } public int getTotalChunks() { return totalChunks; } public void setTotalChunks(int totalChunks) { this.totalChunks = totalChunks; } public String getIdentifier() { return identifier; } public void setIdentifier(String identifier) { this.identifier = identifier; } public MultipartFile getFile() { return file; } public void setFile(MultipartFile file) { this.file = file; } }
ChunkService類
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.UUID; public class ChunkService { public String chunkUploadByMappedByteBuffer(MultipartFileParam param,String filePath) throws IOException,NotSameFileExpection { if (param.getTaskId() == null || "".equals(param.getTaskId())) { param.setTaskId(UUID.randomUUID().toString()); } String fileName = param.getFile().getOriginalFilename(); String tempFileName = param.getTaskId() + fileName.substring(fileName.lastIndexOf(".")) + "_tmp"; File fileDir = new File(filePath); if (!fileDir.exists()) { fileDir.mkdirs(); } File tempFile = new File(filePath,tempFileName); //第一步 開啟將要寫入的檔案 RandomAccessFile raf = new RandomAccessFile(tempFile,"rw"); //第二步 開啟通道 FileChannel fileChannel = raf.getChannel(); //第三步 計算偏移量 long position = (param.getChunkNumber() - 1) * param.getChunkSize(); //第四步 獲取分片資料 byte[] fileData = param.getFile().getBytes(); //第五步 寫入資料 fileChannel.position(position); fileChannel.write(ByteBuffer.wrap(fileData)); fileChannel.force(true); fileChannel.close(); raf.close(); //判斷是否完成檔案的傳輸並進行校驗與重新命名 boolean isComplete = checkUploadStatus(param,fileName,filePath); if (isComplete) { FileInputStream fileInputStream = new FileInputStream(tempFile.getPath()); String md5 = DigestUtils.md5Hex(fileInputStream); fileInputStream.close(); if (StringUtils.isNotBlank(md5) && !md5.equals(param.getIdentifier())) { throw new NotSameFileExpection(); } renameFile(tempFile,fileName); return fileName; } return null; } public void renameFile(File toBeRenamed,String toFileNewName) { if (!toBeRenamed.exists() || toBeRenamed.isDirectory()) { System.err.println("檔案不存在"); return; } String p = toBeRenamed.getParent(); File newFile = new File(p + File.separatorChar + toFileNewName); toBeRenamed.renameTo(newFile); } public boolean checkUploadStatus(MultipartFileParam param,String fileName,String filePath) throws IOException { File confFile = new File(filePath,fileName + ".conf"); RandomAccessFile confAccessFile = new RandomAccessFile(confFile,"rw"); //設定檔案長度 confAccessFile.setLength(param.getTotalChunks()); //設定起始偏移量 confAccessFile.seek(param.getChunkNumber() - 1); //將指定的一個位元組寫入檔案中 127, confAccessFile.write(Byte.MAX_VALUE); byte[] completeStatusList = FileUtils.readFileToByteArray(confFile); confAccessFile.close();//不關閉會造成無法佔用 //建立conf檔案檔案長度為總分片數,每上傳一個分塊即向conf檔案中寫入一個127,那麼沒上傳的位置就是預設的0,已上傳的就是127 for (int i = 0; i < completeStatusList.length; i++) { if (completeStatusList[i] != Byte.MAX_VALUE) { return false; } } confFile.delete(); return true; } }
6.NotSameFileExpection類
public class NotSameFileExpection extends Exception { public NotSameFileExpection() { super("File MD5 Different"); } }
遇到問題
根據自己的實際情況進行取捨,靈活處理。
以上這篇vue-simple-uploader上傳成功之後的response獲取程式碼就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。