使用webuploader实现大文件断点续传(前端部分)

  要使用WebUploader实现大文件的断点续传需要分成几个步骤去实现:

    1.在文件上传之前把文件的标识(一般是文件的md5值)传到服务器进行验证,如果文件已经上传过了,就不执行上传操作了。

    2.每个分块上传之前判断该分块是否已经上传过了,如果当前分块已经上传过了,就跳过,不再上传了。

    3.所有分块上传完之后告诉服务器端,把分块重新合并为一个文件。

  要用webuploader实现以上的的几个步骤,需要用到自定义钩子函数,具体可以看webuploader的文档中的HOOk(钩子)。

文档中只介绍了webuploader的几个比较重要的钩子,如下图所示:

  

  其中我在项目当中只用到了before-send-file和before-send这两个钩子,有些文章也会用到第三个钩子,用于分块上传完成后通知后台对分块进行合并,而我是在uploadsuccess的事件当中进行这步操作的。

  也许会有人会想,uploadStart和uploadBeforeSend相当于before-send-file和before-send,那为什么不用呢?我认为有两点原因,

  第一:因为按以上所说的实现思路去做的话就要用ajax访问后台的接口,而ajax是一个异步的操作,需要用到promise对象去控制回调,webuploader推荐我们在钩子函数当中进行异步的操作并通过使用promise对象对回调进行控制。

  第二:根据实现思路的第二步,需要拿到分块的信息才能判断是否该分块是否已经上传过,而uploadBeforSend这个事件的三个参数分别是obj(相当于file),data(传给后台的参数,相当于formdata,可用于设置参数把文件的md5传给后台用于判断分块属于哪个文件),header(用于设置请求头),这三个参数都没有一个与分块有关的,所以更没法用了。

  说了这么多,现在该说重点了。

  要分块上传,首先得在webuploader初始化的时候设置chunked:true,chunkSize:10*1024*1024

  接着就是编写钩子函数了,在beforeSendFile当中先创建一个Deferred对象,然后用ajax把文件的md5值传给后台检验文件是否上传过,如果已经上传过了,就执行deferred.reject(),这时会触发uploadError事件,如果之前上传中断了,则把中断的位置获取回来,这里我是直接让后端返回上传了多少块,如果没有上传过或者上传中断了就执行deferred.resolve(),最后return deferred.promise();

  编写before-send钩子函数,该函数中有一个chunk的对象,该对象当中有一个chunk的属性去标识当前是第几个分块,我用这个属性值与之前上传中断的位置做比较(如果有中断的话),如果小于已上传的分块数,则执行deferred.reject(),那么就会跳过该分块的上传了,否则就执行deferred.resolve()然分块执行上传的操作,然后就会进入uploadBeforSend事件了。

  最后,在uploadSuccess的事件当中调用接口告诉服务器,让服务器把分块进行合并,然后文件的上传就完成了。

  

 代码实现:

<script>
    
    var GUID = WebUploader.Base.guid();//一个GUID
    var chunkObj = {};	//用来记录文件的状态、上传中断的位置
    $(function () {
        var $ = jQuery;
        var $list = $('#thelist');
        WebUploader.Uploader.register({
            "before-send-file":"beforeSendFile",
            "before-send": "beforeSend"
        }, {
            "beforeSendFile": function (file) {
                var deferred = WebUploader.Deferred();
                $.ajax({
                    url: "/PublicInfoManage/ResourceFile/isCheckFiles",
                    data: {
                        seq: seq,
                        fileMd5: $.md5(file.name + file.size + file.ext),
                        fileName:file.name
                    },
                    dataType: "json",
                    success: function (data) {
                        console.log(data);
                        chunkObj = data;
                        chunkObj.type = data.type;
                        chunkObj.chunk == data.chunk;
                        if (data.type == 0) {
                            
                            deferred.reject();
                            $("#" + file.id).find(".state").text("文件已上传");
                        } else if (data.type == 1) {
                            if (data.chunk) {
                                deferred.resolve();
                            }
                        } else {
                            deferred.resolve();
                        }
                        
                    },
                    error: function () {
                        deferred.resolve();
                    }
                })
                //deferred.resolve();
                return deferred.promise();
            },
            "beforeSend": function (block) {
                var deferred = WebUploader.Deferred();
                var curChunk = block.chunk;
                var totalChunk = block.chunks;
                if (chunkObj.type == "1") {
                    if (curChunk < chunkObj.chunk) {
                        deferred.reject();
                    } else {
                        deferred.resolve();
                    }
                } else {
                    deferred.resolve();
                }
                return deferred.promise();
            }
        });
        var uploader = WebUploader.create({

            // 选完文件后,是否自动上传。
            auto: false,
            // swf文件路径
            swf: applicationPath + '../Content/scripts/plugins/webuploader/Uploader.swf',

            // 文件接收服务端。
            server: applicationPath + 'PublicInfoManage/ResourceFile/Upload',

            // 选择文件的按钮。可选。
            // 内部根据当前运行是创建,可能是input元素,也可能是flash.
            pick: '#picker',

            chunked: true,//开始分片上传
            chunkSize: 20 * 1024 * 1024,//每一片的大小
            //threads: 3,
            formData: {
                seq: seq,
                //fileMd5: "0a663bd7f40f52cb77584ab43c3afd51",
                guid: GUID //自定义参数,待会儿解释
            },

            // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
            resize: false
        });

        // 当有文件被添加进队列的时候
        uploader.on('fileQueued', function (file) {
            
            $list.append('<div id="' + file.id + '" class="item">' +
                '<div class="item-file"><div class="fileType-logo"><img src="/Content/images/filetype/' + file.ext + '.png" /></div>' +
                '<div class="fileMes"><h4 class="info">' + file.name + '</h4>' +
                '<p class="state">等待上传...</p>' +
            '</div></div></div>');
     
        });
        // 文件上传过程中创建进度条实时显示。
        uploader.on('uploadProgress', function (file, percentage) {
            var $li = $('#' + file.id),
        $percent = $li.find('.progress .progress-bar');

            // 避免重复创建
            if (!$percent.length) {
                $percent = $('<div class="progress progress-striped active">' +
                  '<div class="progress-bar" role="progressbar" style=" 0%">' +
                  '</div>' +
                '</div>').appendTo($li).find('.progress-bar');
            }

            $li.find('p.state').text('上传中');

            $percent.css('width', percentage * 100 + '%');
        });
        uploader.on("uploadBeforeSend", function (obj, data, headers) {
            var file = obj.cuted.file;
            data.fileMd5 = $.md5(file.name + file.size + file.ext);
        })
        // 文件上传成功,给item添加成功class, 用样式标记上传成功。
        uploader.on('uploadSuccess', function (file, response) {
            $('#' + file.id).find('p.state').text('已上传');
            $.post('../../PublicInfoManage/ResourceFile/Merge', { seq: seq, fileMd5: $.md5(file.name + file.size + file.ext), folderId: folderId, guid: GUID, fileName: file.name }, function (data) {
                $('#' + file.id).find('.progress').fadeOut();
                data = JSON.parse(data);
                if (data.message == "上传成功") {
                    $("#uploader .state").html("上传成功");
                    $.currentIframe().$("#gridTable").trigger("reloadGrid");
                } else {
                    $("#uploader .state").html("上传出错");
                    return false;
                }

            });
        });

        // 文件上传失败,显示上传出错。
        uploader.on('uploadError', function (file) {
            $('#' + file.id).find('p.state').text('上传出错');
        });

        // 完成上传完了,成功或者失败,先删除进度条。
        uploader.on('uploadComplete', function (file) {
            //$('#' + file.id).find('.progress').fadeOut();
        });

        //所有文件上传完毕
        uploader.on("uploadFinished", function () {
            //提交表单

        });
        //开始上传
        $("#ctlBtn").click(function () {
            uploader.upload();

        });

        //给上传按钮绑定文件上传方法
        //$(document).on('click', '.btn_upload', function () {
        //    var fileId = $(this).closest(".item").attr("id");
        //    uploader.upload();
        //})

    });
</script>

  

  

原文地址:https://www.cnblogs.com/hackerPJ/p/7563023.html