记录一下文件分片上传断点续传功能的前端实现,后端部分可以看看这篇文章:SpringBoot实现文件分片断点续传功能(后端篇)
项目代码已上传至GitHub https://github.com/huiluczP/segment_upload
所有请求都使用ajax
。
简单两控件,output中显示信息。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>segment uploadtitle>
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js">script>
<script type="text/javascript" src="/js/md5.js">script>
<script type="text/javascript" src="/js/tool.js">script>
<script src="/js/upload.js">script>
head>
<body>
<div id="top" class="center">
<p id="message">p>
div>
<div id="upload" class="center">
<h1>Segment File Uploadh1>
<input type="file" name="filename" id="filename" onchange="checkFile()"/>
<input type="button" id="submit" onclick="upload()" value="submit"/>
<span id="output">等待中span>
div>
<span id="uuid">uuid_name:span>
<span id="md5" style="margin-left:20px;">md5_key:span>
body>
html>
切换文件,调用checkFile
方法查询文件信息。点击上传,调用上传方法upload
。
用全局变量存下当前文件的唯一码和固定分片大小:
var key = ''
var segmentSize = 2 * 1024 * 1024; // 先2MB用着
文件的名称,大小,类型和修改时间组合成唯一字符串,计算md5码作为文件唯一码。
md5.js
和tool.js
是网上找的工具类,用来计算各种加密字符串结果。
// 文件key计算
function calFileKey(file){
//把文件的信息存储为一个字符串
var filedetails= file.name + file.size + file.type + file.lastModifiedDate;
//使用当前文件的信息用md5加密生成一个key
var key = hex_md5(filedetails);
var key10 = parseInt(key,16);
//把加密的信息 转为一个62位的
var key62 = Tool._10to62(key10);
console.log("cal key:" + key62)
return key62
}
// 计算分片数量
// 注意分片序号从1开始
function calTotalSegmentSize(file){
var size = file.size
var segmentTotal = Math.ceil(size / segmentSize)
return segmentTotal;
}
// 计算分片的开始
function calSegmentStartAndEnd(segmentIndex, file){
var start = (segmentIndex - 1) * segmentSize;
var end = Math.min(start + segmentSize, file.size);
return new Array(start, end);
}
计算唯一码key,ajax
调用接口查询信息。
function checkFile(){
var file = $('#filename').get(0).files[0]
key = calFileKey(file)
$('#md5').html('md5_key: ' + key)
console.log(file.name)
// ajax请求找下数据库中该文件是否存在
$.ajax({
url:"/checkFile",
type:"post",
cache: false,
data: {
'key': key
},
dataType: 'json',
success:function(data){
var result = data.success
if(!result){
$('#uuid').html('uuid_name:')
$('#output').html('该文件未上传')
}else{
var segmentFile = JSON.parse(data.message)
var segmentIndexNow = segmentFile.segmentIndex
var segmentTotal = segmentFile.segmentTotal
var uuid = segmentFile.fileName
$('#uuid').html('uuid_name: ' + uuid)
if(segmentIndexNow==segmentTotal){
// 完成上传
$('#output').html('该文件已完成上传,别再传了')
}else{
$('#output').html(segmentIndexNow + '/' +segmentTotal)
segmentIndex = segmentIndexNow + 1
}
}
},
error:function(){
console.log("check请求错误")
}
})
}
根据查询结果,修改页面上key,uuid和分片上传信息的表示。已完成上传的显示秒传提示。
参数为分片序号,文件和文件唯一码,串行递归调用。文件的分片切割使用slice
方法。
// 上传分片
function uploadSegment(segmentIndex, file, key){
var fd = new FormData();
var segmentIndex = segmentIndex;
var sAe = calSegmentStartAndEnd(segmentIndex, file)
var segmentStart = sAe[0]
var segmentEnd = sAe[1]
var segment = file.slice(segmentStart, segmentEnd)
var segmentTotal = calTotalSegmentSize(file)
var originFileName = file.name
fd.append('file', segment)
fd.append('fileSize', file.size)
fd.append('segmentIndex', segmentIndex)
fd.append('key', key)
fd.append('segmentSize', segmentSize)
fd.append('originFileName', originFileName)
$.ajax({
url:"/uploadSegment",
type:"post",
cache: false,
data:fd,
processData: false,
contentType: false,
success:function(data){
var result = data.success
if(!result){
$('#output').html(data.message)
}else{
var segmentFile = JSON.parse(data.message)
var uuid = segmentFile.fileName
$('#uuid').html('uuid_name: ' + uuid)
// 递归调用
$('#output').html(segmentIndex + "/" + segmentTotal)
if(segmentIndex < segmentTotal)
uploadSegment(segmentIndex+ 1, file, key)
}
},error:function(){
console.log("分片" + segmentIndex + "上传失败")
}
})
}
利用formData
表单存储信息来传递。要注意的是
,有文件数据的话,ajax
需要设置processData
和contentType
。
首先获取文件信息,之后根据回传结果调用不同的分片序号的分片上传方法。
function upload(){
var file = $('#filename').get(0).files[0]
key = calFileKey(file)
$('#md5').html('md5_key:' + key)
// ajax请求找下数据库中该文件是否存在
$.ajax({
url:"/checkFile",
type:"post",
cache: false,
data: {
'key': key
},
dataType: 'json',
success:function(data){
var result = data.success
if(!result){
var segmentIndexNow = 0
var segmentTotal = calTotalSegmentSize(file)
$('#uuid').html('uuid_name:')
$('#output').html(segmentIndexNow + '/' +segmentTotal)
var segmentIndex = segmentIndexNow + 1
// 开始上传分片
uploadSegment(segmentIndex, file, key)
}else{
var segmentFile = JSON.parse(data.message)
var segmentIndexNow = segmentFile.segmentIndex
var segmentTotal = segmentFile.segmentTotal
var uuid = segmentFile.fileName
$('#uuid').html('uuid_name: ' + uuid)
if(segmentIndexNow==segmentTotal){
// 完成上传
$('#output').html('该文件已完成上传,别再传了')
}else{
$('#output').html(segmentIndexNow + '/' +segmentTotal)
var segmentIndex = segmentIndexNow + 1
// 开始上传分片
uploadSegment(segmentIndex, file, key)
}
}
},
error:function(){
console.log("check请求错误")
}
})
}
未上传文件选择
已上传文件选择
开始分片上传,上传过程中显示分片上传进度
前端逻辑相对来说比较简单,就是串行调用对应的序号的分片进行上传。比较关键的是唯一码的计算和切片工作都是前端进行,觉得有用的话就看看吧。
后端部分可以看看这篇文章:SpringBoot实现文件分片断点续传功能(后端篇)
项目代码已上传至GitHub https://github.com/huiluczP/segment_upload