webuploader与django进行断点续传
- 需要实现的效果如下
-
需要使用的 js
- jquery.js
- webuploader.hs
- hashmap.js
-
路由
from django.urls import path from . import views urlpatterns = [ path(\'index/\',views.index), path(\'checkChunk/\',views.checkChunk,name=\'checkChunk\'), path(\'mergeChunks/\',views.mergeChunks,name=\'mergeChunks\'), path(\'upload/\',views.upload,name=\'upload\'), ]
-
视图
from django.shortcuts import render from django.http import JsonResponse import os def index(request): return render(request,\'upload.html\') # 检查上传分片是否重复,如果重复则不提交,否则提交 def checkChunk(request): # post请求 if request.method == \'POST\': # 获得上传文件块的大小,如果为0,就告诉他不要上传了 chunkSize = request.POST.get("chunkSize") if chunkSize == \'0\': return JsonResponse({\'ifExist\': True}) # 如果文件块大小不为0 ,那么就上传,需要拼接一个临时文件 file_name = request.POST.get(\'fileMd5\')+request.POST.get(\'chunk\') # 如果说这个文件不在已经上传的目录,就可以上传,已经存在了就不需要上传。 if file_name not in get_deep_data(): return JsonResponse({\'ifExist\': False}) return JsonResponse({\'ifExist\': True}) # 判断一个文件是否在一个目录下 def get_deep_data(path=\'static/upload/\'): result = [] data = os.listdir(path) for i in data: if os.path.isdir(i): get_deep_data(i) else: result.append(i) return result # 前端上传的分片 保存到 指定的目录下 def upload(request): if request.method == \'POST\': md5 = request.POST.get("fileMd5") chunk_id = request.POST.get("chunk","0") fileName = "%s-%s"%(md5,chunk_id) file = request.FILES.get("file") with open(\'static/upload/\'+fileName,\'wb\') as f: for i in file.chunks(): f.write(i) return JsonResponse({\'upload_part\':True}) # 将每次上传的分片合并成一个新文件 def mergeChunks(request): if request.method == \'POST\': # 获取需要给文件命名的名称 fileName = request.POST.get("fileName") # 该图片上传使用的md5码值 md5 = request.POST.get("fileMd5") id = request.POST.get("fileId") # 分片的序号 chunk = 0 # 完成的文件的地址为 path = os.path.join(\'static\',\'upload\',fileName) with open(path,\'wb\') as fp: while True: try: filename = \'static/upload/{}-{}\'.format(md5,chunk) with open(filename,\'rb\') as f: fp.write(f.read()) # 当图片写入完成后,分片就没有意义了,删除 os.remove(filename) except: break chunk += 1 return JsonResponse({\'upload\':True,\'fileName\':fileName,\'fileId\':id})
-
前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>webuploader上传</title> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/webuploader/0.1.1/webuploader.css"> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="/static/jquery-2.2.3.js"></script> <script src="/static/webuploader.min.js"></script> <script type="text/javascript" src="/static/hashmap.js"></script> <style type="text/css"> #picker { display: inline-block; line-height: 1.428571429; vertical-align: middle; margin: 0 12px 0 0; } </style> </head> <body> <div id="uploader" class="container"> <!--用来存放文件信息--> <div id="thelist" class="row"> <div class="panel panel-primary"> <div class="panel-heading">webuploader文件上传</div> <table class="table table-striped table-bordered" id="uploadTable"> <thead> <tr> <th>序号</th> <th>文件名称</th> <th>文件大小</th> <th>上传状态</th> <th>上传进度</th> <th style="width:15%;">操作</th> </tr> </thead> <tbody></tbody> </table> <div class="panel-footer"> <div id="picker">选择文件</div> <button id="btn" class="btn btn-default">开始上传</button> </div> </div> </div> </div> <script type="text/javascript"> var fileMd5; var fileSuffix; var $list=$("#thelist table>tbody"); var state = \'pending\';//初始按钮状态 var $btn=$("#btn"); var count=0; var map=new HashMap(); //监听分块上传过程中的三个时间点 WebUploader.Uploader.register({ "before-send-file" : "beforeSendFile", "before-send" : "beforeSend", "after-send-file" : "afterSendFile", }, { //时间点1:所有分块进行上传之前调用此函数 beforeSendFile : function(file) { var deferred = WebUploader.Deferred(); //1、计算文件的唯一标记,用于断点续传 // (new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024) (new WebUploader.Uploader()).md5File(file, 0, 1024) .progress(function(percentage) { $(\'#\' + file.id).find("td.state").text("正在读取文件信息..."); }).then(function(val) { fileMd5 = val; $(\'#\' + file.id).find("td.state").text("成功获取文件信息..."); //获取文件信息后进入下一步 deferred.resolve(); }); return deferred.promise(); }, //时间点2:如果有分块上传,则每个分块上传之前调用此函数 beforeSend : function(block) { var deferred = WebUploader.Deferred(); $.ajax({ type : "POST", url : "{% url \'checkChunk\'%}", data : { //文件唯一标记 fileMd5 : fileMd5, //当前分块下标 chunk : block.chunk, //当前分块大小 chunkSize : block.end - block.start }, dataType : "json", success : function(response) { if (response.ifExist) { //分块存在,跳过 deferred.reject(); } else { //分块不存在或不完整,重新发送该分块内容 deferred.resolve(); } } }); this.owner.options.formData.fileMd5 = fileMd5; deferred.resolve(); return deferred.promise(); }, //时间点3:所有分块上传成功后调用此函数 afterSendFile : function(file) { //如果分块上传成功,则通知后台合并分块 $.ajax({ type : "POST", url : "{% url \'mergeChunks\'%}", data : { fileId : file.id, fileMd5 : fileMd5, fileSuffix:fileSuffix, fileName:file.name, }, success : function(response) { console.log(response.fileName+" 上传成功") $(\'#del\'+file.id).hide(); } }); } }); var uploader = WebUploader .create({ // swf文件路径 swf : \'https://cdnjs.cloudflare.com/ajax/libs/webuploader/0.1.1/Uploader.swf\', // 文件接收服务端。 server : "{% url \'upload\' %}", // 选择文件的按钮。可选。 // 内部根据当前运行是创建,可能是input元素,也可能是flash. pick : { id : \'#picker\',//这个id是你要点击上传文件的id multiple : true }, // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传! resize : true, auto : false, //开启分片上传 chunked : true, chunkSize : 10 * 1024 * 1024, accept : { extensions : "txt,jpg,jpeg,bmp,png,zip,rar,war,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx,iso,flv,mp4", mimeTypes : \'.txt,.jpg,.jpeg,.bmp,.png,.zip,.rar,.war,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.iso,.flv,.mp4\' } }); // 当有文件被添加进队列的时候 uploader.on(\'fileQueued\', function(file) { //保存文件扩展名 fileSuffix=file.ext; fileName=file.source[\'name\']; var fileSize=file.size; var fileSizeStr=""; fileSizeStr=WebUploader.Base.formatSize(fileSize); count++; $list.append( \'<tr id="\' + file.id + \'" class="item" flag=0>\'+ \'<td class="index">\' + count + \'</td>\'+ \'<td class="info">\' + file.name + \'</td>\'+ \'<td class="size">\' + fileSizeStr + \'</td>\'+ \'<td class="state">等待上传...</td>\'+ \'<td class="percentage"></td>\'+ \'<td class="operate"><button name="upload" id="del\'+file.id+\'" class="btn btn-warning">开始</button><button name="delete" class="btn btn-error">删除</button></td></tr>\'); map.put(file.id+"",file); }); // 文件上传过程中创建进度条实时显示。 uploader.on(\'uploadProgress\', function(file, percentage) { $(\'#\' + file.id).find(\'td.percentage\').text( \'上传中 \' + Math.round(percentage * 100) + \'%\'); }); uploader.on(\'uploadSuccess\', function(file) { $(\'#\' + file.id).find(\'td.state\').text(\'已上传\'); }); uploader.on(\'uploadError\', function(file) { $(\'#\' + file.id).find(\'td.state\').text(\'上传出错\'); }); uploader.on(\'uploadComplete\', function(file) { uploader.removeFile(file); }); uploader.on(\'all\', function(type) { if (type === \'startUpload\') { state = \'uploading\'; } else if (type === \'stopUpload\') { state = \'paused\'; } else if (type === \'uploadFinished\') { state = \'done\'; } if (state === \'uploading\') { $btn.text(\'暂停上传\'); } else { $btn.text(\'开始上传\'); } }); $btn.on(\'click\', function(){ if (state === \'uploading\'){ uploader.stop(true); } else { uploader.upload(); } }); $("body").on("click","#uploadTable button[name=\'upload\']",function(){ flag=$(this).parents("tr.item").attr("flag")^1; $(this).parents("tr.item").attr("flag",flag); var id=$(this).parents("tr.item").attr("id"); if(flag==1){ $(this).text("暂停"); uploader.upload(uploader.getFile(id,true)); }else{ $(this).text("开始"); uploader.stop(uploader.getFile(id,true)); }); $("body").on("click","#uploadTable button[name=\'delete\']",function(){ var id=$(this).parents("tr.item").attr("id"); $(this).parents("tr.item").remove(); uploader.removeFile(uploader.getFile(id,true)); map.remove(id); }); </script> </body> </html>