首先简单介绍一下什么是WebUploader,WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。
采用大文件分片并发上传,极大的提高了文件上传效率。
实现基本思路:
前端对文件进行分片,上传分片文件到服务器,服务器根据标识合并相关的文件。最终实现文件的上传。
前端实现
-
简单页面实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>文件上传</title>
<link ref="stylesheet" type="text/css" href="./webuploader-0.1.5/webuploader.css">
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./webuploader-0.1.5/webuploader.min.js"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="./bootstrap-4.3.1-dist/css/bootstrap.min.css">
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> -->
<script src="./bootstrap-4.3.1-dist/js/bootstrap.min.js"></script>
<style type="text/css">
.modal-header {
padding: 0;
}
/*.modal-content{border-radius: 0;}*/
.modal-dialog .close {
position: absolute;
top: 10px;
right: 15px;
}
.modal-dialog h3 {
font-size: 14px;
height: 42px;
line-height: 42px;
margin: 0;
padding: 0 80px 0 20px;
}
.modal-dialog label {
font-weight: 400;
}
.tips {
line-height: 34px;
font-size: 13px;
}
.tips span {
color: red;
}
@media (min-width: 1180px) {
/*模态框-距顶部距离*/
.modal-dialog {
margin-top: 100px;
}
.col-sm-6 {
padding-left: 0;
padding-right: 0;
}
}
.modal-body {
font-size: 16px;
}
</style>
<script src="./js/app_upload.js"></script>
</head>
<body>
<!--模态框-->
<div class="modal-dialog ">
<div class="modal-content">
<form class="" autocomplete="off" action="" disabled>
<div class="modal-header">
<h3>文件上传</h3>
</div>
<div class="modal-body">
<div class="form-group row">
<label for="add_app" class="col-sm-3">应用文件:</label>
<input id="add_app" type="file" class="file col-sm-8">
<div id="picker" class="col-sm-8">选择文件</div>
</div>
<div class="form-group row">
<button id="startUpload" type="button" onclick="start()" class="btn btn-primary btn-sm">开始上传</button>
<button id="resetUpload" type="button" onclick="start()" class="btn btn-primary btn-sm">开始上传</button>
<div id="currentInfo" class="col-sm-8" >
<strong></strong>
</div>
</div>
</div>
<!-- 进度条 -->
<div class="progress">
<div id="progressLength" class="progress-bar bg-success progress-bar-striped progress-bar-animated"
style="width:0%">0%</div>
</div>
</form>
</div>
</div>
</body>
</html>
基本效果:
image.png
-
相关的js
var WSDL = "PublicTransferLoginService?wsdl";
var SOAP_XMLNS = '"http://service.dpns.com"';
var uploader;
$(document).ready(function () {
var fileName;
var fileMd5;
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
"before-send-file": "beforeSendFile",
"before-send": "beforeSend",
"after-send-file": "afterSendFile",
}, {
//时间点1 所有分块上传之前调用此函数
beforeSendFile: function (file) {
fileName = file.name;
var deferred = WebUploader.Deferred();
//1.使用md5计算文件的唯一标识,用于断点续传
(new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024)
.progress(function (percenttage) {
$("#item1").find("p.state").text("正在读取文件信息...");
})
.then(function (val) {
fileMd5 = val;
$("#item1").find("p.state").text("成功读取文件信息");
//获取文件信息后进入下一步
deferred.resolve();
});
//调用 deferred.resolve();无效
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend: function (block, file) {
console.log("分块" + fileName.replace(/.+\./, ""));
var deferred = WebUploader.Deferred();
$.ajax({
type: "POST",
url: "http://localhost:8686/MergeFile?action=checChunk",
data: {
action: "checChunk",
//文件唯一标记
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 () {
console.log("合并");
//如果分块上传成功,则通知后台合并分块
$.ajax({
type: "POST",
url: "http://localhost:8686/MergeFile?action=mergeChunks",
data: {
fileMd5: fileMd5,
},
success: function (response) {
console.log(response);
alert("上传完成");
}
});
}
});
uploader = WebUploader.create({
// swf文件路径
swf: '<%=basePath%>js/webuploader-0.1.5/Uploader.swf',
// 文件接收服务端。
server: 'http://localhost:8686/FileUpLoad',
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: {
id: '#picker',
//这个id是你要点击上传文件的id,自己设置就好</span>
multiple: true
},
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: true,
auto: false,
//上传并发数
threads: 5,
//开启分片上传
chunked: true,
chunkSize: 10 * 1024 * 1024,
/* accept: {
//限制上传文件为MP4
extensions: 'mp4',
mimeTypes: 'video/mp4',
} */
});
// 当有文件被添加进队列的时候
uploader.on('fileQueued', function (file) {
$("#currentInfo").text("等待上传...");
});
// 文件上传过程中创建进度条实时显示。
uploader.on('uploadProgress', function (file, percentage) {
// $('#item1').find('p.state').text(file.name+'上传中 '+Math.round(percentage * 100) + '%');
var completePercentage = Math.round(percentage * 100) + "%";
$("#progressLength").css("width", completePercentage);
$("#progressLength").text(completePercentage);
});
uploader.on('uploadSuccess', function (file) {
// $( '#'+file.id ).find('p.state').text('上传完成');
$("#currentInfo").text('上传完成');
$("#currentInfo").css("color", "green");
});
uploader.on('uploadError', function (file) {
// $( '#'+file.id ).find('p.state').text('上传出错');
$("#currentInfo").text('上传出错,重新上传');
$("#currentInfo").css("color", "red");
//被锁的输入框打开
});
uploader.on('uploadComplete', function (file) { //上传完成移除进度条,进度条隐藏
});
$("#picker").hide(); //隐藏picker,并且不占用位置
});
//开始上传
function start() {
$("#myFieldset").disabled=true;
//开始上传时,禁止修改form表单的值
var filesList = $('#add_app').prop('files');
uploader.addFiles(filesList); //将文件添加到uploader中
console.log(uploader.getFiles()[0]);
var files = uploader.getFiles();
if (files.length > 1) {
// alert("只允许上传一个文件");
$("#currentInfo").text('只允许上传一个文件');
$("#currentInfo").css("color", "red");
return;
}
uploader.upload();
}
//停止上传
function stop() {
uploader.stop(true);
// $('#btn').attr("onclick","start()");
// $('#btn').text("继续上传");
}
function reset(){
window.location.reload();
}
以上代码上传时,创建了三个时间点,在不同的时间点做相应的操作。并且调用了后端两个servlet.