webuploader与django进行断点续传

Posted 巫小诗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webuploader与django进行断点续传相关的知识,希望对你有一定的参考价值。

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>
    

以上是关于webuploader与django进行断点续传的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程下载器FileDownloader(支持断点续传代理等功能)

解决WebUploader断点续传md5混乱导致的文件合并错误问题

jsp利用webuploader实现超大文件分片上传断点续传

java使用WebUploader做大文件的分块和断点续传

webUploader实现大文件分片,断点续传

大文件断点续传插件webupload插件