您现在的位置:首页 >> 前端 >> 内容

基于AJAX的文件上传显示进度条实现

时间:2016/12/6 9:32:00 点击:

  核心提示:基于Ajax的文件上传要实现的功能要求,要在用户提交了上传按钮请求后,客户端其页面要显示文件上传进度条。其整个功能时序图如图所示。简单的说,要实现在客户端显示进度条,需要做的是:当客户端提交上传文件请...

基于Ajax的文件上传要实现的功能要求,要在用户提交了上传按钮请求后,客户端其页面要显示文件上传进度条。

其整个功能时序图如图所示。

基于AJAX的文件上传显示进度条实现

 

简单的说,要实现在客户端显示进度条,需要做的是:当客户端提交上传文件请求后,服务器在上传文件的过程中,将上传进度情况保存到Session中,客户端周期性的发送请求来获取保存在Session中值,以获取上传文件的进度信息。

1.新建web工程AjaxUpload。

2.将commons-fileupload-1.2.1-bin.zip包中的commons-fileupload-1.2.1.jar文件和commons-io-1.4-bin.zip包中的commons-io-1.4.jar文件拷贝到web工程下的WEB-INF\lib目录下。

3.由于本实例涉及到多个类,处理此类问题最好是给相应的类打包进行管理。在web工程src目录下新建一个包com.ncu.upload。

4.服务器端实现。

首先要创建一个用来保存文件上传状态的类FileUploadStatus。其源码如下:

  1. packagecom.ncu.upload;
  2. importjava.util.*;
  3. publicclassFileUploadStatus{//上传总量
  4. privatelonguploadTotalSize=0;//读取上传总量
  5. privatelongreadTotalSize=0;//当前上传文件号
  6. privateintcurrentUploadFileNum=0;//成功读取上传文件数
  7. privateintsuccessUploadFileCount=0;//状态
  8. privateStringstatus="";//处理起始时间
  9. privatelongprocessStartTime=0l;//处理终止时间
  10. privatelongprocessEndTime=0l;//处理执行时间
  11. privatelongprocessRunningTime=0l;//上传文件URL列表
  12. privateListuploadFileUrlList=newArrayList();//取消上传
  13. privatebooleancancel=false;//上传base目录
  14. privateStringbaseDir="";
  15. publicStringgetBaseDir(){returnbaseDir;
  16. }publicvoidsetBaseDir(StringbaseDir){
  17. this.baseDir=baseDir;}
  18. publicbooleangetCancel(){returncancel;
  19. }publicvoidsetCancel(booleancancel){
  20. this.cancel=cancel;}
  21. publicListgetUploadFileUrlList(){returnuploadFileUrlList;
  22. }publicvoidsetUploadFileUrlList(ListuploadFileUrlList){
  23. this.uploadFileUrlList=uploadFileUrlList;}
  24. publiclonggetProcessRunningTime(){returnprocessRunningTime;
  25. }publicvoidsetProcessRunningTime(longprocessRunningTime){
  26. this.processRunningTime=processRunningTime;}
  27. publiclonggetProcessEndTime(){returnprocessEndTime;
  28. }publicvoidsetProcessEndTime(longprocessEndTime){
  29. this.processEndTime=processEndTime;}
  30. publiclonggetProcessStartTime(){returnprocessStartTime;
  31. }publicvoidsetProcessStartTime(longprocessStartTime){
  32. this.processStartTime=processStartTime;}
  33. publiclonggetReadTotalSize(){returnreadTotalSize;
  34. }publicvoidsetReadTotalSize(longreadTotalSize){
  35. this.readTotalSize=readTotalSize;}
  36. publicintgetSuccessUploadFileCount(){returnsuccessUploadFileCount;
  37. }publicvoidsetSuccessUploadFileCount(intsuccessUploadFileCount){
  38. this.successUploadFileCount=successUploadFileCount;}
  39. publicintgetCurrentUploadFileNum(){returncurrentUploadFileNum;
  40. }publicvoidsetCurrentUploadFileNum(intcurrentUploadFileNum){
  41. this.currentUploadFileNum=currentUploadFileNum;}
  42. publicStringgetStatus(){returnstatus;
  43. }publicvoidsetStatus(Stringstatus){
  44. this.status=status;}
  45. publiclonggetUploadTotalSize(){returnuploadTotalSize;
  46. }publicvoidsetUploadTotalSize(longuploadTotalSize){
  47. this.uploadTotalSize=uploadTotalSize;}
  48. }

由于要在客户端要显示进度条,所以在上传过程中服务器端需要监视和维护上传状态的信息,此过程需要处理的数据信息是:不断更新Session中保存的FileUploadStatus实例的信息,如:已经上传的字节数,上传文件的总大小等。FileUpload现在的1.2版本为监视上传进度提供了内建的支持,可以直接继承类ProgressListener,然后重载update()方法,在该方法中添加自己要处理的代码,最后在文件上传处理代码(后面会讲到)中通过为ServletFileUpload对象注册创建的监听类。监听类UploadListener的源代码如下:

  1. packagecom.ncu.upload;
  2. importjavax.servlet.http.HttpSession;
  3. importorg.apache.commons.fileupload.ProgressListener;
  4. publicclassUploadListenerimplementsProgressListener{
  5. privateHttpSessionsession=null;
  6. publicUploadListener(HttpSessionsession){this.session=session;
  7. }/**
  8. *更新状态*@parampBytesRead读取字节总数
  9. *@parampContentLength数据总长度*@parampItems当前正在被读取的field号
  10. */publicvoidupdate(longpBytesRead,longpContentLength,intpItems){
  11. FileUploadStatusfuploadStatus=UploadServlet.takeOutFileUploadStatusBean(this.session);fuploadStatus.setUploadTotalSize(pContentLength);
  12. //读取完成if(pContentLength==-1){
  13. fuploadStatus.setStatus("完成对"+pItems+"个文件的读取:读取了"+pBytesRead+"/"+pContentLength+"bytes.");fuploadStatus.setReadTotalSize(pBytesRead);
  14. fuploadStatus.setCurrentUploadFileNum(pItems);fuploadStatus.setProcessEndTime(System.currentTimeMillis());
  15. fuploadStatus.setProcessRunningTime(fuploadStatus.getProcessEndTime());}else{//读取过程中
  16. fuploadStatus.setStatus("当前正在处理第"+pItems+"个文件:已经读取了"+pBytesRead+"/"+pContentLength+"bytes.");fuploadStatus.setReadTotalSize(pBytesRead);
  17. fuploadStatus.setCurrentUploadFileNum(pItems);fuploadStatus.setProcessRunningTime(System.currentTimeMillis());
  18. }//System.out.println("已经读取:"+pBytesRead);
  19. UploadServlet.storeFileUploadStatusBean(this.session,fuploadStatus);}
  20. }


有了前面两个类的基础,下来我们可以动手去实现真正处理整个操作Servlet类。源代码如下。

  1. packagecom.ncu.upload;
  2. importjava.io.*;importjava.util.List;
  3. importjavax.servlet.ServletException;
  4. importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;
  5. importjavax.servlet.http.HttpSession;
  6. importorg.apache.commons.fileupload.FileItem;importorg.apache.commons.fileupload.FileUploadException;
  7. importorg.apache.commons.fileupload.disk.DiskFileItemFactory;importorg.apache.commons.fileupload.servlet.*;
  8. /**
  9. *ServletimplementationclassforServlet:UploadServlet*
  10. */publicclassUploadServletextendsjavax.servlet.http.HttpServletimplementsjavax.servlet.Servlet{
  11. staticfinallongserialVersionUID=1L;
  12. publicstaticfinalStringUPLOAD_STATUS="UPLOAD_STATUS";publicstaticfinalStringUPLOAD_DIR="/upload";
  13. publicUploadServlet(){
  14. super();}
  15. /**
  16. *从文件路径中取出文件名*@paramfilePath
  17. *@return*/
  18. privateStringtakeOutFileName(StringfilePath){intpos=filePath.lastIndexOf(File.separator);
  19. if(pos>0){returnfilePath.substring(pos+1);
  20. }else{
  21. returnfilePath;}
  22. }
  23. /***从request中取出FileUploadStatusBean
  24. *@paramrequest*@return
  25. */publicstaticFileUploadStatustakeOutFileUploadStatusBean(HttpSessionsession){
  26. Objectobj=session.getAttribute(UPLOAD_STATUS);if(obj!=null){
  27. return(FileUploadStatus)obj;}
  28. else{returnnull;
  29. }}
  30. /**
  31. *把FileUploadStatusBean保存到session*@paramrequest
  32. *@paramuploadStatusBean*/
  33. publicstaticvoidstoreFileUploadStatusBean(HttpSessionsession,
  34. FileUploadStatusuploadStatusBean){session.setAttribute(UPLOAD_STATUS,uploadStatusBean);
  35. }
  36. /***删除已经上传的文件
  37. *@paramrequest*/
  38. privatevoiddeleteUploadedFile(HttpServletRequestrequest){FileUploadStatusfUploadStatus=takeOutFileUploadStatusBean(request.getSession());
  39. for(inti=0;iFile.separator+fUploadStatus.getUploadFileUrlList().get(i));uploadedFile.delete();
  40. }fUploadStatus.getUploadFileUrlList().clear();
  41. fUploadStatus.setStatus("删除已上传的文件");storeFileUploadStatusBean(request.getSession(),fUploadStatus);
  42. }
  43. /***上传过程中出错处理
  44. *@paramrequest*@paramerrMsg
  45. *@throwsIOException*@throwsServletException
  46. */privatevoiduploadExceptionHandle(
  47. HttpServletRequestrequest,StringerrMsg)throwsServletException,IOException{
  48. //首先删除已经上传的文件deleteUploadedFile(request);
  49. FileUploadStatusfUploadStatus=takeOutFileUploadStatusBean(request.getSession());fUploadStatus.setStatus(errMsg);
  50. storeFileUploadStatusBean(request.getSession(),fUploadStatus);}
  51. /**
  52. *初始化文件上传状态Bean*@paramrequest
  53. *@return*/
  54. privateFileUploadStatusinitFileUploadStatusBean(HttpServletRequestrequest){FileUploadStatusfUploadStatus=newFileUploadStatus();
  55. fUploadStatus.setStatus("正在准备处理");fUploadStatus.setUploadTotalSize(request.getContentLength());
  56. fUploadStatus.setProcessStartTime(System.currentTimeMillis());fUploadStatus.setBaseDir(request.getContextPath()+UPLOAD_DIR);
  57. returnfUploadStatus;}
  58. /**
  59. *处理文件上传*@paramrequest
  60. *@paramresponse*@throwsIOException
  61. *@throwsServletException*/
  62. privatevoidprocessFileUpload(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{DiskFileItemFactoryfactory=newDiskFileItemFactory();
  63. //设置内存阀值,超过后写入临时文件//factory.setSizeThreshold(10240000*5);
  64. //设置临时文件存储位置//factory.setRepository(newFile(request.getRealPath("/upload/temp")));
  65. ServletFileUploadupload=newServletFileUpload(factory);//设置单个文件的最大上传size
  66. //upload.setFileSizeMax(10240000*5);//设置整个request的最大size
  67. //upload.setSizeMax(10240000*5);//注册监听类
  68. upload.setProgressListener(newUploadListener(request.getSession()));//保存初始化后的FileUploadStatusBean
  69. storeFileUploadStatusBean(request.getSession(),initFileUploadStatusBean(request));
  70. try{Listitems=upload.parseRequest(request);
  71. //处理文件上传for(inti=0;iFileItemitem=(FileItem)items.get(i);
  72. //取消上传if(takeOutFileUploadStatusBean(request.getSession()).getCancel()){
  73. deleteUploadedFile(request);break;
  74. }//保存文件
  75. elseif(!item.isFormField()&&item.getName().length()>0){StringfileName=takeOutFileName(item.getName());
  76. FileuploadedFile=newFile(request.getRealPath(UPLOAD_DIR)+File.separator+fileName);item.write(uploadedFile);
  77. //更新上传文件列表FileUploadStatusfUploadStatus=takeOutFileUploadStatusBean(request.getSession());
  78. fUploadStatus.getUploadFileUrlList().add(fileName);storeFileUploadStatusBean(request.getSession(),fUploadStatus);
  79. Thread.sleep(500);}
  80. }
  81. }catch(FileUploadExceptione){e.printStackTrace();
  82. //uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage());}catch(Exceptione){
  83. //TODOAuto-generatedcatchblocke.printStackTrace();
  84. //uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage());}
  85. }
  86. /***回应上传状态查询
  87. *@paramrequest*@paramresponse
  88. *@throwsIOException*/
  89. privatevoidresponseFileUploadStatusPoll(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{FileUploadStatusfUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS);
  90. //计算上传完成的百分比longpercentComplete=(long)Math.floor(((double)fUploadStatus.getReadTotalSize()/(double)fUploadStatus.getUploadTotalSize())*100.0);
  91. System.out.println("com:"+percentComplete);response.setContentType("text/xml");
  92. response.setCharacterEncoding("UTF-8");response.setHeader("Cache-Control","no-cache");
  93. if(((long)fUploadStatus.getReadTotalSize()==(long)fUploadStatus.getUploadTotalSize())||(fUploadStatus.getCancel()==true)){response.getWriter().write(fUploadStatus.getStatus().toString()+"success");
  94. }else{response.getWriter().write(fUploadStatus.getStatus().toString()+"vclass=\"prog-border\">+percentComplete+"%;\">");}
  95. }/**
  96. *处理取消文件上传*@paramrequest
  97. *@paramresponse*@throwsIOException
  98. */privatevoidprocessCancelFileUpload(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{
  99. FileUploadStatusfUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS);fUploadStatus.setCancel(true);
  100. request.getSession().setAttribute(UPLOAD_STATUS,fUploadStatus);responseFileUploadStatusPoll(request,response);
  101. }
  102. /**
  103. *在上传文件列表中查找与文件名相关的id*@paramrequest
  104. *@paramfileName文件名*@return 找到返回id,否则返回-1
  105. */privateintfindFileIdInFileUploadedList(HttpServletRequestrequest,StringfileName){
  106. FileUploadStatusfileUploadStatus=takeOutFileUploadStatusBean(request.getSession());for(inti=0;iif(fileName.equals((String)fileUploadStatus.getUploadFileUrlList().get(i))){returni;
  107. }}
  108. return-1;}
  109. protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
  110. doPost(request,response);}
  111.  
  112. protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{booleanisMultipart=ServletFileUpload.isMultipartContent(request);
  113. if(isMultipart){
  114. processFileUpload(request,response);}else{
  115. request.setCharacterEncoding("UTF-8");
  116. if(request.getParameter("uploadStatus")!=null){responseFileUploadStatusPoll(request,response);
  117. }if(request.getParameter("cancelUpload")!=null){
  118. processCancelFileUpload(request,response);}
  119. }
  120. }}

至此,服务器端的代码已经基本完成。

 

 

5.客户端实现

 

由于在上传文件时需要在同一页面显示对应的进度条控件,因此,在提交表单时当前页面不能被刷新。我们可以通过将表单提交至一个隐藏的iframe中来实现。关于Ajax的技术前面讲过,这里就不再细说,直接给出源代码如下:
至此,整个文件上传的实现到此完成,读者可以在此基础上,发挥自己的创新能力,去完善此实例。

Tags:基于 于A AJ JA 
作者:网络 来源:wepe12的博客