webuploader与django进行断点续传

若如初见. 提交于 2020-03-05 22:45:38

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!