項目開發采用前后端分離,在開發中發現需要開發附件上傳功能,遇到的一些問題,做一些總結和記錄
整個文件上傳邏輯是:
1 前端文件上傳前,先使用插件計算文件的唯一MD5值
2 將MD5值上傳到服務器,后端進行校驗是否存儲有相同的MD5值文件
3 如果不存在,上傳文件到后端服務器進行存儲;如果存在,則前端不在重復提交文件
使用MD5 優勢
1 前端生成文件唯一MD5,減輕后端服務器壓力
2 文件的唯一性標志,減小ftp
服務器存放重復文件概率(重復率為零?待測試)
使用MD5 缺點
1 上傳一個文件需要2個http請求,如果文件已經存在,則為一次請求(1:上傳MD5驗證文件是否已經存在 2:不存在則再次上傳文件),如果網絡環境差,影響操作體驗
優化方案: 文件和文件MD5同時傳輸到后端進行處理
遇到問題
1 前端使用element Upload
組件如何自定義上傳文件
2 前端如何 hash
生成文件 MD5
3 前端使用 axios post
請求上傳文件到服務器
4 后端代碼(java)如何接收前端上傳的文件
前端架構: vue
,element
, axios
后端架構:java
, springBoot
解決步驟1:
配置 Upload 組件 http-request
屬性 ,自定義http上傳
:http-request = "customUpload"
核心代碼代碼:
<el-upload
class="upload-demo"
ref="upload"
:multiple="false"
action="http://127.0.0.1:8080/docmanager/upload"
:http-request = "customUpload"
:on-remove="handleRemove"
:on-change="handleChange"
:file-list="fileList"
:auto-upload="true">
<el-button slot="trigger" size="small" type="primary">選取文件</el-button>
<el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上傳到服務器</el-button>
<div slot="tip" class="el-upload__tip">只能上傳jpg/png文件,且不超過500kb</div>
</el-upload>
customUpload(file) {
// this.generatorFileMd5(file.file)
// 自定義上傳
fileUpload(file).then(response => {
console.log(response)
})
}
解決步驟2:
使用hash
生成 MD5
安裝依賴包:spark-md5
spark-md5
npm install --save spark-md5
核心代碼:
generatorFileMd5(file) {
/**
* 生成MD5
*/
let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
// file = this.files[0],
let chunkSize = 2097152 // Read in chunks of 2MB
let chunks = Math.ceil(file.size / chunkSize)
let currentChunk = 0
let spark = new SparkMD5.ArrayBuffer()
let fileReader = new FileReader()
fileReader.onload = function (e) {
// console.log('read chunk nr', currentChunk + 1, 'of', chunks)
spark.append(e.target.result) // Append array buffer
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
// console.info('computed hash', spark.end()) // spark.end(): 文件 MD5值生成完成
console.log(spark.end())
}
};
fileReader.onerror = function () {
console.warn('fileReader.onerror is error')
};
function loadNext() {
var start = currentChunk * chunkSize,
end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end))
}
loadNext()
}
解決步驟3:
使用axios
上傳文件
/**
* 文件上傳
*/
export function fileUpload(fileobj) {
let param = new FormData()
param.append('files',fileobj.file)
return request({
method: 'post',
url: '/docmanager/upload',
headers: {'Content-Type':'multipart/form-data'},
data: param
})
}
解決步驟4:
后端接收前端文件
@PostMapping("/upload")
@JsonBody
public List<DocForm> upload(MultipartFile[] files) throws Exception {
List<DocForm> rs = new ArrayList<DocForm>();
for (MultipartFile file : files) {
// ... 處理文件儲存邏輯
}
return rs;
}