转帖:http://blog.csdn.net/liuzuochen/article/details/1516522#d20101
1.引言
2.实现代码
2.2.1. AjaxWrapper.js
2.2.2. fileUpload.html
2.2.3. result.jsp
2.2.4. fileUpload.css
2.1.3. 后台服务类(BackGroundService)
3. 结语
1.引言
基于浏览器的文件上传,特别是对于通过<input type="file">标签来实现上传的情况,
存在着严重的性能问题,因为用户提交了文件之后,在浏览器把文件上传到服务器的过程中,界面看上去似乎是静止的,如果是小文件还好些,如果不幸需要上传的是几兆、几十兆甚至上百兆的文件,我相信那是一种非常痛苦的体验,我们中间的很多人应该都有过此种不堪的经历。(一笑)
现在我就针对这个问题给出一个解决方案,我们将实现一个具有监控能力的WEB上传的程序――它不仅把文件上传到服务器,而且"实时地"监视文件上传的实际过程。
解决方案的基本思路是这样的:
在介绍源代码之前,我们先来看看程序运行界面:
2. 实现代码
实现代码想当然的有服务器端代码和客户端代码(呵呵),我们先从服务器端开始。
2.1. 服务器端代码
2.1.1. 文件上传状态类(FileUploadStatus)
使用FileUploadStatus这个类记录文件上传状态,并将其作为服务器端与
web客户端之间通信的媒介,通过对这个类对象提供上传状态作为服务器回应发送给web客户端,
web客户端使用JavaScript获得文件上传状态。源代码如下:
/** *本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。 * *如需要转载,请注明作者。 * *作者:刘作晨 * */ packageliuzuochen.sample.upload; importjava.util.*; publicclassFileUploadStatus{ //上传用户地址 privateStringuploadAddr; //上传总量 privatelonguploadTotalSize=0; //读取上传总量 privatelongreadTotalSize=0; //当前上传文件号 privateintcurrentUploadFileNum=0; //成功读取上传文件数 privateintsuccessUploadFileCount=0; //状态 privateStringstatus=""; //处理起始时间 privatelongprocessStartTime=0l; //处理终止时间 privatelongprocessEndTime=0l; //处理执行时间 privatelongprocessRunningTime=0l; //上传文件URL列表 privateListuploadFileUrlList=newArrayList(); //取消上传 privatebooleancancel=false; //上传base目录 privateStringbaseDir=""; publicFileUploadStatus(){ } publicStringgetBaseDir(){ returnbaseDir; } publicvoidsetBaseDir(StringbaseDir){ this.baseDir=baseDir; } publicbooleangetCancel(){ returncancel; } publicvoidsetCancel(booleancancel){ this.cancel=cancel; } publicListgetUploadFileUrlList(){ returnuploadFileUrlList; } publicvoidsetUploadFileUrlList(ListuploadFileUrlList){ this.uploadFileUrlList=uploadFileUrlList; } publiclonggetProcessRunningTime(){ returnprocessRunningTime; } publicvoidsetProcessRunningTime(longprocessRunningTime){ this.processRunningTime=processRunningTime; } publiclonggetProcessEndTime(){ returnprocessEndTime; } publicvoidsetProcessEndTime(longprocessEndTime){ this.processEndTime=processEndTime; } publiclonggetProcessStartTime(){ returnprocessStartTime; } publicvoidsetProcessStartTime(longprocessStartTime){ this.processStartTime=processStartTime; } publiclonggetReadTotalSize(){ returnreadTotalSize; } publicvoidsetReadTotalSize(longreadTotalSize){ this.readTotalSize=readTotalSize; } publicintgetSuccessUploadFileCount(){ returnsuccessUploadFileCount; } publicvoidsetSuccessUploadFileCount(intsuccessUploadFileCount){ this.successUploadFileCount=successUploadFileCount; } publicintgetCurrentUploadFileNum(){ returncurrentUploadFileNum; } publicvoidsetCurrentUploadFileNum(intcurrentUploadFileNum){ this.currentUploadFileNum=currentUploadFileNum; } publicStringgetStatus(){ returnstatus; } publicvoidsetStatus(Stringstatus){ this.status=status; } publiclonggetUploadTotalSize(){ returnuploadTotalSize; } publicStringgetUploadAddr(){ returnuploadAddr; } publicvoidsetUploadTotalSize(longuploadTotalSize){ this.uploadTotalSize=uploadTotalSize; } publicvoidsetUploadAddr(StringuploadAddr){ this.uploadAddr=uploadAddr; } publicStringtoJSon(){ StringBufferstrJSon=newStringBuffer(); strJSon.append("{UploadTotalSize:").append(getUploadTotalSize()).append(",") .append("ReadTotalSize:").append(getReadTotalSize()).append(",") .append("CurrentUploadFileNum:").append(getCurrentUploadFileNum()) .append(",") .append("SuccessUploadFileCount:").append(getSuccessUploadFileCount()) .append(",") .append("Status:'").append(getStatus()).append("',") .append("ProcessStartTime:").append(getProcessStartTime()) .append(",") .append("ProcessEndTime:").append(getProcessEndTime()).append(",") .append("ProcessRunningTime:").append(getProcessRunningTime()) .append(",") .append("Cancel:").append(getCancel()).append("}"); returnstrJSon.toString(); } }
2.1.2. 文件上传状态侦听类(FileUploadListener)
使用Common-FileUpload 1.2版本(20070103)。此版本提供了能够监视文件上传情况的
ProcessListener接口,使开发者通过FileUploadBase类对象的setProcessListener方法植
入自己的Listener。 FileUploadListener类实现了ProcessListener,在整个文件上传过程
中,它对上传进度进行监控,并且根据上传 情况实时的更新上传状态Bean。源代码如下:
/** *本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。 * *如需要转载,请注明作者。 * *作者:刘作晨 * */ packageliuzuochen.sample.upload; importorg.apache.commons.fileupload.ProgressListener; importjavax.servlet.http.HttpServletRequest; publicclassFileUploadListenerimplementsProgressListener{ privateHttpServletRequestrequest=null; publicFileUploadListener(HttpServletRequestrequest){ this.request=request; } /** *更新状态 */ publicvoidupdate(longpBytesRead,longpContentLength,intpItems){ FileUploadStatusstatusBean=BackGroundService.getStatusBean(request); statusBean.setUploadTotalSize(pContentLength); //读取完成 if(pContentLength==-1){ statusBean.setStatus("完成对"+pItems+"个文件的读取:读取了"+pBytesRead +"bytes."); statusBean.setReadTotalSize(pBytesRead); statusBean.setSuccessUploadFileCount(pItems); statusBean.setProcessEndTime(System.currentTimeMillis()); statusBean.setProcessRunningTime(statusBean.getProcessEndTime()); //读取中 }else{ statusBean.setStatus("当前正在处理第"+pItems+"个文件:已经读取了"+pBytesRead +"/"+pContentLength+"bytes."); statusBean.setReadTotalSize(pBytesRead); statusBean.setCurrentUploadFileNum(pItems); statusBean.setProcessRunningTime(System.currentTimeMillis()); } BackGroundService.saveStatusBean(request,statusBean); } }
2.1.3. 后台服务类(BackGroundService)
BackGroundService这个Servlet类负责接收Form Post数据、回应状态轮询请求、处理取
消文件上传的请求。 尽管可以把这些功能相互分离开来,但为了简单明了,还是将它们放到
/** *本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。 * *如需要转载,请注明作者。 * *作者:刘作晨 * */ packageliuzuochen.sample.upload; importjava.io.File; importjava.io.IOException; importjava.util.List; importjavax.servlet.ServletException; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; importorg.apache.commons.fileupload.FileItem; importorg.apache.commons.fileupload.FileUploadException; importorg.apache.commons.fileupload.disk.DiskFileItemFactory; importorg.apache.commons.fileupload.servlet.*; publicclassBackGroundServiceextendsjavax.servlet.http.HttpServletimplements javax.servlet.Servlet{ publicstaticfinalStringUPLOAD_DIR="/upload"; publicstaticfinalStringDEFAULT_UPLOAD_FAILURE_URL="./result.jsp"; publicBackGroundService(){ super(); } protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{ doPost(request,response); } /** *从文件路径中取出文件名 */ privateStringtakeOutFileName(StringfilePath){ intpos=filePath.lastIndexOf(File.separator); if(pos>0){ returnfilePath.substring(pos+1); }else{ returnfilePath; } } /** *从request中取出FileUploadStatusBean */ publicstaticFileUploadStatusgetStatusBean(HttpServletRequestrequest){ BeanControlerbeanCtrl=BeanControler.getInstance(); returnbeanCtrl.getUploadStatus(request.getRemoteAddr()); } /** *把FileUploadStatusBean保存到类控制器BeanControler */ publicstaticvoidsaveStatusBean(HttpServletRequestrequest,FileUploadStatusstatusBean){ statusBean.setUploadAddr(request.getRemoteAddr()); BeanControlerbeanCtrl=BeanControler.getInstance(); beanCtrl.setUploadStatus(statusBean); } /** *删除已经上传的文件 */ privatevoiddeleteUploadedFile(HttpServletRequestrequest){ FileUploadStatussatusBean=getStatusBean(request); for(inti=0;i<satusBean.getUploadFileUrlList().size();i++){ FileuploadedFile=newFile(request.getRealPath(UPLOAD_DIR) +File.separator+satusBean.getUploadFileUrlList().get(i)); uploadedFile.delete(); } satusBean.getUploadFileUrlList().clear(); satusBean.setStatus("删除已上传的文件"); saveStatusBean(request,satusBean); } /** *上传过程中出错处理 */ privatevoiduploadExceptionHandle(HttpServletRequestrequest,StringerrMsg) throwsServletException,IOException{ //首先删除已经上传的文件 deleteUploadedFile(request); FileUploadStatussatusBean=getStatusBean(request); satusBean.setStatus(errMsg); saveStatusBean(request,satusBean); } /** *初始化文件上传状态Bean */ privateFileUploadStatusinitStatusBean(HttpServletRequestrequest){ FileUploadStatussatusBean=newFileUploadStatus(); satusBean.setStatus("正在准备处理"); satusBean.setUploadTotalSize(request.getContentLength()); satusBean.setProcessStartTime(System.currentTimeMillis()); satusBean.setBaseDir(request.getContextPath()+UPLOAD_DIR); returnsatusBean; } /** *处理文件上传 */ privatevoidprocessFileUpload(HttpServletRequestrequest,IOException{ DiskFileItemFactoryfactory=newDiskFileItemFactory(); //设置内存缓冲区,超过后写入临时文件 factory.setSizeThreshold(10240000); //设置临时文件存储位置 factory.setRepository(newFile(request.getRealPath("/upload/temp"))); ServletFileUploadupload=newServletFileUpload(factory); //设置单个文件的最大上传值 upload.setFileSizeMax(102400000); //设置整个request的最大值 upload.setSizeMax(102400000); upload.setProgressListener(newFileUploadListener(request)); //保存初始化后的FileUploadStatusBean saveStatusBean(request,initStatusBean(request)); StringforwardURL=""; try{ Listitems=upload.parseRequest(request); //获得返回url for(inti=0;i<items.size();i++){ FileItemitem=(FileItem)items.get(i); if(item.isFormField()){ forwardURL=item.getString(); break; } } //处理文件上传 for(inti=0;i<items.size();i++){ FileItemitem=(FileItem)items.get(i); //取消上传 if(getStatusBean(request).getCancel()){ deleteUploadedFile(request); break; } //保存文件 elseif(!item.isFormField()&&item.getName().length()>0){ StringfileName=takeOutFileName(item.getName()); FileuploadedFile=newFile( request.getRealPath(UPLOAD_DIR)+File.separator +fileName); item.write(uploadedFile); //更新上传文件列表 FileUploadStatussatusBean=getStatusBean(request); satusBean.getUploadFileUrlList().add(fileName); saveStatusBean(request,satusBean); Thread.sleep(500); } } }catch(FileUploadExceptione){ uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage()); }catch(Exceptione){ uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage()); } if(forwardURL.length()==0){ forwardURL=DEFAULT_UPLOAD_FAILURE_URL; } request.getRequestDispatcher(forwardURL).forward(request,response); } /** *回应上传状态查询 */ privatevoidresponseStatusQuery(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{ response.setContentType("text/xml"); response.setCharacterEncoding("UTF-8"); response.setHeader("Cache-Control","no-cache"); FileUploadStatussatusBean=getStatusBean(request); response.getWriter().write(satusBean.toJSon()); } /** *处理取消文件上传 */ privatevoidprocessCancelFileUpload(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{ FileUploadStatussatusBean=getStatusBean(request); satusBean.setCancel(true); saveStatusBean(request,satusBean); responseStatusQuery(request,response); } protectedvoiddoPost(HttpServletRequestrequest,IOException{ booleanisMultipart=ServletFileUpload.isMultipartContent(request); if(isMultipart){ processFileUpload(request,response); }else{ request.setCharacterEncoding("UTF-8"); if(request.getParameter("uploadStatus")!=null){ responseStatusQuery(request,response); } if(request.getParameter("cancelUpload")!=null){ processCancelFileUpload(request,response); } } } }
2.1.4. 文件上传状态控制类(BeanControler)
这是一个单例类,它的功能是为客户端保存文件上传状态,这里我没有使用Session来存储
文件上传状态,因为对于AJAX这种异步调用,服务器会开启不同的Session,所以无法通过Session
保存文件上传状态。 我并不认为这种方法最好,如果有更好的方法,欢迎大家一起讨论。 源代码如下:
/** *本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。 * *如需要转载,请注明作者。 * *作者:刘作晨 * */ packageliuzuochen.sample.upload; importjava.util.Vector; publicclassBeanControler{ privatestaticBeanControlerbeanControler=newBeanControler(); privateVectorvector=newVector(); privateBeanControler(){ } publicstaticBeanControlergetInstance(){ returnbeanControler; } /** *取得相应FileUploadStatus类对象的存储位置 */ privateintindexOf(StringstrID){ intnReturn=-1; for(inti=0;i<vector.size();i++){ FileUploadStatusstatus=(FileUploadStatus)vector.elementAt(i); if(status.getUploadAddr().equals(strID)){ nReturn=i; break; } } returnnReturn; } /** *取得相应FileUploadStatus类对象 */ publicFileUploadStatusgetUploadStatus(StringstrID){ return(FileUploadStatus)vector.elementAt(indexOf(strID)); } /** *存储FileUploadStatus类对象 */ publicvoidsetUploadStatus(FileUploadStatusstatus){ intnIndex=indexOf(status.getUploadAddr()); if(-1==nIndex){ vector.add(status); }else{ vector.insertElementAt(status,nIndex); vector.removeElementAt(nIndex+1); } } /** *删除FileUploadStatus类对象 */ publicvoidremoveUploadStatus(StringstrID){ intnIndex=indexOf(strID); if(-1!=nIndex) vector.removeElementAt(nIndex); } }
2.2. 客户端代码
客户端我们采用Prototype框架。
2.2.1. AjaxWrapper.js
AjaxWrapper.js对Prototype进行了封装。 源代码如下:
//类工具 varClassUtils=Class.create(); ClassUtils.prototype={ _ClassUtilsName:'ClassUtils',initialize:function(){ },/** *给类的每个方法注册一个对类对象的自我引用 *@paramreference对类对象的引用 */ registerFuncSelfLink:function(reference){ for(varninreference){ varitem=reference[n]; if(iteminstanceofFunction) item.$=reference; } } } //Ajax操作封装类: //由于调用AjaxRequest类进行XMLHTTPRequest操作时,this引用(指向当前的对象)会出现了callstack问题,从而指向当前的对象。 //所以,对putRequest、callBackHandler、以及callback方法都要使用arguments.callee.$来获得正确的类对象引用 varAjaxWrapper=Class.create(); AjaxWrapper.prototype={ debug_flag:false,xml_source:'',/** *初始化 *@paramisDebug是否显示调试信息 */ initialize:function(isDebug){ newClassUtils().registerFuncSelfLink(this); this.debug_flag=isDebug; },/** *以get的方式向server发送request *@paramurl *@paramparams *@paramcallBackFunction发送成功后回调的函数或者函数名 */ putRequest:function(url,params,callBackFunction){ varfuncHolder=arguments.callee.$; varxmlHttp=newAjax.Request(url,{ method:'get',parameters:params,requestHeaders:['my-header-encoding','utf-8'],onFailure:function(){ alert('对不起,网络通讯失败,请重新刷新!'); },onSuccess:function(transport){ },onComplete:function(transport){ funcHolder.callBackHandler.apply(funcHolder,[transport,callBackFunction]); } }); },/** *以post的方式向server发送xml请求 *@paramurl *@parampostDataBody *@paramcallBackFunction发送成功后回调的函数或者函数名 */ pushRequest:function(url,postDataBody,callBackFunction){ varfuncHolder=arguments.callee.$; varoptions={ method:'post',parameters:'',postBody:postDataBody,onFailure:function(transport){ alert('对不起,网络通讯失败,请重新发送!'); },callBackFunction]); } }; varxmlHttp=newAjax.Request(url,options); },/** *远程调用的回调处理 *@paramtransportxmlhttp的transport *@paramcallBackFunction回调时call的方法,可以是函数也可以是函数名 */ callBackHandler:function(transport,callBackFunction){ varfuncHolder=arguments.callee.$; if(transport.status!=200){ alert("获得回应失败,请求状态:"+transport.status); } else{ funcHolder.xml_source=transport.responseText; if(funcHolder.debug_flag) alert('callcallbackfunction'); if(typeof(callBackFunction)=='function'){ if(funcHolder.debug_flag){ alert('invokecallbackFunc'); } callBackFunction(transport.responseText); } else{ if(funcHolder.debug_flag){ alert('evalFunccallbackFunc'); } newexecute().evalFunc(callBackFunction,transport.responseText); } if(funcHolder.debug_flag) alert('endcallbackfunction'); } },//显示xml信息 showXMLResponse:function(){ varfuncHolder=arguments.callee.$; alert(funcHolder.xml_source); } } varXMLDomForAjax=Class.create(); XMLDomForAjax.prototype={ isDebug:false,//dom节点类型常量 ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12,initialize:function(isDebug){ newClassUtils().registerFuncSelfLink(this); this.isDebug=isDebug; },/** *建立跨平台的dom解析器 *@paramxmlxml字符串 *@returndom解析器 */ createDomParser:function(xml){ //codeforIE if(window.ActiveXObject){ vardoc=newActiveXObject("Microsoft.XMLDOM"); doc.async="false"; doc.loadXML(xml); } //codeforMozilla,Firefox,Opera,etc. else{ varparser=newDOMParser(); vardoc=parser.parseFromString(xml,"text/xml"); } returndoc; },/** *反向序列化xml到javascriptBean *@paramxmlxml字符串 *@returnjavascriptBean */ deserializedBeanFromXML:function(xml){ varfuncHolder=arguments.callee.$; vardoc=funcHolder.createDomParser(xml); //documentElement总表示文档的root varobjDomTree=doc.documentElement; varobj=newObject(); for(vari=0;i<objDomTree.childNodes.length;i++){ //获得节点 varnode=objDomTree.childNodes[i]; //取出其中的field元素进行处理 if((node.nodeType==funcHolder.ELEMENT_NODE)&&(node.tagName=='field')){ varnodeText=funcHolder.getNodeText(node); if(funcHolder.isDebug){ alert(node.getAttribute('name')+'type:'+node.getAttribute('type')+'text:'+nodeText); } varobjFieldValue=null; //如果为列表 if(node.getAttribute('type')=='java.util.List'){ if(objFieldValue&&typeof(objFieldValue)=='Array'){ if(nodeText.length>0){ objFieldValue[objFieldValue.length]=nodeText; } } else{ objFieldValue=newArray(); } } elseif(node.getAttribute('type')=='long' ||node.getAttribute('type')=='java.lang.Long' ||node.getAttribute('type')=='int' ||node.getAttribute('type')=='java.lang.Integer'){ objFieldValue=parseInt(nodeText); } elseif(node.getAttribute('type')=='double' ||node.getAttribute('type')=='float' ||node.getAttribute('type')=='java.lang.Double' ||node.getAttribute('type')=='java.lang.Float'){ objFieldValue=parseFloat(nodeText); } elseif(node.getAttribute('type')=='java.lang.String'){ objFieldValue=nodeText; } else{ objFieldValue=nodeText; } //赋值给对象 obj[node.getAttribute('name')]=objFieldValue; if(funcHolder.isDebug){ alert(eval('obj.'+node.getAttribute('name'))); } } elseif(node.nodeType==funcHolder.TEXT_NODE){ if(funcHolder.isDebug){ //alert('TEXT_NODE'); } } elseif(node.nodeType==funcHolder.CDATA_SECTION_NODE){ if(funcHolder.isDebug){ //alert('CDATA_SECTION_NODE'); } } } returnobj; },/** *获得dom节点的text */ getNodeText:function(node){ varfuncHolder=arguments.callee.$; //isthisatextorCDatanode? if(node.nodeType==funcHolder.TEXT_NODE||node.nodeType==funcHolder.CDATA_SECTION_NODE){ returnnode.data; } vari; varreturnValue=[]; for(i=0;i<node.childNodes.length;i++){ //采用递归算法 returnValue.push(funcHolder.getNodeText(node.childNodes[i])); } returnreturnValue.join(''); } } //委托者类 varDispatcher=Class.create(); Dispatcher.prototype={ name:'Dispatcher',//对class中的每个function都赋值一个值为this的$属性 initialize:function(){ newClassUtils().registerFuncSelfLink(this); },/** *委托调用 *@paramcaller调用者,func的拥有者 *@paramfunc如果是function对象,则使用Dispatcher对象自己的name作为参数;否则直接调用func */ dispatch:function(caller,func){ if(funcinstanceofFunction){ varfuncArguments=newArray(); funcArguments[0]=arguments.callee.$.name; func.apply(caller,funcArguments); } else{ eval(func); } } } //祈祷者类 varInvoker=Class.create(); Invoker.prototype={ name:'Invoker',invoke:function(showMsg){ alert(showMsg+"――this.name="+this.name); } }
2.2.2. fileUpload.html
fileUpload.html是文件上传界面。 源代码如下:
<html> <html> <head> <Metahttp-equiv="Content-Type"content="text/html;charset=GBK"> <scripttype="text/javascript"src="./javascript/prototype.js"></script> <scripttype="text/javascript"src="./javascript/AjaxWrapper.js"></script> <linkhref="./css/fileUpload.css"type="text/css"rel="stylesheet"/> <title>文件上传</title> </head> <body> <divid="controlPanel"> <divid="readme">测试说明:最大上传量:100M,单个文件最大长度:100M</div> <divid="uploadFileUrl"></div> <formid="fileUploadForm"name="fileUploadForm"action="./BackGroundService.action" enctype="multipart/form-data"method="post"> <inputtype="file"name="file"id="file"size="40"/><br> <inputtype="file"name="file"id="file"size="40"/><br> <inputtype="file"name="file"id="file"size="40"/><br> <inputtype="submit"name="uploadButton"id="uploadButton"value="开始上传"/> <inputtype="button"name="cancelUploadButton"id="cancelUploadButton"value="取消上传"/><br> </form> <divid="progressBar"> <divid="theMeter"> <divid="progressBarText"></div> <divid="totalProgressBarBox"> <divid="totalProgressBarBoxContent"></div> </div> </div> <divid="progressStatusText"></div> </div> </div> <script> Element.hide('progressBar'); Event.observe('fileUploadForm','submit',startProgress,false); Event.observe('cancelUploadButton','click',cancelProgress,false); //刷新上传状态 functionrefreshUploadStatus(){ varajaxW=newAjaxWrapper(false); ajaxW.putRequest( './BackGroundService.action','uploadStatus=',function(responseText){ eval("uploadInfo="+responseText); varprogressPercent=Math.ceil( (uploadInfo.ReadTotalSize)/uploadInfo.UploadTotalSize*100); $('progressBarText').innerHTML='上传处理进度:'+progressPercent+'%['+ (uploadInfo.ReadTotalSize)+'/'+uploadInfo.UploadTotalSize+'bytes]'+ '正在处理第'+uploadInfo.CurrentUploadFileNum+'个文件'+ '耗时:'+(uploadInfo.ProcessRunningTime-uploadInfo.ProcessStartTime)+'ms'; $('progressStatusText').innerHTML='反馈状态:'+uploadInfo.Status; $('totalProgressBarBoxContent').style.width=parseInt(progressPercent*3.5)+'px'; } ); } //上传处理 functionstartProgress(){ Element.show('progressBar'); $('progressBarText').innerHTML='上传处理进度:0%'; $('progressStatusText').innerHTML='反馈状态:'; $('uploadButton').disabled=true; varperiodicalExe=newPeriodicalExecuter(refreshUploadStatus,0.5); returntrue; } //取消上传处理 functioncancelProgress(){ $('cancelUploadButton').disabled=true; varajaxW=newAjaxWrapper(false); ajaxW.putRequest( './BackGroundService.action','cancelUpload=true',//因为form的提交,这可能不会执行 function(responseText){ eval("uploadInfo="+responseText); $('progressStatusText').innerHTML='反馈状态:'+uploadInfo.status; if(msgInfo.cancel=='true'){ alert('删除成功!'); window.location.reload(); }; } ); } </script> </body> </html>
2.2.3. result.jsp
<%@pagelanguage="java" contentType="text/html;charset=GBK" pageEncoding="GBK"%> <%@pageimport="liuzuochen.sample.upload.*"%> <!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN"> <html> <head> <Metahttp-equiv="Content-Type"content="text/html;charset=GBK"> <linkhref="./css/fileUpload.css"type="text/css"rel="stylesheet"/> <title>文件上传结果</title> </head> <body> <divid="resultPanel"> <div><span>上传文件列表:</span></div> <% FileUploadStatusfUploadStatus=BackGroundService.getStatusBean(request); for(inti=0;i<fUploadStatus.getUploadFileUrlList().size();i++){ StringfileName=(String)fUploadStatus.getUploadFileUrlList().get(i); Stringurl=fUploadStatus.getBaseDir()+"/"+fileName; %> <div><ahref="<%=url%>"_fcksavedurl="<%=url%>"_fcksavedurl="<%=url%>" _fcksavedurl="<%=url%>"><%=fileName%></a></div> <% } if(fUploadStatus.getStatus().indexOf("错误")>=0){ %> <divid='errorArea'><span>错误信息:<%=fUploadStatus.getStatus()%></span></div> <% } elseif(fUploadStatus.getCancel()){ %> <divid='normalMessageArea'><span>由于用户取消上传,所以已经上传的文件均被删除</span></div> <% } BeanControler.getInstance().removeUploadStatus(request.getRemoteAddr()); %> </div> </body> </html>
2.2.4. fileUpload.css
body{ color:#000; background-color:white; font:15pxGeorgia,"LucidaGrande",Arial,sans-serif; letter-spacing:0.01em; margin:15px; } #controlPanel,#resultPanel{ width:700px; margin:20pxauto; padding:25px; border:3pxsolidgray; -moz-border-radius:10px; background:#f8f8f8; } #errorArea{ width:400px; margin:20pxauto; padding:25px; border:3pxsolidgray; -moz-border-radius:10px; background:red; } #normalMessageArea{ width:400px; margin:20pxauto; padding:25px; border:3pxsolidgray; -moz-border-radius:10px; background:yellow; } #progressBar{padding-top:5px;} #totalProgressBarBox{ width:350px; height:20px; border:1pxinset; background:#eee; } #totalProgressBarBoxContent{ width:0; height:20px; border-right:1pxsolid#444; background:#9ACB34; }
2.3. 配置文件
把如下代码加入web.xml中完成Servlet的配置。
<servlet> <br><description> <br></description> <br><display-name> <br>BackGroundService</display-name> <br><servlet-name>BackGroundService</servlet-name> <br><servlet-class> <br>liuzuochen.sample.upload.BackGroundService</servlet-class> <br></servlet> <br><servlet-mapping> <servlet-name>BackGroundService</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
3. 结语
整个程序到这里就介绍完了,希望它多少能为您的工作或学习带来点儿帮助。