参考:http://fex.baidu.com/webuploader/
使用:
前端页面:
<div id="uploadfile" style="margin-top: 10px;">
<div id="picker" >选择文件</div>
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list">
<table class="table" border="1" cellpadding="0" cellspacing="0"
width="100%" id="uploadTable">
<tr class="filelist-head" style="font-size:15px">
<th class="file-name">文件名称</th>
<th class="file-size">大小</th>
<th width="20%" class="file-pro">进度</th>
<th class="file-status">状态</th>
<th width="10%" class="file-manage">操作</th>
</tr>
</table>
</div>
<div id="ctlBtn" class="btn btn-default">开始上传</div>
</div>
</div>
<script>
$(function(){
//上传 start
var $list = $('#thelist .table'),
$btn = $('#ctlBtn');
var uploader = WebUploader.create({
resize: false, // 不压缩image
swf: 'asserts/${appVersion}/lib/webuploader/Uploader.swf', // swf文件路径
server: 'uploadBigFileAdd', // 文件接收服务端。
pick: '#picker', // 选择文件的按钮。可选
chunked: true, //是否要分片处理大文件上传
chunkSize:10*1024*1024, //分片上传,每片2M,默认是5M
// auto: true, //选择文件后是否自动上传
// chunkRetry : 2, //如果某个分片由于网络问题出错,允许自动重传次数
//runtimeOrder: 'html5,flash',
// accept: {
// title: 'Images',
// extensions: 'gif,jpg,jpeg,bmp,png',
// mimeTypes: 'image/*'
// }
duplicate: false //是否支持重复上传
});
// 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) {
$list.append('<tr id="'+ file.id +'" class="file-item">'+'<td class="file-name">'+ file.name +'</td>'+ '<td width="20%" class="file-size">'+ (file.size/1024/1024).toFixed(1)+'M' +'</td>' +'<td width="20%" class="file-pro">0%</td>'+'<td class="file-status">等待上传</td>'+'<td width="20%" class="file-manage"><a class="stop-btn" href="javascript:;">暂停</a> <a class="remove-this" href="javascript:;">取消</a></td>'+'</tr>');
//暂停上传的文件
$list.on('click','.stop-btn',function(){
uploader.stop(true);
})
//删除上传的文件
$list.on('click','.remove-this',function(){
if ($(this).parents(".file-item").attr('id') == file.id) {
uploader.removeFile(file);
$(this).parents(".file-item").remove();
}
})
});
//重复添加文件
var timer1;
uploader.onError = function(code){
clearTimeout(timer1);
timer1 = setTimeout(function(){
alert('该文件已存在');
},250);
}
// 文件上传过程中创建进度条实时显示
uploader.on( 'uploadProgress', function( file, percentage ) {
$("td.file-pro").text("");
var $li = $( '#'+file.id ).find('.file-pro'),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if ( !$percent.length ) {
$percent = $('<div class="progress progress-striped active" style="margin-bottom: 0px">' +
'<div class="progress-bar" role="progressbar" style="width: 0%">' +
'</div>' +
'</div>' + '<div class="per">0%</div>').appendTo( $li ).find('.progress-bar');
}
$li.siblings('.file-status').text('上传中');
$li.find('.per').text((percentage * 100).toFixed(2) + '%');
$percent.css( 'width', percentage * 100 + '%' );
});
// 文件上传成功
uploader.on( 'uploadSuccess', function( file ) {
$( '#'+file.id ).find('.file-status').text('已上传');
$( '#'+file.id ).find('.file-pro').text('100%');
var tb=document.getElementById("uploadTable"); //获取table对像
var rows=tb.rows;
for(var i=0;i<rows.length;i++){ //--循环所有的行
var cells=rows[i].cells;
if(cells[3].innerText=='已上传'){
cells[2].innerText='100%';
cells[4].innerHTML ='';
}
}
$('#uploadBigFileForm').submit();
});
// 文件上传失败,显示上传出错
uploader.on( 'uploadError', function( file ) {
$( '#'+file.id ).find('.file-status').text('上传出错');
});
uploader.on('uploadBeforeSend', function (obj, data, headers) {
var configType=$("#configType option:selected").val();
data.configType= configType;
});
$btn.on('click', function () {
if ($(this).hasClass('disabled')) {
return false;
}
var configType=$("#configType option:selected").val();
$.ajax({
type: "POST",
url: 'uploadBigFileValidate',
data: "configType="+configType,
dataType: 'json',
success: function(obj){
if(obj.success){
//自定义参数
uploader.options.formData.path=encodeURI(encodeURI(obj.content));
uploader.options.formData.guid = Math.random();
uploader.upload();
}else if(!obj.success){
alert(obj.errorMsg);
return false;
}
}
});
});
})
</script>
后端-springmvc
@SuppressWarnings({"rawtypes", "unchecked"})
@NeedLogin
@RequestMapping("/uploadBigFileAdd")
public @ResponseBody String uploadBigFileAdd(MultipartFile file, String guid, Integer chunk, Integer chunks,
HttpServletRequest request) {
String fileSavePath = "";
try {
fileSavePath = URLDecoder.decode(URLDecoder.decode(request.getParameter("path"), "UTF-8"), "UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String tmpPath = "";
String fileName = file.getOriginalFilename();
UploadFileLog log = new UploadFileLog();
log.setFileName(fileName);
if (chunk == null && chunks == null) {// 没有分片 直接保存
long stime = System.currentTimeMillis();
fileSavePath =
fileSavePath + File.separatorChar + DateUtils.formatDate(new Date(), DateUtils.FILE_NAME_PATTERN);
File uploadFile = new File(fileSavePath + File.separatorChar + fileName);
try {
FileUtils.copyInputStreamToFile(file.getInputStream(), uploadFile);
} catch (IOException e) {
logger.error("IOException 0", e);
}
// 保存日志
log.setPath(uploadFile.getAbsolutePath());
log.setTimes(System.currentTimeMillis() - stime);
logService.addLog(log);
return "";
} else {
tmpPath = fileSavePath + File.separatorChar + "tmp" + File.separatorChar
+ DateUtils.formatDate(new Date(), DateUtils.FILE_NAME_PATTERN);
if (chunk == 0) {
start.set(System.currentTimeMillis());
}
// 根据guid 创建一个临时的文件夹
File file2 = new File(tmpPath + File.separatorChar + guid + File.separatorChar + chunk);
if (!file2.exists()) {
file2.mkdirs();
}
try {
// 保存每一个分片
file.transferTo(file2);
} catch (Exception e) {
logger.error("transferTo Exception ", e);
}
// 如果当前是最后一个分片,则合并所有文件
if (chunk == (chunks - 1)) {
//先对分片排序,然后合并文件
}
}
return "";
}
测试结果:
每片5M
文件大小 | 上传耗时 | 合并文件耗时 | 分片数 |
136M | 1171ms | 556ms | 28 |
254M | 2109ms | 1660ms | 51 |
1.75G | 31488ms | 26462ms | 359 |
每片10M
文件大小 | 上传耗时 | 合并文件耗时 | 分片数 |
136M | 404ms | 295ms | 14 |
254M | 2401ms | 1015ms | 26 |
1.75G | 28452ms | 22866ms | 180 |
每片15M
文件大小 | 上传耗时 | 合并文件耗时 | 分片数 |
136M | 749ms | 515ms | 10 |
254M | 1857ms | 1126ms | 17 |
1.75G | 26189ms | 22866ms | 120 |