原文参考于http://blog.csdn.net/chenxiaoyu_csdn/article/details/70847203
其中修复了原文章中由于网络中断等问题,断点续传时会再次上传已经上传文件的问题.修复了不需要分片的文件,上传过程中会出现异常的问题.
- webupload官网下载需要的Uploader.swf、webuploader.css、webuploader.js 文件
- jsp 页面
<div id="uploadfile">
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="form-group form-inline">
<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>
</div>
<p style="color: red;margin-top: 80px;" id="fileError"></p>
</div>
3.js 代码
<script type="text/javascript">
//var projcetName =$("#project").val();
$(function(){
var $list = $('#thelist'),
$btn = $('#ctlBtn');
var fileMd5;
//自定义参数 文件名
var fileName;
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile", //整个文件上传前调用
"before-send":"beforeSend", //每个分片上传前
"after-send-file":"afterSendFile", //分片上传完毕
},{
//时间点1:所有分块进行上传之前调用此函数
beforeSendFile:function(file){
console.log("beforeSendFile");
var deferred = WebUploader.Deferred();
//1、计算文件的唯一标记,用于断点续传
(new WebUploader.Uploader()).md5File(file,0,10*1024*1024)
.progress(function(percentage){
$('#item1').find("p.state").text("正在读取文件信息...");
})
.then(function(val){
fileMd5=val;
$('#item1').find("p.state").text("成功获取文件信息...");
//获取文件信息后进入下一步
deferred.resolve();
});
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend:function(block){
console.log("beforeSend");
var deferred = WebUploader.Deferred();
$.ajax({
type:"POST",
url:"checkOrMerge?action=checkChunk",
data:{
//文件唯一标记
fileMd5:fileMd5,
//当前分块下标
chunk:block.chunk,
//当前分块大小
chunkSize:block.end-block.start
},
dataType:"json",
success:function(response){
if(response.ifExist){
console.log("分片存在:"+block.chunk)
//分块存在,跳过
deferred.reject();
}else{
console.log("分片不存在:"+block.chunk)
//分块不存在或不完整,重新发送该分块内容
deferred.resolve();
}
}
});
this.owner.options.formData.fileMd5 = fileMd5;
console.log("继续执行")
//deferred.resolve();
return deferred.promise();
},
//时间点3:所有分块上传成功后调用此函数
afterSendFile:function(file){
console.log("afterSendFile");
fileName=file.name; //为自定义参数文件名赋值
//如果分块上传成功,则通知后台合并分块
$.ajax({
type:"POST",
url:"checkOrMerge?action=mergeChunks",
data:{
fileMd5:fileMd5,
fileName:fileName,
ext:file.ext, //文件扩展名
projectName: $("#project option:selected").text() //项目名称
},
success:function(response){
var data= eval('(' + response + ')');
var filePath = data.path;
console.log(filePath);
//存储文件路径
var path=$("#filePath").val();
if(path!=""){
path=path+"|"+filePath;
}else{
path=filePath;
}
$("#filePath").val(path);
//alert("上传成功");
//var path = "uploads/"+fileMd5+".mp4";
//$("#item1").attr("src",path);
}
});
}
});
var uploader = WebUploader.create({
resize: false, // 不压缩image
swf: '/res/webuploader-0.1.5/uploader.swf', // swf文件路径
formData: { projectName: ""},
server: 'upload', // 文件接收服务端。
pick: '#picker', // 选择文件的按钮。可选
chunked: true, //是否要分片处理大文件上传
chunkSize:10*1024*1024, //分片上传,每片2M,默认是5M
//auto: false //选择文件后是否自动上传
chunkRetry : 2, //如果某个分片由于网络问题出错,允许自动重传次数
//runtimeOrder: 'html5,flash',
// 在上传当前文件时,准备好下一个文件
prepareNextFile:true,
duplicate : false,//是否重复上传(同时选择多个一样的文件),true可以重复上传
accept: {
title: '语音上传',
extensions: 'wav,zip,rar',
mimeTypes: 'audio/x-wav,.zip,.rar'
}
});
//当文件被加入队列之前触发
uploader.on('beforeFileQueued', function (file,data) {
//项目名称,在后台作为文件夹路径
var projcetName =$("#project").val();
if(projcetName==""){
$("#projectError").text("请先选择项目名称再上传文件!");
return false;
}else{
$("#projectError").text("");
}
//选定项目名称后 ,不可更改
$("#project").attr("disabled","disabled");
});
// 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) {
$list.append( '<div id="' + file.id + '" class="item">' +
'<span class="info">' + file.name + '</span>' +
'<b class="state" style="width:90px;">等待上传...</b>' +
'</div>' );
});
//绑定uploadBeforeSend事件来给每个独立的文件添加参数
uploader.on( 'uploadBeforeSend', function( block, data ) {
//设置data参数
data.projectName= $("#project").find("option:selected").text(); // 将存在file对象中的md5数据携带发送过去。
},2);
// 文件上传过程中创建进度条实时显示。
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="width: 0%">' +
'</div>' +
'</div>').appendTo( $li ).find('.progress-bar');
}
//进度条以百分比的形式显示
$li.find('b.state').text('上传中'+Math.floor(percentage * 100) + '%' );
$percent.css( 'width', percentage * 100 + '%' );
});
// 文件上传成功
uploader.on( 'uploadSuccess', function( file,ret) {
//返回文件的保存路径
if(ret.flag==true){
console.log(ret.path);
var path=$("#filePath").val();
if(path!=""){
path=path+"|"+ret.path;
}else{
path=ret.path;
}
$("#filePath").val(path);
}
$( '#'+file.id ).find('b.state').text('上传成功');
$( '#'+file.id ).find('b.state').css("color","green");
});
// 文件上传失败,显示上传出错
uploader.on( 'uploadError', function( file,ret ) {
status=false;
$( '#'+file.id ).find('b.state').text('上传失败');
});
// 完成上传完
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').fadeOut();
});
$btn.on('click', function () {
if ($(this).hasClass('disabled')) {
return false;
}
uploader.upload();
// if (state === 'ready') {
// uploader.upload();
// } else if (state === 'paused') {
// uploader.upload();
// } else if (state === 'uploading') {
// uploader.stop();
// }
});
});
</script>
4. 后台文件上传及合并代码
// 上传文件
@RequestMapping(value = "upload")
public void uploadFile(HttpServletRequest request,
HttpServletResponse response, String projectName)
throws IOException {
response.setCharacterEncoding("UTF-8");
Map map = new HashMap<>();
MultipartFile uploadFile = ((MultipartHttpServletRequest) request)
.getFile("file");
String fileMd5 = request.getParameter("fileMd5");
String chunk = request.getParameter("chunk");
String path = audioPath;
File file = new File(path + fileMd5);
if (!file.exists()) {
file.mkdirs();// 创建文件夹
}
// 保存文件
File chunkFile = new File(path + fileMd5 + "/" + chunk);
if (!chunkFile.exists()) {
chunkFile.createNewFile();
}
uploadFile.transferTo(chunkFile);
}
// 合并或验证分片文件是否需要上传
@RequestMapping(value = "checkOrMerge")
public void checkOrMerge(HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.setCharacterEncoding("UTF-8");
String savePath = audioPath;
String action = request.getParameter("action");
if (action.equals("mergeChunks")) {
// 合并文件
// 需要合并的文件的目录标记
// 文件MD5
String fileMd5 = request.getParameter("fileMd5");
// 文件名称
String fileName = request.getParameter("fileName");
// 文件扩展名
String suffixName = request.getParameter("ext");
// 项目名称
String projectName = request.getParameter("projectName");
System.out.println("fileMd5 :" + fileMd5);
System.out.println("fileName :" + fileName);
System.out.println("projectName :" + projectName);
// 读取目录里的所有文件
File f = new File(savePath + fileMd5);
File[] fileArray = f.listFiles(new FileFilter() {
// 排除目录只要文件
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return false;
}
return true;
}
});
System.out.println(" fileArray " + fileArray);
// 转成集合,便于排序
List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
// 需要合并的文件才进行排序,即分片的大小大于1
if (fileList != null && fileList.size() > 1) {
Collections.sort(fileList, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
// TODO Auto-generated method stub
if (Integer.parseInt(o1.getName()) < Integer
.parseInt(o2.getName())) {
return -1;
}
return 1;
}
});
}
// 合并的文件夹
File mergeFile = new File(savePath + projectName);
if (!mergeFile.exists()) {
mergeFile.mkdirs();
}
// UUID.randomUUID().toString()-->随机名
File outputFile = new File(savePath + projectName + "/" + fileName);
// 创建文件
outputFile.createNewFile();
// 输出流
FileChannel outChnnel = new FileOutputStream(outputFile)
.getChannel();
// 合并
FileChannel inChannel;
for (File file : fileList) {
inChannel = new FileInputStream(file).getChannel();
inChannel.transferTo(0, inChannel.size(), outChnnel);
inChannel.close();
// 删除分片
file.delete();
}
outChnnel.close();
// 清除文件夹
File tempFile = new File(savePath + fileMd5);
if (tempFile.isDirectory() && tempFile.exists()) {
tempFile.delete();
}
System.out.println("合并成功");
Map<String, String> map = new HashMap<>();
// 文件路径
map.put("path", projectName + "/" + fileName);
response.getWriter().print(JSON.toJSON(map));
} else if (action.equals("checkChunk")) {
// 检查当前分块是否上传成功
String fileMd5 = request.getParameter("fileMd5");
String chunk = request.getParameter("chunk");
String chunkSize = request.getParameter("chunkSize");
File checkFile = new File(savePath + fileMd5 + "/" + chunk);
response.setContentType("text/html;charset=utf-8");
// 检查文件是否存在,且大小是否一致
if (checkFile.exists()
&& checkFile.length() == Integer.parseInt(chunkSize)) {
// 上传过
response.getWriter().write("{\"ifExist\":1}");
} else {
// 没有上传过
response.getWriter().write("{\"ifExist\":0}");
}
}
}