界面及模板代码
【包含组件调用方式--借鉴了huploadify的部分代码,向huploadify作者致敬。】
<script type="text/javascript" src="/static/UI/Huploadify3.0/jquery.Huploadify.v3.js"></script>
<style type="text/css">
</style>
<script type="text/javascript">
$(function(){
var up = $('#upload').Huploadify({
/**---上传按钮ui设置--**/
fileInputId:"fileInput",//文本上传框的id。
fileButtonTPL:document.getElementById("tpl_filebutton").innerHTML ,//模板字符串,请注意,这里用的模板引擎是laytpl,请使用laytpl的语法来写模板,具体可以参考demo页面的写法。
fileBrowserButtonId:"fileBrowserButton",//用于遮住文本框的按钮的id。
fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
buttonText:'选择文件',//上传按钮上的文字
multi:true,
/**列表模板**/
queuePanelId:"filelist",
fileQueueTPL:document.getElementById("tpl_filequeue").innerHTML,//文件列表的模板,请注意它也是用laytpl渲染的,注意语法,而且有几个文件列表里面有几个组件不能缺少(你可以隐藏他们)--除非你设置showFileQueue=false--否则,进度条,上传按钮,删除按钮请不要去掉了。
formData:{key:123456,key2:'vvvv'},
fileSizeLimit:99999999999,
showUploadedPercent:false,
showUploadedSize:true,
removeTimeout:9999999,
uploader:'handler_chunkuploader.jsp',
breakPoints:true,
fileSplitSize:1024*1024//断点续传的文件块大小,单位Byte,默认1M
//--几个方法设置。
,onBeforeSendBlob:function(fileMD5,chunkSequence,paras){
paras.chunks_seq=chunkSequence;
paras.chunk=chunkSequence;
paras.md5=fileMD5;
console.log(" before send blob: "+fileMD5+" chunk "+chunkSequence);
}
,onAfterSendBlob:function(fileMD5,chunkSequence,isIgnore){
console.log("after send blob:"+fileMD5+" chunk "+chunkSequence+" ingnore "+isIgnore);
}
,onBeforeSendFile:function(fileMD5){
console.log("before send file:"+fileMD5);
}
,onAfterSendFile:function(fileMD5,fileInfo){
console.log("after send file:"+fileMD5);
$.ajax({
url:"handler_combineChunks.jsp",
data:{
md5:fileMD5,
total:fileInfo.chunks,
name:fileInfo.fileName
},
success:function(data){
console.log("合并文件结果");
console.log(data);
}
});
}
});
$("#btn_upload").click(function(){
up.upload();
});
window.up=up;
});
</script>
</head>
<body>
<div id="upload"></div>
<div id="filelist" class="uploadify-queue">
</div>
<div>
<button id="btn_upload">开始上传</button>
</div>
<script type="text/html" id="tpl_filebutton">
{{#
var item=d;
var _multi="";
if(item.multi){
_multi=" multiple='' ";
}
var _accept=" accept='"+item.fileTypeExts+"' ";
}}
<input id="{{item.fileInputId}}" class="selectbtn" style="display:none;" type="file" name="fileselect[]" {{_multi}} {{_accept}} />
<a id="{{item.fileBrowserButtonId}}" href="javascript:void(0)" class="uploadify-button">{{item.buttonText}}</a>
</script>
<script type="text/html" id="tpl_filequeue">
{{#
var items=d.items;
if(items != undefined && items.length > 0){
for(var i=0;i < items.length;i++){
var item=items[i];
var _showUploadBtn="display:inline-block;";
if(item.file==null||item.file==undefined){
_showUploadBtn="display:none";
}
var _uploadedSize=(item.chunks <= 0)?0:item.fileSize*(item.uploadedChunks/item.chunks);
}}
<div _md5="{{item.md5}}" class="uploadify-queue-item">
<div class="uploadify-progress" lastloaded="609789">
<div class="uploadify-progress-bar" style="width: {{item.percent}}%;"></div>
</div>
<span class="up_percent">{{item.percent}}%</span>
<span class="progressnum">
<span class="uploadedsize">{{d.F.formatFileSize(_uploadedSize,false)}}</span>/<span class="totalsize">{{d.F.formatFileSize(item.fileSize,false)}}</span></span>
<span class="up_filename">{{item.fileName}}</span>
【<span class="upload_status">请再次选择文件</span>】
<!--<button class="uploadbtn" _md5="{{item.md5}}" style="{{_showUploadBtn}}">上传</button>-->
<button class="delfilebtn" _md5="{{item.md5}}">删除</button>
</div>
{{#
}
}
}}
</script>
js脚本代码
【注意,这个js使用了html5的特性,有文件切片,本地存储,所以,低版本的浏览器,ie9或者以上是不需要考虑的了。未来可能会考虑开发flash版本以作兼容。】
/**
* Created by edward on 2014/10/24.
* 该插件改自jquery.Huploadify 2.0,最大的特点是:
* 1、将显示模板分离出来放在页面上面,随意修改(但是涉及到id就不要修改了,html结构可以改)。上传按钮,文件列表等都可以自定义结构样式。
* 2、更新设置,现在可以随意设置要不要显示文件列表了,可以设置文件列表会显示到什么地方了。
* 3、可以设置是否自动开始了,也修正本地保存的已经上传的文件列表的存储方式,改为存储md5码。。
* 4、添加上传每一块之前的事件,添加自定义事件来控制是否跳过该chunk。
*
*/
(function($){
$.fn.Huploadify = function(opts){
//--通用变量
var _that=this;
//-组件设置
var defaults = {
/**---上传按钮ui设置--**/
fileInputId:"fileInput",//文本上传框的id。
fileButtonTPL:"" ,//模板字符串,请注意,这里用的模板引擎是laytpl,请使用laytpl的语法来写模板,具体可以参考demo页面的写法。
fileBrowserButtonId:"fileBrowserButton",//用于遮住文本框的按钮的id。
fileTypeExts:'*.*',//允许上传的文件类型,格式'*.jpg;*.doc'
buttonText:'选择文件',//上传按钮上的文字
/**--上传列表ui设置--**/
showFileQueue:true,//是否显示文件列表,假如显示的话,那么系统将按照模板将文件列表渲染到列表容器里面,再添加一些事件。
queuePanelId:"queuePanel",//存放上传文件列表的容器的id,假如你不需要显示文件列表及上传进度,那么你就不需要特别指定这个东西了,它将不起作用。
fileQueueTPL:"",//文件列表的模板,请注意它也是用laytpl渲染的,注意语法,而且有几个文件列表里面有几个组件不能缺少(你可以隐藏他们)--除非你设置showFileQueue=false--否则,进度条,上传按钮,删除按钮请不要去掉了。
showUploadedPercent:true,//是否实时显示上传的百分比,如20%
showUploadedSize:false,//是否实时显示已上传的文件大小,如1M/2M
removeTimeout: 1000,//上传完成后进度条的消失时间,单位毫秒
/**---其他功能设置--**/
multi:true,//是否允许选择多个文件
formData:null,//发送给服务端的参数,格式:{key1:value1,key2:value2}
fileObjName:'file',//在后端接受文件的参数名称,如PHP中的$_FILES['file']
fileSizeLimit:2048,//允许上传的文件大小,单位KB
uploader:'',//文件提交的地址
auto:false,//是否开启自动上传
method:'post',//发送请求的方式,get或post
//itemTemplate:itemTemp,//上传队列显示的模板--该参数丢弃
fileSplitSize:1024*1024//断点续传的文件块大小,单位Byte,默认1M
,storageKey:"huploadify_storage" //保存到本地的key,请注意,假如你希望不同的组件保存不同的文件信息,那么就修改一下这个位置。
//--几个方法设置。
,onBeforeSendBlob:function(fileMD5,chunkSequence,paras){
}
,onAfterSendBlob:function(fileMD5,chunkSequence,isIgnore){
}
,onBeforeSendFile:function(fileMD5,fileInfo){
}
,onAfterSendFile:function(fileMD5,fileInfo){
}
/**相关提醒及提示**/
};
var defaults = $.extend(defaults,opts);
//--相关模板引擎。
var _tpl_button=laytpl(defaults.fileButtonTPL);
var _tpl_list=laytpl(defaults.fileQueueTPL);
//定义一个通用函数集合
var F = {
//将文件的单位由bytes转换为KB或MB,若第二个参数指定为true,则永远转换为KB
formatFileSize : function(size,withKB){
if (size > 1024 * 1024 && !withKB){
size = (Math.round(size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
}
else{
size = (Math.round(size * 100 / 1024) / 100).toString() + 'KB';
}
return size;
},
//将输入的文件类型字符串转化为数组,原格式为*.jpg;*.png
getFileTypes : function(str){
var result = [];
var arr1 = str.split(";");
for(var i=0, len=arr1.length; i<len; i++){
result.push(arr1[i].split(".").pop());
}
return result;
},
//根据文件序号获取文件
getFile : function(index,files){
for(var i=0;i<files.length;i++){
if(files[i].index == index){
return files[i];
}
}
return null;
},
//根据后缀名获取文件Mime类型
getMimetype : function(name){
var mimetypeMap = {
zip : ['application/x-zip-compressed'],
jpg : ['image/jpeg'],
png : ['image/png'],
gif : ['image/gif'],
doc : ['application/msword'],
xls : ['application/msexcel'],
docx : ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
xlsx : ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
ppt : ['application/vnd.ms-powerpoint'],
pptx : ['application/vnd.openxmlformats-officedocument.presentationml.presentation'],
mp3 : ['audio/mp3'],
mp4 : ['video/mp4'],
pdf : ['application/pdf']
};
return mimetypeMap[name];
},
//获取上传组件accept的值
getAcceptString : function(str){
var types = F.getFileTypes(str);
var result = [];
for(var i=0,len=types.length;i<len;i++){
var mime = F.getMimetype(types[i]);
if(mime){
result.push(mime);
}
}
return result.join(',');
}
//--将模板字符串渲染出来。
,renderButtonTPL:function(){
var _tpl_str=defaults.fileButtonTPL;
var d={
fileInputId:defaults.fileInputId,
fileBrowserButtonId:defaults.fileBrowserButtonId,
buttonText:defaults.buttonText,
fileTypeExts:defaults.fileTypeExts,
multi:defaults.multi
};
var tpl=laytpl(_tpl_str);
var html=tpl.render(d);
return html;
}
,_filter: function(files) { //选择文件组的过滤方法
var arr = [];
var typeArray = F.getFileTypes(defaults.fileTypeExts);
if(typeArray.length>0){
for(var i=0,len=files.length;i<len;i++){
var f = files[i];
if(parseInt(F.formatFileSize(f.size,true))<=defaults.fileSizeLimit){
if($.inArray('*',typeArray)>=0 || $.inArray(f.name.split('.').pop(),typeArray)>=0){
arr.push(f);
}
else{
alert('文件 "'+f.name+'" 类型不允许!');
}
}
else{
alert('文件 "'+f.name+'" 大小超出限制!');
continue;
}
}
}
return arr;
}
};
//--文件上传状态枚举值。
var FileUploadStatus={
ready:"ready",
uploading:"uploading",
cancel:"cancel",
finished:"finished"
};
//--核心数据。
var _fileUploadInfo={
storageKey:defaults.storageKey//本地存储名称
,maxRecord:20 //最大记录条数,20.
,chunkSize:defaults.fileSplitSize //分块大小 5mb,最小单位为byte。
,files:[] //文件上传列表,里面的信息请参考下面的_fileInfo,在存储上面。fileInfo里面没有文件句柄file的参数,但是在运行时条件就必须有file这个句柄。
};
var _fileInfo={
md5:"" //md5码
,fileName:"" //文件名称
,fileSize:0 //文件大小
,lastModified: 1413766748000 //最近修改日期
,chunks:0 //文件分块数量
,uploadstatus:FileUploadStatus.ready //文件上传状态。
,file:null //文件句柄
,fileType:""
,percent:0 //上传的进度
,uploadedChunks:0 //已经上传了的分片数量
,uploaded:[] //文件已经上传了的分块序号列表
};
var _memoryFiles=[];//这是内存里面文件上传列表,里面的文件都包含了文件句柄,切记。
var _memoryFileInfo={
md5:"" //md5码
,fileName:"" //文件名称
,fileSize:0 //文件大小
,lastModified: 1413766748000 //最近修改日期
,chunks:0 //文件分块数量
,uploadstatus:FileUploadStatus.ready //文件上传状态。
,file:null //文件句柄
,fileType:""
,status:""
,percent:0
,uploadedChunks:0 //已经上传了的分片数量
,uploaded:[] //文件已经上传了的分块序号列表
};
//--任务队列。
/**
* 本地任务队列解释:
* 本地任务队列用于存储分片信息。
* */
var _taskQueue={
status:"ready" //任务有几种状态,begin 开始,finished 结束 cancel 取消 ready 就绪
};//格式如下:{md5_fileMD5:{chunk1:""}};以这个作为key。。以chunk1作为key。
var __taskItem={
};//当前任务的一些信息,只作为参考用的数据样本。
//--任务队列管理器。
var taskQueueManager={
//--添加任务。
addTask:function(fileMD5,sequence,begin,end){
if(_taskQueue["md5_"+fileMD5]!=undefined&&_taskQueue["md5_"+fileMD5]["chunk_"+sequence]!=undefined){
_taskQueue["md5_"+fileMD5]["chunk_"+sequence]["begin"]=begin;
_taskQueue["md5_"+fileMD5]["chunk_"+sequence]["end"]=end;
}
else if(_taskQueue["md5_"+fileMD5]!=undefined){
_taskQueue["md5_"+fileMD5]["chunk_"+sequence]={
md5:fileMD5,
chunk:sequence,
begin:begin,
end:end
};
}
else{
_taskQueue["md5_"+fileMD5]={};
_taskQueue["md5_"+fileMD5]["chunk_"+sequence]={
md5:fileMD5,
chunk:sequence,
begin:begin,
end:end
};
}
}
//--是否包含这个任务的信息。
,hasTask:function(fileMD5){
if(_taskQueue["md5_"+fileMD5]==undefined){
return false;
}
return true;
}
//--是否包含某个任务的某个分片信息。
,hasChunk:function(fileMD5,chunkSequence){
if(this.hasTask(fileMD5)==false){
return false;
}
if(_taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence]==undefined){
return false;
}
return true;
}
,getChunk:function(fileMD5,chunkSequence){
if(this.hasTask(fileMD5)==false){
return null;
}
if(_taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence]==undefined){
return null;
}
return _taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence];
}
//--删除任务。
,delTask:function(fileMD5){
if(this.hasTask(fileMD5)){
delete _taskQueue["md5_"+fileMD5];
return true;
}
else{
return false;
}
}
//--删除某个分片的信息。
//--该方法禁用!!!本地需要这一份记录
,delChunk:function(fileMD5,chunkSequence){
if(this.hasChunk(fileMD5,chunkSequence)){
delete _taskQueue["md5_"+fileMD5]["chunk_"+chunkSequence];
//--计算是否还有分片,假如没有的话,那么就删除这个任务算了。
var chunksTotal=0;
for(var key in _taskQueue["md5_"+fileMD5]){
if(key.indexOf('chunk_')!=-1){
chunksTotal++;
break;
}
}
if(chunksTotal<=0){
this.delTask(fileMD5);
}
return true;
}
return false;
}
//--还剩下多少个任务。
,getTaskCount:function(){
var _count=0;
for(var key in _taskQueue){
if(key.indexOf("md5_")!=-1){
_count++;
}
}
return _count;
}
//--设置任务状态。
,setStatus:function(status){
this.status=status;
}
//--获取任务状态。
,getStatus:function(){
return this.status;
}
//--获取第一个任务切片
/**
* 值得注意的是,第一个任务列表必然是内存文件的第一个文件的列表第一块。。。。
* */
,getFirstChunkTask:function(){
var _task="";
if(_fileUploadInfo.files.length<=0){
return null;
}
var _theMD5=_fileUploadInfo.files[0].md5;
if(_taskQueue["md5_"+_theMD5]==undefined||_taskQueue["md5_"+_theMD5]["chunk_0"]==undefined){
return null;
}
return _taskQueue["md5_"+_theMD5]["chunk_0"];
}
//--获取下一个任务切片
,getNextChunkTask:function(fileMD5,chunkSequence){
if(_fileUploadInfo.files.length<=0){
return null;
}
var _task="";
var c2=this.getChunk(fileMD5,chunkSequence+1);
if(c2!=null){
return c2;
}
//--假如c2是null,那么需要看下一片的位置。
var _nowFileIndex=-1;
var _cindex=-1;
//--从内存文件里面获取下一个文件的md5.
for(var i=0;i<_fileUploadInfo.files.length;i++){
var item=_fileUploadInfo.files[i];
if(fileMD5==item.md5){
_nowFileIndex=i;
break;
}
}
if(_nowFileIndex<0){
return this.getFirstChunkTask();
}
if(_nowFileIndex<0||(_nowFileIndex+1)>=_fileUploadInfo.files.length){
return null;
}
var _nextFileMD5=_fileUploadInfo.files[(_nowFileIndex+1)].md5;
if(_taskQueue["md5_"+_nextFileMD5]==undefined||_taskQueue["md5_"+_nextFileMD5]["chunk_0"]==undefined){
return null;
}
return _taskQueue["md5_"+_nextFileMD5]["chunk_0"];
}
//--获取当前任务文件的下一个任务切片
,getNextFileFirstChunkTask:function(fileMD5){
var _task="";
if(_fileUploadInfo.files.length<=0){
return null;
}
//--假如c2是null,那么需要看下一片的位置。
var _nowFileIndex=-1;
var _cindex=-1;
//--从内存文件里面获取下一个文件的md5.
for(var i=0;i<_fileUploadInfo.files.length;i++){
var item=_fileUploadInfo.files[i];
if(fileMD5==item.md5){
_nowFileIndex=i;
break;
}
}
if(_nowFileIndex<0||(_nowFileIndex+1)>=_fileUploadInfo.files.length){
return null;
}
var _nextFileMD5=_fileUploadInfo.files[(_nowFileIndex+1)].md5;
if(_taskQueue["md5_"+_nextFileMD5]==undefined||_taskQueue["md5_"+_nextFileMD5]["chunk_0"]==undefined){
return null;
}
return _taskQueue["md5_"+_nextFileMD5]["chunk_0"];
}
};
//--存储管理器
var storageManager={
//--初始化方法,将storage里面的信息读取出来初始化为内存里面的_fileUploadInfo及_memoryFiles
init:function(){
var jsonstr=localStorage.getItem(defaults.storageKey);
if(jsonstr==undefined||jsonstr==null||util.checkEmpty(jsonstr)==true){
return;
}
_fileUploadInfo= JSON.parse(jsonstr);
//--顺便初始化内存里面的Files。
_memoryFiles=[];
if(_fileUploadInfo.uploaded==undefined){
_fileUploadInfo.uploaded=[];
}
for(var i=0;i<_fileUploadInfo.files.length;i++){
var _newFile= $.extend({},_fileUploadInfo.files[i]);
_memoryFiles.push(_newFile);
}
}
//--将内存里面的文件上传信息重新保存到storage下面
,save:function(){
//--将_fileUploadInfo字符串化,保存到浏览器里面
var jsonstr= JSON.stringify(_fileUploadInfo);
localStorage.setItem(defaults.storageKey,jsonstr);
}
//--在上面使用了方法uploader的caculateFileInfo获得了相关信息以后,那么就需要将它添加或者更新到现有的内容数据里面去了(这部分只是更新数据,不包含持久化到storage里面,请自行调用storageManager.save()方法)
,updateMemoryFileList:function(resultFileInfo){
//--检查一下_memoryFiles有没有。
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==resultFileInfo.md5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile==null){
_mfile=resultFileInfo;
_mfile.percent=0;
_memoryFiles.push(_mfile);
}
else{
var _theOriginFile=_mfile.file;
delete _mfile.file;
var _theResFile=resultFileInfo.file;
delete resultFileInfo.file;
if(_mfile.percent==undefined){
_mfile.percent=0;
}
delete resultFileInfo.percent;
_mfile= $.extend(_mfile,resultFileInfo);
resultFileInfo.file=_theResFile;
_mfile.file=_theResFile;
}
//同步检查内存的文件列表映射。
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==resultFileInfo.md5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile==null){
var _theresFile=resultFileInfo.file;
delete resultFileInfo.file;
resultFileInfo.percent=0;
var _newobj= $.extend({},resultFileInfo);
_newobj.percent=0;
_fileUploadInfo.files.push(_newobj);
resultFileInfo.file=_theresFile;
}
else{
var _theresFile=resultFileInfo.file;
delete resultFileInfo.file;
if(_tfile.percent==undefined){
_tfile.percent=0;
}
delete resultFileInfo.percent;
var _tfile= $.extend({},_tfile,resultFileInfo);
resultFileInfo.file=_theresFile;
}
}
//--这部分是删除对应的md5内存文件信息,请注意,它不包含持久化到storage,请自行调用storageManager.save
,deleteMemoryFile:function(fileMD5){
//--检查一下_memoryFiles有没有。
var _mfile_index=-1;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile_index=i;
break;
}
}
//同步检查内存的文件列表映射。
var _tfile_index=-1;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile_index=i;
break;
}
}
if(_mfile_index!=-1){
_memoryFiles.splice(_mfile_index,1);
}
if(_tfile_index!=-1){
_fileUploadInfo.files.splice(_tfile_index,1);
}
}
//--将上传的进度保存到内存里面,请注意,这个也是没有自动更新到storage里面的,请自行调用save方法。
,updateFileProcess:function(fileMD5,uploadedChunks,percent){
//--检查一下_memoryFiles有没有。
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile!=null){
_mfile.uploadedChunks=uploadedChunks;
_mfile.percent=percent;
}
//同步检查内存的文件列表映射。
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile!=null){
_tfile.uploadedChunks=uploadedChunks;
_tfile.percent=percent;
}
}
//--将上传的信息的状态保存到内存里面,请注意,这个也是没有自动更新到storage里面的,请自行调用save方法。
,updateFileStatus:function(fileMD5,status){
//--检查一下_memoryFiles有没有。
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile!=null){
_mfile.uploadstatus=status;
}
//同步检查内存的文件列表映射。
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile!=null){
_tfile.uploadstatus=status;
}
}
//--判断该文件是否包含在内存文件里面
,hasFileInMemory:function(fileMD5){
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile==null){
return false;
}
else{
return true;
}
}
//--获取某个momery 里面的 文件信息。
,getMemoryFile:function(fileMD5){
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile=_memoryFiles[i];
break;
}
}
return _mfile;
}
,getFileInfo:function(fileMD5){
//同步检查内存的文件列表映射。
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
return _tfile;
}
//--判断当前文件已经上传的块是否包含这个。。
//--返回格式:{hasFile:是否有这个文件,status:是否已经上传了}
,isChunkUploaded:function(fileMD5,chunkSequence){
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile!=null){
var _has=false;
if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
for(var i=0;i<_tfile.uploaded.length;i++){
var _chunkseq=_tfile.uploaded[i];
if(_chunkseq==chunkSequence){
_has=true;
break;
}
}
}
return {
hasFile:true,
status:_has
};
}
else{
return {
hasFile:false,
status:false
};
}
}
//--添加一个上传块。
//--返回信息:{hasFile:是否有这个文件,hasChunk:是否已经有这一块了,status:是否添加成功}
,addUploadedChunk:function(fileMD5,chunkSequence){
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile!=null){
var _has=false;
if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
for(var i=0;i<_tfile.uploaded.length;i++){
var _chunkseq=_tfile.uploaded[i];
if(_chunkseq==chunkSequence){
_has=true;
break;
}
}
if(_has){
return {
hasFile:true,
hasChunk:true,
status:false
};
}
else{
_tfile.uploaded.push(chunkSequence);
return {
hasFile:true,
hasChunk:false,
status:true
};
}
}
else{
_tfile.uploaded.push(chunkSequence);
return {
hasFile:true,
hasChunk:false,
status:true
};
}
}
else{
return {
hasFile:false,
hasChunk:false,
status:false
};
}
}
//--删除某个文件的已经上传了的分块的信息。
//--返回信息:{hasFile:是否有这个文件,hasChunk:是否已经有这一块了,status:是否删除成功}
,delUploadedChunk:function(fileMD5,chunkSequence){
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==fileMD5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile!=null){
var _has=false;
var _chunkIndex=-1;
if(_tfile.uploaded!=undefined&&_tfile.uploaded.length>0){
for(var i=0;i<_tfile.uploaded.length;i++){
var _chunkseq=_tfile.uploaded[i];
if(_chunkseq==chunkSequence){
_has=true;
_chunkIndex=i;
break;
}
}
if(_has){
_tfile.uploaded.splice(_chunkIndex,1);
return {
hasFile:true,
hasChunk:true,
status:true
};
}
else{
return {
hasFile:true,
hasChunk:false,
status:false
};
}
}
else{
return {
hasFile:false,
hasChunk:false,
status:false
};
}
}
else{
return {
hasFile:false,
hasChunk:false,
status:false
};
}
}
//--该方法判断是否包含这个块。
//--该方法删除某个块序号。请注意,没有自动更新到storage,请自行调用save方法。
};
//--定时任务管理器
var timerManager={
interval:null
,canRun:false //外部用的接口,只有在canRun为true,busy为false的时候才能运行下一个任务。
,busy:false //内部是否有任务正在运行,有正在运行的任务就必须等待该任务,无论canRun是否为true。
,sleep:function(){
this.canRun=false;
}
,wake:function(){
this.canRun=true;
}
,setBusy:function(bool_busy){
this.busy=bool_busy;
}
,isBusy:function(){
return this.busy;
}
,init:function(opts){
if(this.interval!=null){
//--
//请先清除定时器
return;
}
var defaultsLV2={
speed:10
,runnable:function(){
}
,runRightNow:false
};
defaultsLV2=$.extend({},defaultsLV2,opts);
var _that=this;
this.interval=setInterval(function(){
if(_that.canRun&&_that.busy==false){
defaultsLV2.runnable();
}
else{
}
},defaultsLV2.speed);
this.canRun=defaultsLV2.runRightNow;
}
};
//-----界面控制器
//--按钮控制界面。
var uploadButtonUI={
//--初始化界面及将外界的事件作为响应时间
init:function(options){
var defaultsLV2={
onFileSelected:function(originFiles){} //回调函数,表示当用户选择了一个或多个文件以后执行的方法。
};
defaultsLV2= $.extend({},defaultsLV2,options);
var html= F.renderButtonTPL();
_that.html(html);
//--添加响应事件
$('#'+defaults.fileBrowserButtonId).on('click',function(){
$('#'+defaults.fileInputId).trigger('click');
});
document.getElementById(defaults.fileInputId).addEventListener("change", function() {
var files = document.getElementById(defaults.fileInputId).files;
files= F._filter(files);
defaultsLV2.onFileSelected(files);
});
}
};
//--列表控制界面。
var uploadListUI={
//--初始化列表
init:function(opts){
var defaultLV2={
onUploadClick:function(fileMD5){
}//点击上传按钮后的事件,注意,参数只有一个md5码,请自行通过这个码获取相关文件句柄。
,onDelClick:function(fileMD5){
}//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
};//设置
defaultLV2= $.extend({},defaultLV2,opts);
var html=_tpl_list.render({
F:F,
items:_memoryFiles
});
$("#"+defaults.queuePanelId).html(html);
//--初始化事件。
$("#"+defaults.queuePanelId).find(".uploadbtn").click(function(){
var _md5=$(this).attr("_md5");
defaultLV2.onUploadClick(_md5);
});
$("#"+defaults.queuePanelId).find(".delfilebtn").click(function(){
var _md5=$(this).attr("_md5");
defaultLV2.onDelClick(_md5);
});
},
//--添加新的
addFile:function(theFileInfo,opts){
var defaultLV2={
onUploadClick:function(fileMD5){
}//点击上传按钮后的事件,注意,参数只有一个md5码,请自行通过这个码获取相关文件句柄。
,onDelClick:function(fileMD5){
}//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
};//设置
defaultLV2= $.extend({},defaultLV2,opts);
var _arr=[];
_arr.push(theFileInfo);
var html=_tpl_list.render({
F:F,
items:_arr
});
var el=$(html);
$("#"+defaults.queuePanelId).append(el);
//--初始化事件。
$(el).find(".uploadbtn").click(function(){
var _md5=$(this).attr("_md5");
defaultLV2.onUploadClick(_md5);
});
$(el).find(".delfilebtn").click(function(){
var _md5=$(this).attr("_md5");
defaultLV2.onDelClick(_md5);
});
},
//--更新ui
editFile:function(theFileInfo){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+theFileInfo.md5+"']");
if(el.length<=0){
return;
}
var ui_fileName=$(el).find(".up_filename");
var ui_totalsize=$(el).find(".totalsize");
var ui_up_percent=$(el).find(".up_percent");
var ui_process=$(el).find(".uploadify-progress-bar");
ui_fileName.text(theFileInfo.fileName);
ui_totalsize.text(F.formatFileSize(theFileInfo.fileSize));
ui_up_percent.text(theFileInfo.percent+"%");
ui_process.css("width",theFileInfo.percent+"%");
},
//--判断是否有这个列表item。
hasFileItem:function(fileMD5){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return false;
}
return true;
},
//--通过md5,更新当前进度。
updatePercent:function(fileMD5,percent){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
var ui_up_percent=$(el).find(".up_percent");
var ui_process=$(el).find(".uploadify-progress-bar");
ui_up_percent.text(percent+"%");
ui_process.css("width",percent+"%");
},
//设置当前uiitem为上传中的状态。
setStatus_Uploading:function(fileMD5){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
var ui_Btn=$(el).find(".delfilebtn");
var ui_uploadBtn=$(el).find(".uploadbtn");
var ui_uploadStatus=$(el).find(".upload_status");
ui_uploadStatus.text("正在上传");
ui_uploadBtn.text("上传中");
ui_uploadBtn.attr("disabled","disabled");
ui_Btn.attr("disabled","disabled");
},
//设置当前某个ui的状态为准备上传
setStatus_Ready:function(fileMD5){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
var ui_Btn=$(el).find(".delfilebtn");
var ui_uploadBtn=$(el).find(".uploadbtn");
var ui_uploadStatus=$(el).find(".upload_status");
ui_uploadStatus.text("文件就绪");
ui_uploadBtn.text("上传");
ui_uploadBtn.removeAttr("disabled");
ui_Btn.css("display","inline-block");
ui_Btn.removeAttr("disabled");
ui_uploadBtn.css("display","inline-block");
},
hideFile:function(fileMD5,opts){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
var defaultsLV3={
speed:500,
callback:function(){}
};
defaultsLV3= $.extend({},defaultsLV3,opts);
el.slideUp(defaultsLV3.speed,function(){
defaultsLV3.callback();
});
},
//--更新界面,设置删除按钮是否可用。
enableDelButton:function(fileMD5,enabled){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
var ui_Btn=$(el).find(".delfilebtn");
if(enabled){
ui_Btn.removeAttr("disabled");
}
else{
ui_Btn.attr("disabled","disabled");
}
},
//--删除某个文件的列表ui
delFile:function(fileMD5){
var el=$("#"+defaults.queuePanelId).find(".uploadify-queue-item[_md5='"+fileMD5+"']");
if(el.length<=0){
return;
}
el.remove();
}
};
//--上传控制器。
var uploadManager={
//--当前上传的分块。
currentUpload:{
md5:null,
chunkSequence:0
},
nextUpload:{
md5:undefined,
chunkSequence:undefined
},
//--计算及完成某个文件的相关信息。譬如,md5,分块,文件名称等等。这也是异步的。>_<
caculateFileInfo:function(originFile,opts){
var defaultsLV2={
onFinished:function(theResultFileInfo){
}//计算完毕以后,会调用这个方法。
};
defaultsLV2= $.extend({},defaultsLV2,opts);
var _freder=new FileReader();
_freder.onload = function(e) {
var __resultInfo={
md5:"" //md5码
,fileName:"" //文件名称
,fileSize:0 //文件大小
,fileType:""
,lastModified:"2014-01-01" //最近修改日期
,chunks:0 //文件分块数量
,uploadstatus:FileUploadStatus.ready //文件上传状态。
,file:null //文件句柄
,percent:0
,uploadedChunks:0 //已经上传了的分片数量
,uploaded:[] //文件已经上传了的分块序号列表
};
var sparkMd5_partial=new SparkMD5();
sparkMd5_partial.appendBinary(e.target.result);
var partialMd5= sparkMd5_partial.end();
__resultInfo.md5=partialMd5;
__resultInfo.fileName=originFile.name;
__resultInfo.fileSize=originFile.size;
__resultInfo.fileType=originFile.type;
__resultInfo.file=originFile;
__resultInfo.lastModified=originFile.lastModified;
//--计算分块。
var _realKBs=Math.ceil(__resultInfo.fileSize/1024);
var chunks = Math.ceil(__resultInfo.fileSize /defaults.fileSplitSize);
__resultInfo.chunks=chunks;
//--调用回调函数。
defaultsLV2.onFinished(__resultInfo);
};
_freder.readAsBinaryString(originFile);
},
//--在上面使用了方法uploader的caculateFileInfo获得了相关信息以后,那么就需要将它添加或者更新到现有的内容数据里面去了(这部分只是更新数据,不包含持久化到storage里面,请自行调用storageManager.save()方法)
updateMemoryFileList:function(resultFileInfo){
//--检查一下_memoryFiles有没有。
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==resultFileInfo.md5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile==null){
_mfile=resultFileInfo;
_memoryFiles.push(_mfile);
}
else{
var _theOriginFile=_mfile.file;
delete _mfile.file;
var _theResFile=resultFileInfo.file;
delete resultFileInfo.file;
_mfile= $.extend(_mfile,resultFileInfo);
resultFileInfo.file=_theResFile;
_mfile=_theResFile;
}
//同步检查内存的文件列表映射。
var _tfile=null;
for(var i=0;i<_fileUploadInfo.files.length;i++){
if(_fileUploadInfo.files[i].md5==resultFileInfo.md5){
_tfile=_fileUploadInfo.files[i];
break;
}
}
if(_tfile==null){
var _theresFile=resultFileInfo.file;
delete resultFileInfo.file;
var _newobj= $.extend({},resultFileInfo);
_fileUploadInfo.files.push(_newobj);
resultFileInfo.file=_theresFile;
}
else{
var _theresFile=resultFileInfo.file;
delete resultFileInfo.file;
var _tfile= $.extend({},_tfile,resultFileInfo);
resultFileInfo.file=_theresFile;
}
},
//--获取当前文件的信息以后,那么就需要处理一下这些信息,变成任务队列的任务信息了。
setTask:function(TheResultInfo){
var _md5=TheResultInfo.md5;
if(_md5==undefined||_md5==null){
return;
}
//--判断内存里面有没有这份文件。
var res=storageManager.hasFileInMemory(_md5);
if(res==false){
return;
}
//--那么计算分片了。
for(var i=0;i<TheResultInfo.chunks;i++){
var _begin=0;
var _end=0;
var start = i * defaults.fileSplitSize;
var end = start + defaults.fileSplitSize >= TheResultInfo.fileSize ? TheResultInfo.fileSize : start + defaults.fileSplitSize;
taskQueueManager.addTask(TheResultInfo.md5,i,start,end);
}
},
//--上传单个文件。
uploadFile:function(fileMD5,opts){
var defaultsLV2={
beforeUpload:function(fileInfo){}
};
defaultsLV2= $.extend({},defaultsLV2,opts);
//--从memory文件列表中看看有没有这份文件信息,并且,这份文件信息的file不能为空。
var _mfile=null;
for(var i=0;i<_memoryFiles.length;i++){
if(_memoryFiles[i].md5==fileMD5){
_mfile=_memoryFiles[i];
break;
}
}
if(_mfile==null||_mfile.file==undefined||_mfile.file==null){
return;
}
//--方法内通用的变量。
var xhr = null;//请求。
var originalFile = _mfile.file;//保存原始未切割的文件引用
try{
xhr=new XMLHttpRequest();
}catch(e){
xhr=ActiveXobject("Msxml12.XMLHTTP");
}
file = originalFile.slice(uploadedSize,uploadedSize + option.fileSplitSize);
file.status = originalFile.status;
file.name = originalFile.name;
if(xhr.upload){
// 上传中
xhr.upload.onprogress = function(e) {
uploadManager.onProgress(file, originalFile, e.loaded, e.total);
};
xhr.onreadystatechange = function(e) {
if(xhr.readyState == 4){
uploadManager.uploadOver = true;
if(xhr.status == 200){
if(option.breakPoints){
//保存已上传文件大小
uploadedSize += option.fileSplitSize;
if(option.saveUploadedSize){
option.saveUploadedSize(originalFile,uploadedSize);
}
else{
alert('请先配置saveUploadedSize参数!');
return;
}
//继续上传其他片段
if(uploadedSize<originalFile.size){
uploadManager.uploadOver = false;
if(!uploadManager.uploadStopped){
file = originalFile.slice(uploadedSize,uploadedSize + option.fileSplitSize);
file.status = originalFile.status;
file.name = originalFile.name;
uploadManager._sendBlob(xhr, file, originalFile);
}
}
else{
uploadManager._uploadSucessCallback(originalFile, xhr);
}
}
else{
uploadManager._uploadSucessCallback(originalFile, xhr);
}
}
else {
originalFile.status = 3;//标记为上传失败
option.onUploadError && option.onUploadError(originalFile, xhr.responseText);
}
//无论上传成功或失败均执行下面的代码
if(uploadManager.uploadOver){
option.onUploadComplete && option.onUploadComplete(originalFile,xhr.responseText);
//检测队列中的文件是否全部上传完成,执行onQueueComplete
if(option.onQueueComplete){
var queueData = uploadManager._allFilesUploaded();
queueData && option.onQueueComplete(queueData);
}
//清除文件选择框中的已有值
uploadManager._getInputBtn().val('');
}
}
}
//开始上传文件
option.onUploadStart && option.onUploadStart(originalFile);
uploadManager._sendBlob(xhr, file, originalFile);
}
}
//上传文件片
,_sendBlob : function(xhr, file, originalfile){
if(file.status===0){
file.status = 1;//标记为正在上传
uploadManager.uploadStopped = false;
xhr.open(defaults.method, defaults.uploader, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
var fd = new FormData();
fd.append(defaults.fileObjName,file);
fd.append(defaults.fileObjName, originalfile.name);
fd.append('lastModifiedDate', originalfile.lastModifiedDate.getTime());
if(defaults.formData){
for(var key in defaults.formData){
fd.append(key,defaults.formData[key]);
}
}
xhr.send(fd);
}
}
,_chunkTask:function(xhr){
timerManager.setBusy(true);
var _that=this;
if(_that.currentUpload==undefined||_that.currentUpload.md5==undefined){
timerManager.sleep();
timerManager.setBusy(false);
return;
}
var _currentChunkTaskInfo= taskQueueManager.getChunk(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
if(_currentChunkTaskInfo==null){
//-没有这一块啊。。断了吧。
timerManager.sleep();
timerManager.setBusy(false);
return;
}
var _currentFileInfo=storageManager.getFileInfo(_that.currentUpload.md5);
//--是否当前文件的第一块?
if(_that.currentUpload.chunkSequence===0){
//-是,那么执行开始发送文件前的方法。
var _ex_fileInfo= $.extend({},_currentFileInfo);
defaults.onBeforeSendFile(_that.currentUpload.md5,_ex_fileInfo);
}
var __paras_to_send={};
//--执行上传分片前的方法。
defaults.onBeforeSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,__paras_to_send);
//--判断当前是否允许上传分片。
var _cStatus=storageManager.isChunkUploaded(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
if(_cStatus.status===true){
defaults.onAfterSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,true);
//--是否是最后一片了。
if(_currentFileInfo.chunks-1<=_that.currentUpload.chunkSequence){
//--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
taskQueueManager.delTask(_that.currentUpload.md5);
storageManager.deleteMemoryFile(_that.currentUpload.md5);
storageManager.save();
var _theMD5=_that.currentUpload.md5;
uploadListUI.hideFile(_theMD5,{
callback:function(){
uploadListUI.delFile(_theMD5);
}
});
//-是,那么执行开始发送文件前的方法。
var _ex_fileInfo= $.extend({},_currentFileInfo);
defaults.onAfterSendFile(_theMD5,_ex_fileInfo);
}
//--继续获取下一片。假如有下一片,那么就继续,假如没有,那么就算了。
var _nextChunkTask=taskQueueManager.getNextChunkTask(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
console.log("下一片");
console.log(_nextChunkTask);
if(_nextChunkTask==null){
_that.currentUpload={};
timerManager.sleep();
timerManager.setBusy(false);
}
else{
_that.currentUpload={
md5:_nextChunkTask.md5,
chunkSequence:_nextChunkTask.chunk
};
timerManager.setBusy(false);
timerManager.wake();
}
}
else{
//--没有上传,那么现在就来上传了。
_that.sendBlob(xhr,_currentChunkTaskInfo,__paras_to_send);
}
}
,sendBlob:function(xhr,chunkTaskInfo,paras){
timerManager.setBusy(true);
var memoryfile=storageManager.getMemoryFile(chunkTaskInfo.md5);
var originalfile=memoryfile.file;
//--获取任务信息并且切片。
xhr.open(defaults.method, defaults.uploader, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
var fd = new FormData();
//--切片
var chunkInfo= chunkTaskInfo;
var fileBlob= originalfile.slice(chunkInfo.begin,chunkInfo.end);
fd.append(defaults.fileObjName,fileBlob);
//fd.append(defaults.fileObjName, originalfile.name);
fd.append('lastModifiedDate', originalfile.lastModifiedDate.getTime());
if(defaults.formData){
for(var key in defaults.formData){
fd.append(key,defaults.formData[key]);
}
}
//--
if(paras!=null&¶s!=undefined){
for(var key in paras){
fd.append(key,paras[key]);
}
}
xhr.send(fd);
}
//--开始上传任务。
,uploadBegin:function(){
var _that=this;
if(taskQueueManager.getTaskCount()<=0){
return;
}
if(timerManager.interval!=null){
//--重新获取第一个切片。
//--开始执行任务。
var _chunkBegin=taskQueueManager.getFirstChunkTask();
if(_chunkBegin!=undefined&&_chunkBegin!=null){
_that.currentUpload={
md5:_chunkBegin.md5,
chunkSequence:_chunkBegin.chunk
};
}
timerManager.setBusy(false);
timerManager.wake();
return;
}
taskQueueManager.setStatus("begin");
uploadManager.currentUpload={};
//--新建一个request
//--方法内通用的变量。
var xhr = null;//请求。
try{
xhr=new XMLHttpRequest();
}catch(e){
xhr=ActiveXobject("Msxml12.XMLHTTP");
}
xhr.onreadystatechange = function(e) {
if(xhr.readyState == 4){
if(xhr.status == 200){
//--回调的时候处理相关操作
//--更新已经上传的分片的数据。
storageManager.addUploadedChunk(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
//--更新界面。
var _currentFileInfo=storageManager.getFileInfo(_that.currentUpload.md5);
var __percent=_currentFileInfo.chunks<=0?100:parseInt(_currentFileInfo.uploaded.length*100/_currentFileInfo.chunks);
storageManager.updateFileProcess(_that.currentUpload.md5,_currentFileInfo.uploaded.length,__percent);
storageManager.save();
uploadListUI.updatePercent(_that.currentUpload.md5,__percent);
//--是否已经结束了。
defaults.onAfterSendBlob(_that.currentUpload.md5,_that.currentUpload.chunkSequence,false);
//--是否是最后一片了。
if(_currentFileInfo.chunks-1<=_that.currentUpload.chunkSequence){
//--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
taskQueueManager.delTask(_that.currentUpload.md5);
storageManager.deleteMemoryFile(_that.currentUpload.md5);
storageManager.save();
var _theMD5=_that.currentUpload.md5;
uploadListUI.hideFile(_theMD5,{
callback:function(){
uploadListUI.delFile(_theMD5);
}
});
//-是,那么执行开始发送文件前的方法。
var _ex_fileInfo= $.extend({},_currentFileInfo);
defaults.onAfterSendFile(_theMD5,_ex_fileInfo);
}
//--还有没有下一片?
//--删除任务队列相关信息。
//--继续获取下一片。假如有下一片,那么就继续,假如没有,那么就算了。
var _nextChunkTask=taskQueueManager.getNextChunkTask(_that.currentUpload.md5,_that.currentUpload.chunkSequence);
console.log("下一片");
console.log(_nextChunkTask);
if(_nextChunkTask==null){
_that.currentUpload={};
timerManager.sleep();
timerManager.setBusy(false);
}
else{
_that.currentUpload={
md5:_nextChunkTask.md5,
chunkSequence:_nextChunkTask.chunk
};
timerManager.setBusy(false);
timerManager.wake();
}
}
else {
alert("上传失败!");
}
}
}
//--开始执行任务。
var _chunkBegin=taskQueueManager.getFirstChunkTask();
if(_chunkBegin!=undefined&&_chunkBegin!=null){
_that.currentUpload={
md5:_chunkBegin.md5,
chunkSequence:_chunkBegin.chunk
};
}
timerManager.init({
speed:10,
runnable:function(){
_that._chunkTask(xhr);
},
runRightNow:true
});
}
};
//--app总控制器。。将各个小部件都调用组织起来。
var app={
//--入口函数,初始化整个app。
init:function(){
//--获取本地上传数据并保存到内存中。
storageManager.init();
//--初始化上传按钮。
uploadButtonUI.init({
onFileSelected:function(originFiles){
//选择完文件,获得有效文件列表后,获得当前文件的列表信息。并且添加到列表ui里面去。
for(var i=0;i<originFiles.length;i++){
var _file=originFiles[i];
uploadManager.caculateFileInfo(_file,{
onFinished:function(theResultFileInfo){
storageManager.updateMemoryFileList(theResultFileInfo);
//--同步到本地存储。
storageManager.save();
//--更新到任务列表,随时准备上传。
uploadManager.setTask(theResultFileInfo);
//--更新到列表界面。
var _newFileInfo=storageManager.getMemoryFile(theResultFileInfo.md5);
if(uploadListUI.hasFileItem(theResultFileInfo.md5)){
uploadListUI.editFile(_newFileInfo);
uploadListUI.setStatus_Ready(theResultFileInfo.md5);
}
else{
uploadListUI.addFile(_newFileInfo,{
onDelClick:function(fileMD5){
app.deleteFile(fileMD5);
}//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
});
uploadListUI.setStatus_Ready(theResultFileInfo.md5);
}
}
});
}
}
});
//--初始化列表ui
uploadListUI.init({
onDelClick:function(fileMD5){
app.deleteFile(fileMD5);
}//点击删除按钮后的事件,请注意,参数只有一个md5码,请自行获取句柄及操作。
});
}
//--删除某个文件(以md5作为标志)的处理方式。
,deleteFile:function(fileMD5){
storageManager.deleteMemoryFile(fileMD5);
storageManager.save();
//--删除内存中这个文件的数据--上传完成就不需要记录了。别删除任务的上传历史记录了。。。。这是用来核对的。。//
if(_that.currentUpload!=undefined&&_that.currentUpload.md5!=undefined){
taskQueueManager.delTask(_that.currentUpload.md5);
}
uploadListUI.delFile(fileMD5);
}
};
//--初始化及开始运行app
app.init();
//--对外接口。
//--开始上传选定的文件及列表。
var returnObj={
upload:function(){
uploadManager.uploadBegin();
}
,sleep:function(){
timerManager.sleep();
}
,wake:function(){
timerManager.wake();
}
,debug:function(){
console.log("_fileUploadInfo");
console.log(_fileUploadInfo);
console.log("_memoryfileInfo");
console.log(_memoryFiles);
console.log("_task");
console.log(_taskQueue);
console.log(timerManager);
}
};
return returnObj;
}
})(jQuery)
服务端代码
处理分片的保存
<%@ page import="java.util.Hashtable" %>
<%@ page import="java.io.File" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="org.apache.commons.fileupload.FileItem" %>
<%@ page import="com.alibaba.fastjson.JSON" %>
<%@ page import="java.util.Date" %>
<%@ page import="org.apache.commons.fileupload.FileUploadException" %>
<%@ page import="Easis.Common.StringUtil" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
/**
* 在servlet或者jsp里面获取当前web的根目录绝对路径譬如:F:/projects/myCMS/这种形式。
* */
public static String getRealPath(HttpServletRequest request,String path){
String servletPath = request.getServletPath();
String realPath = request.getSession().getServletContext()
.getRealPath(servletPath);
String WebRootPath=realPath.replace('\\','/');
WebRootPath=WebRootPath.substring(0,WebRootPath.lastIndexOf(servletPath));
WebRootPath=(WebRootPath+"/"+path).replaceAll("//","/").replace('/','\\');
return WebRootPath;
}%>
<%
Hashtable<String,Object> _hash=new Hashtable<String, Object>(3);
String savePath = "C:/file_tmp/";
File f_d=new File(savePath);
if(!f_d.exists()){
f_d.mkdirs();
}
//--参数。
String fileMD5="";
int currentChunk=0;
//--接收图片
//--接收图片开始
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("utf-8");
try {
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
FileItem _fileItem=null;
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
if (item.isFormField()) {
System.out.println("表单参数名:" + item.getFieldName() + ",表单参数值:" + item.getString("UTF-8"));
if(item.getFieldName().equals("md5")){
fileMD5=item.getString("UTF-8");
}
else if(item.getFieldName().equals("chunks_seq")){
currentChunk= StringUtil.toInt(item.getString("UTF-8"));
}
} else {
if (item.getName() != null && !item.getName().equals("")) {
_fileItem=item;
}else{
}
}
}
if(_fileItem==null){
_hash.put("status",false);
_hash.put("message","没有上传任何文件!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
return;
}
String fileNameExt=_fileItem.getName().trim();// new String(_fileItem.getName().getBytes("gbk")).trim();
fileNameExt=fileNameExt.substring(fileNameExt.lastIndexOf('.')+1);
System.out.println(fileNameExt);
String fileName_2=request.getSession().getId()+((new Date()).getTime());
String _newFileName=fileName_2+"."+fileNameExt;
String realFilePath=savePath+File.separator+_newFileName;
//String realURL=_avatarRoot+"/"+_newFileName;
//--生成分片文件。
String _fileName=fileMD5+"_"+currentChunk+".chunk";
realFilePath=savePath+_fileName;
//--写入文件
File f1=new File(realFilePath);
if(f1.exists()){
f1.delete();
}
_fileItem.write(f1);
_hash.put("status",true);
_hash.put("message","成功写入分块文件!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
}catch(FileUploadException e){
e.printStackTrace();
_hash.put("status",false);
_hash.put("message","上传文件失败,文件流异常!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
return;
} catch (Exception e) {
e.printStackTrace();
_hash.put("status",false);
_hash.put("message","服务器500错误!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
return;
}
//--接收图片结束
%>
处理文件的合并
<%@ page import="java.util.Hashtable" %>
<%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %>
<%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="org.apache.commons.fileupload.FileItem" %>
<%@ page import="com.alibaba.fastjson.JSON" %>
<%@ page import="java.util.Date" %>
<%@ page import="org.apache.commons.fileupload.FileUploadException" %>
<%@ page import="Easis.Common.StringUtil" %>
<%@ page import="Easis.HTTP.RequestEX" %>
<%@ page import="java.io.*" %>
<%--
该文件为demo文件,切勿用于实际效果,该jsp作用:
结束某个文件的分块上传时候,需要合并所有分块成为一个文件。
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
/**
* 在servlet或者jsp里面获取当前web的根目录绝对路径譬如:F:/projects/myCMS/这种形式。
* */
public static String getRealPath(HttpServletRequest request,String path){
String servletPath = request.getServletPath();
String realPath = request.getSession().getServletContext()
.getRealPath(servletPath);
String WebRootPath=realPath.replace('\\','/');
WebRootPath=WebRootPath.substring(0,WebRootPath.lastIndexOf(servletPath));
WebRootPath=(WebRootPath+"/"+path).replaceAll("//","/").replace('/','\\');
return WebRootPath;
}%>
<%
Hashtable<String,Object> _hash=new Hashtable<String, Object>(3);
String savePath = "C:/file_tmp/";
String realFilePath="C:/file_real/";
File f_d=new File(savePath);
File f_r=new File(realFilePath);
if(!f_d.exists()){
f_d.mkdirs();
}
if(!f_r.exists()){
f_r.mkdirs();
}
//--参数
String fileMD5="";
int totalChunks=0;
String fileName="";
//--接收图片
//--接收图片开始
RequestEX req=new RequestEX(request);
fileMD5=req.getParaValueByBoth("md5");
totalChunks=StringUtil.toInt(req.getParaValueByBoth("total"));
fileName=req.getParaValueByBoth("name");
if(StringUtil.isNullOrEmpty(fileMD5)||totalChunks<=0||StringUtil.isNullOrEmpty(fileName)){
_hash.put("status",false);
_hash.put("message","无法合并任何文件,缺乏必要参数!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
return;
}
try {
String fileRealPath=realFilePath+fileName;
File file_now=new File(fileRealPath);
if(file_now.exists()){
file_now.delete();
}
file_now.createNewFile();
//--
for(int i=0;i<totalChunks;i++){
File f_tmp=new File(savePath+""+fileMD5+"_"+i+".chunk");
if(f_tmp.exists()==false){
System.out.println("无法找到:"+fileMD5+"_"+i+".chunk!!");
continue;
}
long len = f_tmp.length();
byte[] bytes = new byte[(int) len];
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(f_tmp));
int r = bufferedInputStream.read(bytes);
if (r != len) throw new IOException("读取文件不正确");
bufferedInputStream.close();
//--追加写入同样的文件。
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file_now,true));
bos.write(bytes);
//BufferedWriter out =new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f_1, true)));
bos.close();
}
//_fileItem.write(f1);
_hash.put("status",true);
_hash.put("message","成功上传图片!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
}catch (Exception e) {
e.printStackTrace();
_hash.put("status",false);
_hash.put("message","服务器500错误!");
_hash.put("url","");
out.write(JSON.toJSONString(_hash));
return;
}
//--接收图片结束
%>