分享

ajax 文件上传进度条

 时间要去哪 2014-10-09

一:方案分析

 

     基于浏览器的文件上传,为了有更好的用户体验,我们一般就设置一个旋转的图标,旋转的图标无法实时的监控文件上传情况。所以我们将实现一个如何实时的监控文件的上传。

 

参考资料:http://www.cnblogs.com/ybase/archive/2011/11/15/2249298.html 

 

技术问题分析:

  • 如何实现上传的功能
  • 如何实现上传文件的监听功能
  • 如何实现记录上传状态的功能
  • 客户端如何状态的实时显示

解决方案:

  

  • 如何实现上传的功能  ------使用apache的FileUpload组件上传文件
  • 如何实现上传文件的监听功能 ------使用ProgressListener监听文件状态
  • 如何实现记录上传状态的功能 ------使用session保存文件的状态
  • 客户端如何状态的实时显示 -------客户端使用AJAX来查询上传的状态

 

基本思路:

 

客户端:界面的提交的时候使用<iframe 来实现模拟的无刷新提交,然后在使用ajax来周期的访问servlet并返回sesson中最新的状态信息。

 

服务器端:在servlet介绍到请求的时候,区分请求的类型是上传的请求还是ajax询问的请求,如果是上传的请求,则执行上传的方法,并启动监听保存上传状态到session中。

 

 

 

 

 

 在介绍源代码之前,我们先来看看程序运行界面:

 

接下来是源文件的目录结构:

 


 


 二、实现代码

 

UploadFileProgressBar.java ------使用apache的FileUpload组件上传文件

Java代码  收藏代码
  1. package com.yangpan.upload.progressbar;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.OutputStream;  
  8. import java.io.PrintWriter;  
  9. import java.text.SimpleDateFormat;  
  10. import java.util.Arrays;  
  11. import java.util.Date;  
  12. import java.util.HashMap;  
  13. import java.util.Iterator;  
  14. import java.util.List;  
  15. import java.util.Random;  
  16.   
  17. import javax.servlet.ServletException;  
  18. import javax.servlet.http.HttpServlet;  
  19. import javax.servlet.http.HttpServletRequest;  
  20. import javax.servlet.http.HttpServletResponse;  
  21. import javax.servlet.http.HttpSession;  
  22.   
  23. import org.apache.commons.fileupload.FileItem;  
  24. import org.apache.commons.fileupload.FileItemFactory;  
  25. import org.apache.commons.fileupload.FileUpload;  
  26. import org.apache.commons.fileupload.FileUploadException;  
  27. import org.apache.commons.fileupload.ProgressListener;  
  28. import org.apache.commons.fileupload.disk.DiskFileItemFactory;  
  29. import org.apache.commons.fileupload.servlet.ServletFileUpload;  
  30. /** 
  31.  * 有进度条的上传 
  32.  *  
  33.  * @author 妞见妞爱 
  34.  * 
  35.  */  
  36. public class UploadFileProgressBar extends HttpServlet {  
  37.   
  38.     /** 
  39.      *  
  40.      */  
  41.     private static final long serialVersionUID = 1L;  
  42.     //定义允许上传的文件扩展名  
  43.     protected HashMap<String, String> extMap = new HashMap<String, String>();  
  44.     //最大文件大小 100 M  --测试用  
  45.     protected long  maxSize = 100 * 1024 * 1024;  
  46.     //上传文件的保存路径  
  47.     protected String configPath = "attached/";  
  48.   
  49.     protected String dirTemp = "attached/temp/";  
  50.       
  51.     protected String dirName = "file";  
  52.       
  53.     public void init() throws ServletException {  
  54.           
  55.         //定义允许上传的文件扩展名  
  56.         //extMap.put("image", "gif,jpg,jpeg,png,bmp");  
  57.         //extMap.put("flash", "swf,flv");  
  58.         //extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");  
  59.         extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar");   
  60.           
  61.           
  62.           
  63.     }  
  64.   
  65.       
  66.     /** 
  67.      * 处理上传文件 
  68.      * @param request 
  69.      * @param response 
  70.      * @throws ServletException 
  71.      * @throws IOException 
  72.      */  
  73.     @SuppressWarnings("unchecked")  
  74.     public void processFileUpload(HttpServletRequest request, PrintWriter out)  
  75.         throws ServletException, IOException {  
  76.        
  77.         //文件保存目录路径  
  78.         String savePath = this.getServletContext().getRealPath("/") + configPath;  
  79.           
  80.         // 临时文件目录   
  81.         String tempPath = this.getServletContext().getRealPath("/") + dirTemp;  
  82.           
  83.         SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");  
  84.         String ymd = sdf.format(new Date());  
  85.         savePath += "/" + ymd + "/";  
  86.         //创建文件夹  
  87.         File dirFile = new File(savePath);  
  88.         if (!dirFile.exists()) {  
  89.             dirFile.mkdirs();  
  90.         }  
  91.           
  92.         tempPath += "/" + ymd + "/";  
  93.         //创建临时文件夹  
  94.         File dirTempFile = new File(tempPath);  
  95.         if (!dirTempFile.exists()) {  
  96.             dirTempFile.mkdirs();  
  97.         }  
  98.           
  99.         DiskFileItemFactory  factory = new DiskFileItemFactory();  
  100.         factory.setSizeThreshold(20 * 1024 * 1024); //设定使用内存超过5M时,将产生临时文件并存储于临时目录中。     
  101.         factory.setRepository(new File(tempPath)); //设定存储临时文件的目录。     
  102.   
  103.         ServletFileUpload upload = new ServletFileUpload(factory);  
  104.         upload.setHeaderEncoding("UTF-8");  
  105.           
  106.         //创建一个进度监听器  
  107.         FileUploadProgressListener progressListener = new FileUploadProgressListener(request);  
  108.         upload.setProgressListener(progressListener);  
  109.           
  110.         try {  
  111.             List items = upload.parseRequest(request);  
  112.             Iterator itr = items.iterator();  
  113.             while (itr.hasNext()) {  
  114.                 FileItem item = (FileItem) itr.next();  
  115.                 String fileName = item.getName();  
  116.                 long fileSize = item.getSize();  
  117.                 if (!item.isFormField()) {  
  118.                     //检查文件大小  
  119.                     if(item.getSize() > maxSize){  
  120.                         setStatusMsg(request, "1", "上传文件大小超过限制。");  
  121.                         return;  
  122.                     }  
  123.                     //检查扩展名  
  124.                     String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();  
  125.                     if(!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)){  
  126.                         setStatusMsg(request, "1", "上传文件扩展名是不允许的扩展名。只允许" + extMap.get(dirName) + "格式。");  
  127.                         return;  
  128.                     }  
  129.   
  130.                     SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");  
  131.                     String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;  
  132.                     try{  
  133.                         File uploadedFile = new File(savePath, newFileName);  
  134.                           
  135.                         /* 
  136.                          * 第一种方法 
  137.                          *  
  138.                          * 好处: 一目了然..简单啊... 
  139.                          * 弊端: 这种方法会导致上传的文件大小比原来的文件要大 
  140.                          *  
  141.                          * 推荐使用第二种 
  142.                          */  
  143.                         //item.write(uploadedFile);  
  144.                         //--------------------------------------------------------------------  
  145.                         //第二种方法  
  146.                         OutputStream os = new FileOutputStream(uploadedFile);    
  147.                         InputStream is = item.getInputStream();    
  148.                         byte buf[] = new byte[1024];//可以修改 1024 以提高读取速度  
  149.                         int length = 0;    
  150.                         while( (length = is.read(buf)) > 0 ){    
  151.                             os.write(buf, 0, length);    
  152.                         }    
  153.                         //关闭流    
  154.                         os.flush();  
  155.                         os.close();    
  156.                         is.close();    
  157.                             
  158.                     }catch(Exception e){  
  159.                         setStatusMsg(request, "1", "上传文件失败。");  
  160.                         return;  
  161.                     }  
  162.                     setStatusMsg(request, "2", "文件上传成功!");  
  163.                 }  
  164.             }  
  165.               
  166.         } catch (FileUploadException e) {  
  167.             // TODO Auto-generated catch block  
  168.             e.printStackTrace();  
  169.         }  
  170.           
  171.           
  172.     }  
  173.   
  174.     /** 
  175.      *  
  176.      * 错误信息的处理 
  177.      *  
  178.      * @param request 
  179.      * @param error -- 1 : 错误  0 : 正常  2 : 上传完成 
  180.      * @param message 
  181.      */  
  182.     private void setStatusMsg(HttpServletRequest request, String error, String message) {  
  183.         HttpSession session = request.getSession();  
  184.         FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");  
  185.         status.setError(error);  
  186.         status.setStatusMsg(message);  
  187.     }  
  188.       
  189.     /** 
  190.      *  
  191.      * 获取状态信息 
  192.      *  
  193.      * @param request 
  194.      * @param out 
  195.      */  
  196.     @SuppressWarnings("unused")  
  197.     private void getStatusMsg(HttpServletRequest request,PrintWriter out){  
  198.         HttpSession session = request.getSession();  
  199.         FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");  
  200.         System.out.println("输出信息对象:"+status);  
  201.         out.println(status.toJSon());  
  202.     }  
  203.       
  204.       
  205.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  206.             throws ServletException, IOException {  
  207.   
  208.         request.setCharacterEncoding("UTF-8");  
  209.         response.setContentType("text/html; charset=UTF-8");  
  210.   
  211.         PrintWriter out = response.getWriter();  
  212.         //检查输入请求是否为multipart表单数据。     
  213.         boolean isMultipart= FileUpload.isMultipartContent(request);     
  214.         if (isMultipart) {  
  215.             processFileUpload(request, out);  
  216.         }else {  
  217.             if (request.getParameter("uploadStatus") != null) {  
  218.                 //response.setContentType("text/xml");  
  219.                 //response.setHeader("Cache-Control", "no-cache");  
  220.                 System.out.println("ajax 读取状态····");  
  221.                 getStatusMsg(request, out);  
  222.             }  
  223.         }  
  224.           
  225.         out.flush();  
  226.         out.close();  
  227.     }  
  228.       
  229.        
  230.   
  231. }  

 

 

FileUploadProgressListener------使用ProgressListener监听文件状态

 

Java代码  收藏代码
  1. package com.yangpan.upload.progressbar;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpSession;  
  5.   
  6. import org.apache.commons.fileupload.ProgressListener;  
  7.   
  8. /** 
  9.  * 上传监听器 
  10.  *   
  11.  * @author 妞见妞爱 
  12.  * 
  13.  */  
  14. public class FileUploadProgressListener implements ProgressListener {  
  15.   
  16.     private HttpSession session;  
  17.     private long megaBytes = -1;  
  18.   
  19.       
  20.     public FileUploadProgressListener(HttpServletRequest request) {  
  21.         session = request.getSession();  
  22.         FileUploadStatus newUploadStatus = new FileUploadStatus();  
  23.         session.setAttribute("upladeStatus", newUploadStatus);  
  24.     }  
  25.   
  26.     /** 
  27.      *  
  28.      * 为了进度条监听器不会引起性能问题 
  29.      * 解决方案,是减少进步条的活动数 
  30.      * 比如,只有当上传了1兆字节的时候才反馈给用户 
  31.      *  
  32.      */  
  33.     public void update(long pBytesRead, long pContentLength, int pItems) {  
  34.         /*long mBytes = pBytesRead / 1048576; 
  35.         if (megaBytes == mBytes) { 
  36.             return; 
  37.         } 
  38.         megaBytes = mBytes;*/  
  39.         FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");  
  40.         if (pContentLength == -1) {  
  41.             status.setStatusMsg("已完成" + pItems +"个文件的上传");  
  42.         }else {  
  43.             status.setStatusMsg("正在上传第" + pItems +"个文件");  
  44.         }  
  45.         status.setError("0");  
  46.         status.setReadedBytes(pBytesRead);  
  47.         status.setTotalBytes(pContentLength);  
  48.         status.setCurrentItem(pItems);  
  49.     }  
  50.       
  51. }  

 

 

FileUploadStatus------使用session保存文件的状态

Java代码  收藏代码
  1. package com.yangpan.upload.progressbar;  
  2.   
  3.   
  4. /** 
  5.  *  
  6.  * 上传状态类 
  7.  *  
  8.  * @author 妞见妞爱 
  9.  * 
  10.  */  
  11. public class FileUploadStatus {  
  12.       
  13.     private String statusMsg = "";  
  14.     private long readedBytes = 0L;  
  15.     private long totalBytes = 0L;  
  16.     private int currentItem = 0;  
  17.     // 1 : 错误  0 : 正常  2:完成  
  18.     private String error = "0";  
  19.       
  20.     public String getStatusMsg() {  
  21.         return statusMsg;  
  22.     }  
  23.   
  24.     public void setStatusMsg(String statusMsg) {  
  25.         this.statusMsg = statusMsg;  
  26.     }  
  27.   
  28.     public long getReadedBytes() {  
  29.         return readedBytes;  
  30.     }  
  31.   
  32.     public void setReadedBytes(long readedBytes) {  
  33.         this.readedBytes = readedBytes;  
  34.     }  
  35.   
  36.     public long getTotalBytes() {  
  37.         return totalBytes;  
  38.     }  
  39.   
  40.     public void setTotalBytes(long totalBytes) {  
  41.         this.totalBytes = totalBytes;  
  42.     }  
  43.   
  44.     public int getCurrentItem() {  
  45.         return currentItem;  
  46.     }  
  47.   
  48.     public void setCurrentItem(int currentItem) {  
  49.         this.currentItem = currentItem;  
  50.     }  
  51.    
  52.     public String getError() {  
  53.         return error;  
  54.     }  
  55.   
  56.     public void setError(String error) {  
  57.         this.error = error;  
  58.     }  
  59.   
  60.     public String toJSon() {  
  61.         StringBuffer strJSon = new StringBuffer();  
  62.         strJSon.append("{");  
  63.         strJSon.append("error:'").append(error).append("',");  
  64.         strJSon.append("statusMsg:'").append(statusMsg).append("',");  
  65.         strJSon.append("readedBytes:'").append(readedBytes).append("',");  
  66.         strJSon.append("totalBytes:'").append(totalBytes).append("',");  
  67.         strJSon.append("currentItem:'").append(currentItem).append("'");  
  68.         strJSon.append("}");  
  69.         return strJSon.toString();  
  70.     }     
  71. }  

 

 

web.xml

 

Xml代码  收藏代码
  1. <servlet>  
  2.     <servlet-name>UploadFileProgressBar</servlet-name>  
  3.     <servlet-class>  
  4.         com.yangpan.upload.progressbar.UploadFileProgressBar  
  5.     </servlet-class>  
  6. </servlet>  
  7.   
  8. <servlet-mapping>  
  9.     <servlet-name>UploadFileProgressBar</servlet-name>  
  10.     <url-pattern>/servlet/UploadFileProgressBar</url-pattern>  
  11. </servlet-mapping>  

 

 

客户端代码:

Html代码  收藏代码
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>  
  2. <%  
  3.     String path = request.getContextPath();  
  4.  %>  
  5. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  6. <html>  
  7.   <head>  
  8.       
  9.     <title>妞见妞爱 QQ:609865047</title>  
  10.       
  11.     <meta http-equiv="pragma" content="no-cache">  
  12.     <meta http-equiv="cache-control" content="no-cache">  
  13.     <meta http-equiv="expires" content="0">  
  14.     <link rel="stylesheet" href="css/jquery-ui-1.8.16.custom.css" type="text/css"></link>  
  15.     <link rel="stylesheet" href="css/main.css" type="text/css"></link>  
  16.     <script type="text/javascript" src="js/jquery-1.6.2.min.js" ></script>  
  17.     <script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js" ></script>  
  18.     <script type="text/javascript" src="js/script.js" ></script>  
  19.     <script type="text/javascript">  
  20.           
  21.           
  22.         function uploadFile(){  
  23.             var file = document.getElementById("file").value;  
  24.             if(file == ""){  
  25.                 alert("请选项上传文件!");  
  26.                 return false;  
  27.             }  
  28.             document.getElementById("editForm").submit();  
  29.             document.getElementById("updateButton").disabled = "disabled";  
  30.             ajaxBackState();  
  31.         }  
  32.           
  33.         var bool = true;  
  34.           
  35.         var readedBytes = 0;  
  36.         var totalBytes = 0;  
  37.         function ajaxBackState(){  
  38.               
  39.             $.post("<%=path%>/servlet/UploadFileProgressBar",{uploadStatus:"uploadStatus"},function(result){  
  40.                 var obj = eval("("+result+")");  
  41.                 var txt = document.getElementById("txt");  
  42.                   
  43.                 readedBytes = obj["readedBytes"];  
  44.                 totalBytes = obj["totalBytes"];  
  45.                   
  46.                 if(obj["error"] == "0"){  
  47.                     txt.innerHTML = obj["statusMsg"]+":"+ readedBytes +"/"+totalBytes;  
  48.                 }else if(obj["error"] == "1"){  
  49.                     txt.innerHTML = obj["statusMsg"];  
  50.                     bool = false;  
  51.                 }else{  
  52.                     txt.innerHTML = obj["statusMsg"]+":"+ readedBytes +"/"+totalBytes;  
  53.                     bool = false;  
  54.                 }  
  55.             });  
  56.             document.getElementById("bytes").innerHTML += readedBytes + "<br>";  
  57.             progressbar(readedBytes,totalBytes)  
  58.             if(bool){  
  59.                     setTimeout("ajaxBackState()",1000);                       
  60.             }  
  61.         }  
  62.           
  63.         function progressbar(readedBytes,totalBytes){  
  64.                    
  65.              $('#progress').children('.pbar').progressbar();  
  66.              iPerc = (readedBytes > 0) ? (readedBytes / totalBytes) * 100 : 0; // percentages  
  67.                
  68.              $('#progress').children('.percent').html('<b>'+iPerc.toFixed(1)+'%</b>');  
  69.              $('#progress').children('.pbar').children('.ui-progressbar-value').css('width', iPerc+'%');  
  70.              if (iPerc >= 100) {  
  71.                   $('#progress').children('.percent').html('<b>100%</b>');  
  72.                   $('#progress').children('.elapsed').html('Finished');  
  73.              }  
  74.                
  75.         }  
  76.           
  77.         /***  
  78.         *  
  79.         *  
  80.         var readedBytes = 0;  
  81.         var totalBytes = 100000;  
  82.         function test(){  
  83.               
  84.             readedBytesreadedBytes = readedBytes + 1000;  
  85.               
  86.             progressbar(readedBytes,totalBytes);  
  87.             if(readedBytes >= totalBytes){  
  88.                 clearInterval(intervalProcess);  
  89.             }  
  90.         }  
  91.           
  92.         var intervalProcess = setInterval("test()",1000);  
  93.         **/   
  94.     </script>  
  95.   
  96.     </head>  
  97.     
  98.   <body>  
  99.     <iframe name="uploadIfr" style="display:none;"></iframe>  
  100.     <form id="editForm" action="<%=path%>/servlet/UploadFileProgressBar" method="post" enctype="multipart/form-data" target="uploadIfr" >   
  101.         <input type="file" id="file" name="file" style="width: 300px;" >   
  102.         <input type="button" style="height:20px;"  id="updateButton" value=" 上 传 " onclick="uploadFile()" ><br>   
  103.         <span id='txt' ></span><br><br>  
  104.        <div id="progress" style="width: 400px" >  
  105.             <div class="percent"></div>  
  106.             <div class="pbar"></div>  
  107.             <div class="elapsed"></div>  
  108.         </div>  
  109.         <span id=bytes ></span><br>  
  110.     </form>  
  111.   </body>  
  112. </html>  

 

 

 三、总结

     疑惑一:

       监听器不会引起性能问题,因为它是实时的。我看有些文档上面有说可能会。我暂时把它注释掉了。

 

   

     扩展:

     1、上传成功后。点击删除按钮删除上传文件---这个倒简单

     2、上传中。点击取消上传,---这个如何实现? 希望大家讨论下...是不是可以直接关闭什么输入输出流来实现?


     O(∩_∩)O哈哈~..差不多了...说的差不多了,希望它多少能为您的工作或学习带来点儿帮助。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多