大文件分片上传-百度webuploader

一、官方文档参考地址

http://fex-team.github.io/webuploader/document.html

二、功能需求

点击一个按钮,直接打开文件选择窗口,选中多个文件后,点击窗口【确定】按钮后,直接开始上传。

三、实现

由于文件普遍为较大文件,所以使用分片上传的方式来实现。使用的js框架为百度的webuploader。

1.前端部分:

首先页面引入webuploader.js插件

<script type="text/javascript" charset="UTF-8" th:src="@{/scripts/common/file/upload/webuploader.js}"></script>

上传按钮部分:

<a class="btn btn-default btn-sm" id="upload_btn" > 上传 </a>
<div style="display:none;">
       <span id="picker" class="showclass">点击上传文件</span>
</div>

id=“picker” 这部分要注意,后面会用到,webuploader是会对一个指定id的元素,在下方生成一些html代码,来辅助上传。

新建个uploader.js引入到页面,本js主要就是对webuploader的一些初始化之类的。

var SbzUploader = function(conf) {

}

var sbzUploadConf =
    {
        autoUpload : false, sbzFile : 'sbzUploadFile', docType : 'PDM', businessId : '1111111112312312321', fileId : '',
        complete : function() {
            alert('success');
        }, progress : function(file, percentage) {
            console.log()
        }
    }

var $sbzFile = $('#' + sbzUploadConf.sbzFile);

/**
 * 上传的AJAX
 */
var sbzUploadAjax =
    function(uri, data, success, fail) {
        $.ajax({
            url : uri, data : JSON.stringify(data), type : "POST", contentType : "application/json;charset=UTF-8",
            dataType : "json"
        }).done(function(res) {
            if (res.buinessException && res.code < 9) {
                sbz.Msg.showMsg(res.code, res.message)
                if (fail) {
                    fail(res);
                }
            } else if (success) {
                success(res);
            }
        }).fail(function(res) {
            if (fail) {
                fail(res);
            } else {
                sbz.Msg.error(res.message + res.responseText);
            }
        });

    }

/**
 * 
 */
var _sbzUploadConf =
    {
        chunkSize : 5 * 1024 * 1024, fileNumLimit : 1024, fileSizeLimit : 1024 * 1024 * 1024 * 10,
        fileSingleSizeLimit : 1024 * 1024 * 1024
    }

// HOOK 这个必须要再uploader实例化前面
WebUploader.Uploader.register({
    'before-send-file' : 'beforeSendFile', 'before-send' : 'beforeSend'
}, {
    beforeSendFile : function(file) {
        console.log("beforeSendFile");
        // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
        var task = new $.Deferred();
        // 根据文件内容来查询MD5
        uploader.md5File(file).progress(function(percentage) { // 及时显示进度
            console.log('md5 per:', percentage);
            getProgressBar(file, percentage, "MD5", "分片计算");
        }).then(function(val) { // 完成
            console.log('md5 result:', val);
            file.md5 = val;
            file.uid = WebUploader.Base.guid();
            file.bid = sbzUploadConf.businessId;
            // 进行md5判断
            $.post("/document/uploader/checkFileMd5", {
                uid : file.uid, md5 : file.md5, bid : sbzUploadConf.businessId
            }, function(data) {
                console.log(data.status);
                var status = data.status;
                task.resolve();
                if (status == 101) {
                    // 文件不存在,那就正常流程
                    
                    // hky add bid
                    sbzUploadConf.businessId = '11111111'
                    
                } else if (status == 100) {
                    // 忽略上传过程,直接标识上传成功;
                    //uploader.skipFile(file);
                    //file.pass = true;
                } else if (status == 102) {
                    // 部分已经上传到服务器了,但是差几个模块。
                    file.missChunks = data.data;
                }
            });
        });
        return $.when(task);
    }, beforeSend : function(block) {
        console.log("block")
        var task = new $.Deferred();
        var file = block.file;
        var missChunks = file.missChunks;
        var blockChunk = block.chunk;
        console.log("当前分块:" + blockChunk);
        console.log("missChunks:" + missChunks);
        if (missChunks !== null && missChunks !== undefined && missChunks !== '') {
            var flag = true;
            for (var i = 0; i < missChunks.length; i++) {
                if (blockChunk == missChunks[i]) {
                    console.log(file.name + ":" + blockChunk + ":还没上传,现在上传去吧。");
                    flag = false;
                    break;
                }
            }
            if (flag) {
                task.reject();
            } else {
                task.resolve();
            }
        } else {
            task.resolve();
        }
        return $.when(task);
    }
});

// 实例化
var uploader =
    WebUploader.create({
        pick : {
            id : '#picker'
        }, 
        name : 'sbz-uploader-file', 
        formData : {
            uid : 0, 
            md5 : '', 
            bid : '', chunkSize : _sbzUploadConf.chunkSize
        },
        chunked : true, 
        chunkSize : _sbzUploadConf.chunkSize, // 字节 1M分块
        threads : 3, 
        server : '/document/uploader/fileUpload', 
        auto : true,
        // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
        disableGlobalDnd : false, 
        fileNumLimit : _sbzUploadConf.fileNumLimit,
        fileSizeLimit : _sbzUploadConf.fileSizeLimit,
        fileSingleSizeLimit : _sbzUploadConf.fileSingleSizeLimit
    });
    
// 当有文件被添加进队列的时候
uploader.on('fileQueued', function(file) {
    console.log("fileQueued");
    
    uploadFlag = true; // hky add
    var uploadFileProgressHtml = '<div>'+file.name+'</div><div class="progress"><div id="progress_'+ file.id +'"class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">0%</div></div>'
    $('#upload_modal_body').append(uploadFileProgressHtml)
    
    
    // 生成新的记录
    $sbzFile.val(file.name);
    if (sbzUploadConf.autoUpload) {
        uploader.upload();
    }
});

// 当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。
uploader.onUploadBeforeSend = function(obj, data) {
    console.log("onUploadBeforeSend");
    var file = obj.file;
    data.md5 = file.md5 || '';
    data.uid = file.uid;
    data.bid=file.bid;
    data.type=file.type;
    data.docType=sbzUploadConf.docType;
};
// 上传中
uploader.on('uploadProgress', function(file, percentage) {
	console.log('进度中', file, percentage)
    getProgressBar(file, percentage, "FILE", "上传进度");
});
// 上传返回结果
uploader.on('uploadSuccess', function(file) {
    var text = '已上传';
    if (file.pass) {
        text = "文件妙传功能,文件已上传。"
    }
    $('#' + file.id).find('p.state').text(text);
});

uploader.on('uploadError', function(file) {
    $('#' + file.id).find('p.state').text('上传出错');
});

uploader.on('uploadComplete', function(file) {
	console.log('uploadComplete')
	// $("#common_upload_modal").hide();
	sbz.Msg.success(file.name + " 上传完成");
	$("#common_upload_title").html(file.name + ' 上传完成')
	
	
	uploadCompleteCallback(file)
});

var uploadFlag = true;
// hky 进度条
function getProgressBar(file, percentage, id_Prefix, titleName) {
	if(uploadFlag) {
		$("#common_upload_modal").modal("toggle");
		uploadFlag = false;
	}
	var value = (percentage * 100).toFixed(2);
	var progressPercentage = value + '%';
	$('#progress_'+ file.id).html(progressPercentage)
	
	$('#progress_'+ file.id).attr('aria-valuenow', value)
	$('#progress_'+ file.id).width(progressPercentage)
	
	if(id_Prefix == 'MD5') {
		$("#common_upload_title").html('文件:' + file.name + ' 处理中')
	}else{
		$("#common_upload_title").html('文件:' + file.name + ' 上传进度')
	}
	
}


然后,把上传按钮的事件初始化

    //上传按钮
    $('#upload_btn').bind("click", function () {
        sbzUploadConf.businessId = 'xxxxx';
        console.info("sbzUploadConf.businessId=====" + sbzUploadConf.businessId);
        uploader.reset();
        $('.webuploader-element-invisible').click();
    });
    
    function onReleaseChange(refId) {
    if (tableData.length) {
        let data = docReleaseModal.tableData.find((item) => {
            return item.refId === refId
        });
        docPropertiesModal.show(data,docReleaseTable);
        docPropertiesTable.reload();
    }

}

其中$(‘.webuploader-element-invisible’).click();就是webuploader插件生成的input标签的代码。也就是手动调了下,input file 标签的选择文件。

2.后端部分

校验文件是否上传过,可实现秒传。

    @RequestMapping(value = "/checkFileMd5", method = RequestMethod.POST)
    @ResponseBody
    public Object checkFileMd5(String md5) throws IOException {
        ResultVo result = null;

        Object processingObj = stringRedisTemplate.opsForHash().get(UploadConst.FILE_UPLOAD_STATUS,
            UploadConfig.getFileMd5(md5));
        if (processingObj == null) {
            result = new ResultVo(ResultStatus.NO_HAVE);
        } else {

            String processingStr = processingObj.toString();
            boolean processing = Boolean.parseBoolean(processingStr);
            String value = stringRedisTemplate.opsForValue().get(UploadConfig.getUploadRedisKey(md5));
            if (processing) {
                File t = new File(value);
                if (t.exists()) {
                    result = new ResultVo(ResultStatus.IS_HAVE, value);
                } else {
                    result = new ResultVo(ResultStatus.NO_HAVE);
                }
            } else {
                List<String> missChunkList = new LinkedList<>();
                if (value != null && value.length() > 0) {
                    File confFile = new File(value);
                    if (confFile.exists()) {
                        byte[] completeList = FileUtils.readFileToByteArray(confFile);

                        for (int i = 0; i < completeList.length; i++) {
                            if (completeList[i] != Byte.MAX_VALUE) {
                                missChunkList.add(i + "");
                            }
                        }
                    } else {
                        result = new ResultVo(ResultStatus.NO_HAVE);
                    }
                }

                result = new ResultVo<>(ResultStatus.ING_HAVE, missChunkList);
            }
        }
        return result;
    }

文件上传接口:

    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity fileUpload(MulitpartFileData param, HttpServletRequest request) {
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (isMultipart) {
            SystemLogger.debug("上传文件start。");
            try {
                storageService.uploadFileByMappedByteBuffer(param);
            } catch (IOException e) {
                e.printStackTrace();
                SystemLogger.error("文件上传失败" + param.toString(), e);

                ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body("上传失败");
            }
            SystemLogger.debug("上传文件end。");
        }
        return ResponseEntity.ok("上传成功。");
    }

先写这么多,简单做个记录,以后有空再补充…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值