原文参考于http://c7.gg/cds8e
其中修复了原文章中由于网络中断等问题,断点续传时会再次上传已经上传文件的问题.修复了不需要分片的文件,上传过程中会出现异常的问题.
- 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}");
-
}
-
}
-
}