• 基于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-INFlib目录下。

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

    4. 服务器端实现。

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

    1. package com.ncu.upload;    
    2.     
    3. import java.util.*;    
    4.     
    5. public class FileUploadStatus {    
    6.     //上传总量    
    7.     private long uploadTotalSize=0;    
    8.     //读取上传总量    
    9.     private long readTotalSize=0;    
    10.     //当前上传文件号    
    11.     private int currentUploadFileNum=0;    
    12.     //成功读取上传文件数    
    13.     private int successUploadFileCount=0;    
    14.     //状态    
    15.     private String status="";    
    16.     //处理起始时间    
    17.     private long processStartTime=0l;    
    18.     //处理终止时间    
    19.     private long processEndTime=0l;    
    20.     //处理执行时间    
    21.     private long processRunningTime=0l;    
    22.     //上传文件URL列表    
    23.     private List uploadFileUrlList=new ArrayList();    
    24.     //取消上传    
    25.     private boolean cancel=false;    
    26.     //上传base目录    
    27.     private String baseDir="";    
    28.         
    29.     public String getBaseDir() {    
    30.         return baseDir;    
    31.     }    
    32.     public void setBaseDir(String baseDir) {    
    33.         this.baseDir = baseDir;    
    34.     }    
    35.     public boolean getCancel() {    
    36.         return cancel;    
    37.     }    
    38.     public void setCancel(boolean cancel) {    
    39.         this.cancel = cancel;    
    40.     }    
    41.     public List getUploadFileUrlList() {    
    42.         return uploadFileUrlList;    
    43.     }    
    44.     public void setUploadFileUrlList(List uploadFileUrlList) {    
    45.         this.uploadFileUrlList = uploadFileUrlList;    
    46.     }    
    47.     public long getProcessRunningTime() {    
    48.         return processRunningTime;    
    49.     }    
    50.     public void setProcessRunningTime(long processRunningTime) {    
    51.         this.processRunningTime = processRunningTime;    
    52.     }    
    53.     public long getProcessEndTime() {    
    54.         return processEndTime;    
    55.     }    
    56.     public void setProcessEndTime(long processEndTime) {    
    57.         this.processEndTime = processEndTime;    
    58.     }    
    59.     public long getProcessStartTime() {    
    60.         return processStartTime;    
    61.     }    
    62.     public void setProcessStartTime(long processStartTime) {    
    63.         this.processStartTime = processStartTime;    
    64.     }    
    65.     public long getReadTotalSize() {    
    66.         return readTotalSize;    
    67.     }    
    68.     public void setReadTotalSize(long readTotalSize) {    
    69.         this.readTotalSize = readTotalSize;    
    70.     }    
    71.     public int getSuccessUploadFileCount() {    
    72.         return successUploadFileCount;    
    73.     }    
    74.     public void setSuccessUploadFileCount(int successUploadFileCount) {    
    75.         this.successUploadFileCount = successUploadFileCount;    
    76.     }    
    77.     public int getCurrentUploadFileNum() {    
    78.         return currentUploadFileNum;    
    79.     }    
    80.     public void setCurrentUploadFileNum(int currentUploadFileNum) {    
    81.         this.currentUploadFileNum = currentUploadFileNum;    
    82.     }    
    83.     public String getStatus() {    
    84.         return status;    
    85.     }    
    86.     public void setStatus(String status) {    
    87.         this.status = status;    
    88.     }    
    89.     public long getUploadTotalSize() {    
    90.         return uploadTotalSize;    
    91.     }    
    92.     public void setUploadTotalSize(long uploadTotalSize) {    
    93.         this.uploadTotalSize = uploadTotalSize;    
    94.     }    
    95.         
    96. }  

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

    1. package com.ncu.upload;    
    2.     
    3. import javax.servlet.http.HttpSession;    
    4.     
    5. import org.apache.commons.fileupload.ProgressListener;    
    6.     
    7. public class UploadListener implements ProgressListener {    
    8.         
    9.     private HttpSession session=null;    
    10.         
    11.     public UploadListener (HttpSession session){    
    12.         this.session=session;    
    13.     }    
    14.     /**  
    15.      * 更新状态  
    16.      * @param pBytesRead 读取字节总数  
    17.      * @param pContentLength 数据总长度  
    18.      * @param pItems 当前正在被读取的field号  
    19.      */    
    20.     public void update(long pBytesRead, long pContentLength, int pItems) {    
    21.         FileUploadStatus fuploadStatus = UploadServlet.takeOutFileUploadStatusBean(this.session);    
    22.         fuploadStatus.setUploadTotalSize(pContentLength);    
    23.         //读取完成    
    24.         if (pContentLength == -1) {    
    25.             fuploadStatus.setStatus("完成对" + pItems + "个文件的读取:读取了 " + pBytesRead + "/"  + pContentLength+ " bytes.");    
    26.             fuploadStatus.setReadTotalSize(pBytesRead);    
    27.             fuploadStatus.setCurrentUploadFileNum(pItems);    
    28.             fuploadStatus.setProcessEndTime(System.currentTimeMillis());    
    29.             fuploadStatus.setProcessRunningTime(fuploadStatus.getProcessEndTime());    
    30.         }else{//读取过程中    
    31.                fuploadStatus.setStatus("当前正在处理第" + pItems+"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes.");    
    32.                fuploadStatus.setReadTotalSize(pBytesRead);    
    33.                fuploadStatus.setCurrentUploadFileNum(pItems);    
    34.                fuploadStatus.setProcessRunningTime(System.currentTimeMillis());    
    35.         }    
    36.         //System.out.println("已经读取:" + pBytesRead);    
    37.         UploadServlet.storeFileUploadStatusBean(this.session, fuploadStatus);    
    38.     }    
    39.     
    40. }    

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

    1. package com.ncu.upload;    
    2.     
    3. import java.io.*;    
    4. import java.util.List;    
    5.     
    6. import javax.servlet.ServletException;    
    7. import javax.servlet.http.HttpServletRequest;    
    8. import javax.servlet.http.HttpServletResponse;    
    9. import javax.servlet.http.HttpSession;    
    10.     
    11. import org.apache.commons.fileupload.FileItem;    
    12. import org.apache.commons.fileupload.FileUploadException;    
    13. import org.apache.commons.fileupload.disk.DiskFileItemFactory;    
    14. import org.apache.commons.fileupload.servlet.*;    
    15.     
    16. /**  
    17.  * Servlet implementation class for Servlet: UploadServlet  
    18.  *  
    19.  */    
    20.  public class UploadServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {    
    21.    static final long serialVersionUID = 1L;    
    22.        
    23.      public static final String UPLOAD_STATUS="UPLOAD_STATUS";    
    24.      public static final String UPLOAD_DIR="/upload";    
    25.        
    26.     public UploadServlet() {    
    27.         super();    
    28.     }      
    29.         
    30.     /**  
    31.      * 从文件路径中取出文件名  
    32.      * @param filePath  
    33.      * @return  
    34.      */    
    35.     private String takeOutFileName(String filePath){    
    36.         int pos=filePath.lastIndexOf(File.separator);    
    37.         if (pos>0){    
    38.             return filePath.substring(pos+1);    
    39.         }    
    40.         else{    
    41.             return filePath;    
    42.         }    
    43.     }    
    44.         
    45.     /**  
    46.      * 从request中取出FileUploadStatus Bean  
    47.      * @param request  
    48.      * @return  
    49.      */    
    50.     public static FileUploadStatus takeOutFileUploadStatusBean(HttpSession session){    
    51.         Object obj=session.getAttribute(UPLOAD_STATUS);    
    52.         if (obj!=null){    
    53.             return (FileUploadStatus)obj;    
    54.         }    
    55.         else{    
    56.             return null;    
    57.         }    
    58.     }    
    59.         
    60.     /**  
    61.      * 把FileUploadStatus Bean保存到session  
    62.      * @param request  
    63.      * @param uploadStatusBean  
    64.      */    
    65.     public static void storeFileUploadStatusBean(    
    66.             HttpSession session,    
    67.             FileUploadStatus uploadStatusBean){    
    68.         session.setAttribute(UPLOAD_STATUS,uploadStatusBean);    
    69.     }    
    70.         
    71.     /**  
    72.      * 删除已经上传的文件  
    73.      * @param request  
    74.      */    
    75.     private void deleteUploadedFile(HttpServletRequest request){    
    76.         FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession());    
    77.         for(int i=0;i<fUploadStatus.getUploadFileUrlList().size();i++){    
    78.             File uploadedFile = new File(request.getRealPath(UPLOAD_DIR)+    
    79.                     File.separator+fUploadStatus.getUploadFileUrlList().get(i));    
    80.             uploadedFile.delete();    
    81.         }    
    82.         fUploadStatus.getUploadFileUrlList().clear();    
    83.         fUploadStatus.setStatus("删除已上传的文件");    
    84.         storeFileUploadStatusBean(request.getSession(),fUploadStatus);    
    85.     }    
    86.         
    87.     /**  
    88.      * 上传过程中出错处理  
    89.      * @param request  
    90.      * @param errMsg  
    91.      * @throws IOException   
    92.      * @throws ServletException   
    93.      */    
    94.     private void uploadExceptionHandle(    
    95.             HttpServletRequest request,    
    96.             String errMsg) throws ServletException, IOException{    
    97.         //首先删除已经上传的文件    
    98.         deleteUploadedFile(request);    
    99.         FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession());    
    100.         fUploadStatus.setStatus(errMsg);    
    101.         storeFileUploadStatusBean(request.getSession(),fUploadStatus);    
    102.     }    
    103.         
    104.     /**  
    105.      * 初始化文件上传状态Bean  
    106.      * @param request  
    107.      * @return  
    108.      */    
    109.     private FileUploadStatus initFileUploadStatusBean(HttpServletRequest request){    
    110.         FileUploadStatus fUploadStatus=new FileUploadStatus();    
    111.         fUploadStatus.setStatus("正在准备处理");    
    112.         fUploadStatus.setUploadTotalSize(request.getContentLength());    
    113.         fUploadStatus.setProcessStartTime(System.currentTimeMillis());    
    114.         fUploadStatus.setBaseDir(request.getContextPath()+UPLOAD_DIR);    
    115.         return fUploadStatus;    
    116.     }    
    117.         
    118.     /**  
    119.      * 处理文件上传  
    120.      * @param request  
    121.      * @param response  
    122.      * @throws IOException   
    123.      * @throws ServletException   
    124.      */    
    125.     private void processFileUpload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{    
    126.         DiskFileItemFactory factory = new DiskFileItemFactory();    
    127.         //设置内存阀值,超过后写入临时文件    
    128.         //factory.setSizeThreshold(10240000*5);    
    129.         //设置临时文件存储位置    
    130.         //factory.setRepository(new File(request.getRealPath("/upload/temp")));    
    131.         ServletFileUpload upload = new ServletFileUpload(factory);    
    132.         //设置单个文件的最大上传size    
    133.         //upload.setFileSizeMax(10240000*5);    
    134.         //设置整个request的最大size    
    135.         //upload.setSizeMax(10240000*5);    
    136.         //注册监听类    
    137.         upload.setProgressListener(new UploadListener(request.getSession()));    
    138.         //保存初始化后的FileUploadStatus Bean    
    139.         storeFileUploadStatusBean(request.getSession(),initFileUploadStatusBean(request));    
    140.     
    141.         try {    
    142.             List items = upload.parseRequest(request);    
    143.             //处理文件上传    
    144.             for(int i=0;i<items.size();i++){    
    145.                 FileItem item=(FileItem)items.get(i);    
    146.     
    147.                 //取消上传    
    148.                 if (takeOutFileUploadStatusBean(request.getSession()).getCancel()){    
    149.                     deleteUploadedFile(request);    
    150.                     break;    
    151.                 }    
    152.                 //保存文件    
    153.                 else if (!item.isFormField() && item.getName().length()>0){    
    154.                     String fileName=takeOutFileName(item.getName());    
    155.                     File uploadedFile = new File(request.getRealPath(UPLOAD_DIR)+File.separator+fileName);    
    156.                     item.write(uploadedFile);    
    157.                     //更新上传文件列表    
    158.                     FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession());    
    159.                     fUploadStatus.getUploadFileUrlList().add(fileName);    
    160.                     storeFileUploadStatusBean(request.getSession(),fUploadStatus);    
    161.                     Thread.sleep(500);    
    162.                 }    
    163.             }    
    164.             
    165.         } catch (FileUploadException e) {    
    166.             e.printStackTrace();    
    167.             //uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage());    
    168.         } catch (Exception e) {    
    169.             // TODO Auto-generated catch block    
    170.             e.printStackTrace();    
    171.             //uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage());    
    172.         }    
    173.     }    
    174.         
    175.     /**  
    176.      * 回应上传状态查询  
    177.      * @param request  
    178.      * @param response  
    179.      * @throws IOException  
    180.      */    
    181.     private void responseFileUploadStatusPoll(HttpServletRequest request,HttpServletResponse response) throws IOException{    
    182.         FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS);    
    183.         //计算上传完成的百分比    
    184.         long percentComplete = (long)Math.floor(((double) fUploadStatus.getReadTotalSize()/(double) fUploadStatus.getUploadTotalSize())*100.0);    
    185.         System.out.println("com:"+percentComplete);    
    186.         response.setContentType("text/xml");    
    187.         response.setCharacterEncoding("UTF-8");    
    188.         response.setHeader("Cache-Control""no-cache");    
    189.         if ( ((long)fUploadStatus.getReadTotalSize() == (long)fUploadStatus.getUploadTotalSize()) || (fUploadStatus.getCancel() == true)){    
    190.         response.getWriter().write(fUploadStatus.getStatus().toString()+"success");    
    191.         }else{    
    192.             response.getWriter().write(fUploadStatus.getStatus().toString()+"<div class="prog-border"><div class="prog-bar" style=" "    
    193.                                 + percentComplete + "%;"></div></div>");    
    194.         }    
    195.     }    
    196.     /**  
    197.      * 处理取消文件上传  
    198.      * @param request  
    199.      * @param response  
    200.      * @throws IOException  
    201.      */    
    202.     private void processCancelFileUpload(HttpServletRequest request,HttpServletResponse response) throws IOException{    
    203.         FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS);    
    204.         fUploadStatus.setCancel(true);    
    205.         request.getSession().setAttribute(UPLOAD_STATUS, fUploadStatus);    
    206.         responseFileUploadStatusPoll(request,response);    
    207.     
    208.     }    
    209.         
    210.     /**  
    211.      * 在上传文件列表中查找与文件名相关的id  
    212.      * @param request  
    213.      * @param fileName 文件名  
    214.      * @return 找到返回id,否则返回-1  
    215.      */    
    216.     private int findFileIdInFileUploadedList(HttpServletRequest request,String fileName){    
    217.         FileUploadStatus fileUploadStatus=takeOutFileUploadStatusBean(request.getSession());    
    218.         for(int i=0;i<fileUploadStatus.getUploadFileUrlList().size();i++){    
    219.             if (fileName.equals((String)fileUploadStatus.getUploadFileUrlList().get(i))){    
    220.                 return i;    
    221.             }    
    222.         }    
    223.         return -1;    
    224.     }    
    225.         
    226.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    
    227.         doPost(request,response);    
    228.     }       
    229.         
    230.     
    231.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    
    232.         boolean isMultipart = ServletFileUpload.isMultipartContent(request);    
    233.             
    234.         if (isMultipart) {    
    235.             processFileUpload(request,response);    
    236.         }else{    
    237.             request.setCharacterEncoding("UTF-8");    
    238.                 
    239.             if (request.getParameter("uploadStatus")!=null){    
    240.                 responseFileUploadStatusPoll(request,response);    
    241.             }    
    242.             if (request.getParameter("cancelUpload")!=null){    
    243.                 processCancelFileUpload(request,response);    
    244.             }    
    245.         }    
    246.             
    247.     }                   
    248. }  

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

     

    5. 客户端实现

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

    1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
    2. <html>    
    3. <head>    
    4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">    
    5. <title>基于Ajax的上传文件显示进度条</title>    
    6.  <style>    
    7.   .prog-border {    
    8.   height: 15px;    
    9.    205px;    
    10.   background: #fff;    
    11.   border: 1px solid #000;    
    12.   margin: 0;    
    13.   padding: 0;    
    14.   }    
    15.   .prog-bar {    
    16.   height: 11px;    
    17.   margin: 2px;    
    18.   padding: 0px;    
    19.   background: #178399;    
    20.   font-size: 10pt;    
    21.   }    
    22.   body{    
    23.     font-family: Arial, Helvetica, sans-serif;    
    24.     font-size: 10pt;    
    25.   }    
    26.   </style>    
    27. <script language="javascript" type="text/javascript">    
    28. <!--    
    29.     //var userName=document.getElementById("userName").value;    
    30.     //创建跨浏览器的XMLHttpRequest对象    
    31.     var timer;    
    32. function startListener(){    
    33.     var xmlhttp;    
    34.     try{    
    35.     //IE 5.0     
    36.         xmlhttp = new ActiveXObject('Msxm12.XMLHTTP');    
    37.     }catch(e){    
    38.         try{    
    39.         //IE 5.5 及更高版本    
    40.             xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');    
    41.         }catch(e){    
    42.             try{    
    43.             //其他浏览器    
    44.                 xmlhttp = new XMLHttpRequest();    
    45.             }catch(e){}    
    46.         }    
    47.     }    
    48.     var progressStatusText = document.getElementById("progressBar");    
    49.     xmlhttp.open("get","UploadServlet?uploadStatus=true",true);    
    50.     /**此处Header设置非常重要,必须设置Content-type类型,负责会报错误    
    51.     */    
    52.      xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");    
    53.      xmlhttp.onreadystatechange = function(){    
    54.         if(xmlhttp.readyState == 4){    
    55.             if(xmlhttp.status == 200){    
    56.             progressStatusText.innerHTML = "";    
    57.             progressStatusText.innerHTML = xmlhttp.responseText;    
    58.             var temp = xmlhttp.responseText.indexOf("success");    
    59.             if (  temp > 0 ){    
    60.             window.clearTimeout(timer);    
    61.             }else{    
    62.             timer = window.setTimeout(startListener,1000);    
    63.             }    
    64.             }    
    65.         }    
    66.     }    
    67.     xmlhttp.send(null);    
    68. }    
    69. function startUpload(){    
    70.     timer = window.setTimeout(startListener,1000);    
    71.     return true;    
    72. }    
    73. function cancelUpload(){    
    74.     var xmlhttp;    
    75.     try{    
    76.     //IE 5.0     
    77.         xmlhttp = new ActiveXObject('Msxm12.XMLHTTP');    
    78.     }catch(e){    
    79.         try{    
    80.         //IE 5.5 及更高版本    
    81.             xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');    
    82.         }catch(e){    
    83.             try{    
    84.             //其他浏览器    
    85.                 xmlhttp = new XMLHttpRequest();    
    86.             }catch(e){}    
    87.         }    
    88.     }    
    89.     var progressStatusText = document.getElementById("progressBar");    
    90.     xmlhttp.open("get","UploadServlet?cancelUpload=true",true);    
    91.      xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");    
    92.     //xmlhttp.setRequestHeader("Content-type", "multipart/form-data");    
    93.     xmlhttp.onreadystatechange = function(){    
    94.         if(xmlhttp.readyState == 4){    
    95.             if(xmlhttp.status == 200){    
    96.             progressStatusText.innerHTML = "";    
    97.             progressStatusText.innerHTML = xmlhttp.responseText;    
    98.             }    
    99.         }    
    100.     }    
    101.     xmlhttp.send(null);    
    102.     return false;    
    103. }    
    104. //-->    
    105. </script>    
    106. </head>    
    107. <body>    
    108. <div id="controlPanel">    
    109.     <!-- 这个是隐藏的<iframe>作为表单提交后处理的后台目标    
    110.         通过表单form的target属性指定该<iframe>将返回信息显示在<iframe>框架中    
    111.   -->    
    112.   <iframe id='target_upload' name='target_upload' src='' style='display: none'></iframe>    
    113.     <form id="fileUploadForm" name="fileUploadForm" action="UploadServlet"     
    114.         enctype="multipart/form-data" method="post" onsubmit="return startUpload();" target="target_upload">    
    115.     <input type="file" name="file" id="file" size="40"/><br>    
    116.     <input type="submit" name="uploadButton" id="uploadButton" value="开始上传"/>    
    117.     <input type="button" name="cancelUploadButton" id="cancelUploadButton" value="取消上传" onclick="return cancelUpload();"/><br>    
    118.     </form>       
    119.     <div id="progressBar">    
    120.    </div>      
    121. </div>    
    122. </body>    
    123. </html>  

     至此,整个文件上传的实现到此完成,读者可以在此基础上,发挥自己的创新能力,去完善此实例。

    Good Luck!

  • 相关阅读:
    南阳理工ACM1076--方案数量
    南阳理工oj88--汉诺塔(一)
    杭电ACM1170--Balloon Comes!
    杭电ACM2011-- 多项式求和
    杭电ACM2080--夹角有多大II
    杭电ACM2076--夹角有多大(题目已修改,注意读题)
    请!继续!
    南阳理工ACM954--N!
    南阳理工ACM975--关于521
    致自己即将到来的人生
  • 原文地址:https://www.cnblogs.com/wepe/p/7424546.html
Copyright © 2020-2023  润新知