`
yangpanwww
  • 浏览: 624942 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ajax 文件上传进度条

 
阅读更多

一:方案分析

 

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

 

参考资料: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组件上传文件

package com.yangpan.upload.progressbar;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
 * 有进度条的上传
 * 
 * @author 妞见妞爱
 *
 */
public class UploadFileProgressBar extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	//定义允许上传的文件扩展名
	protected HashMap<String, String> extMap = new HashMap<String, String>();
	//最大文件大小 100 M  --测试用
	protected long  maxSize = 100 * 1024 * 1024;
	//上传文件的保存路径
	protected String configPath = "attached/";

	protected String dirTemp = "attached/temp/";
	
	protected String dirName = "file";
	
	public void init() throws ServletException {
		
		//定义允许上传的文件扩展名
		//extMap.put("image", "gif,jpg,jpeg,png,bmp");
		//extMap.put("flash", "swf,flv");
		//extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
		extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar"); 
		
		
		
	}

	
	/**
	 * 处理上传文件
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public void processFileUpload(HttpServletRequest request, PrintWriter out)
		throws ServletException, IOException {
	 
		//文件保存目录路径
		String savePath = this.getServletContext().getRealPath("/") + configPath;
		
		// 临时文件目录 
		String tempPath = this.getServletContext().getRealPath("/") + dirTemp;
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
		String ymd = sdf.format(new Date());
		savePath += "/" + ymd + "/";
		//创建文件夹
		File dirFile = new File(savePath);
		if (!dirFile.exists()) {
			dirFile.mkdirs();
		}
		
		tempPath += "/" + ymd + "/";
		//创建临时文件夹
		File dirTempFile = new File(tempPath);
		if (!dirTempFile.exists()) {
			dirTempFile.mkdirs();
		}
		
		DiskFileItemFactory  factory = new DiskFileItemFactory();
		factory.setSizeThreshold(20 * 1024 * 1024); //设定使用内存超过5M时,将产生临时文件并存储于临时目录中。   
		factory.setRepository(new File(tempPath)); //设定存储临时文件的目录。   

		ServletFileUpload upload = new ServletFileUpload(factory);
		upload.setHeaderEncoding("UTF-8");
		
		//创建一个进度监听器
		FileUploadProgressListener progressListener = new FileUploadProgressListener(request);
		upload.setProgressListener(progressListener);
		
		try {
			List items = upload.parseRequest(request);
			Iterator itr = items.iterator();
			while (itr.hasNext()) {
				FileItem item = (FileItem) itr.next();
				String fileName = item.getName();
				long fileSize = item.getSize();
				if (!item.isFormField()) {
					//检查文件大小
					if(item.getSize() > maxSize){
						setStatusMsg(request, "1", "上传文件大小超过限制。");
						return;
					}
					//检查扩展名
					String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
					if(!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)){
						setStatusMsg(request, "1", "上传文件扩展名是不允许的扩展名。只允许" + extMap.get(dirName) + "格式。");
						return;
					}

					SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
					String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
					try{
						File uploadedFile = new File(savePath, newFileName);
						
						/*
						 * 第一种方法
						 * 
						 * 好处: 一目了然..简单啊...
						 * 弊端: 这种方法会导致上传的文件大小比原来的文件要大
						 * 
						 * 推荐使用第二种
						 */
						//item.write(uploadedFile);
						//--------------------------------------------------------------------
						//第二种方法
	                    OutputStream os = new FileOutputStream(uploadedFile);  
	                    InputStream is = item.getInputStream();  
	                    byte buf[] = new byte[1024];//可以修改 1024 以提高读取速度
	                    int length = 0;  
	                    while( (length = is.read(buf)) > 0 ){  
	                        os.write(buf, 0, length);  
	                    }  
	                    //关闭流  
	                    os.flush();
	                    os.close();  
	                    is.close();  
	                      
					}catch(Exception e){
						setStatusMsg(request, "1", "上传文件失败。");
						return;
					}
					setStatusMsg(request, "2", "文件上传成功!");
				}
			}
			
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

	/**
	 * 
	 * 错误信息的处理
	 * 
	 * @param request
	 * @param error -- 1 : 错误  0 : 正常  2 : 上传完成
	 * @param message
	 */
	private void setStatusMsg(HttpServletRequest request, String error, String message) {
		HttpSession session = request.getSession();
		FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");
		status.setError(error);
		status.setStatusMsg(message);
	}
	
	/**
	 * 
	 * 获取状态信息
	 * 
	 * @param request
	 * @param out
	 */
	@SuppressWarnings("unused")
	private void getStatusMsg(HttpServletRequest request,PrintWriter out){
		HttpSession session = request.getSession();
		FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");
		System.out.println("输出信息对象:"+status);
		out.println(status.toJSon());
	}
	
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html; charset=UTF-8");

		PrintWriter out = response.getWriter();
		//检查输入请求是否为multipart表单数据。   
		boolean isMultipart= FileUpload.isMultipartContent(request);   
		if (isMultipart) {
			processFileUpload(request, out);
		}else {
			if (request.getParameter("uploadStatus") != null) {
				//response.setContentType("text/xml");
				//response.setHeader("Cache-Control", "no-cache");
				System.out.println("ajax 读取状态····");
				getStatusMsg(request, out);
			}
		}
		
		out.flush();
		out.close();
	}
	
	 

}

 

 

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

 

package com.yangpan.upload.progressbar;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.ProgressListener;

/**
 * 上传监听器
 *  
 * @author 妞见妞爱
 *
 */
public class FileUploadProgressListener implements ProgressListener {

	private HttpSession session;
	private long megaBytes = -1;

	
	public FileUploadProgressListener(HttpServletRequest request) {
		session = request.getSession();
		FileUploadStatus newUploadStatus = new FileUploadStatus();
		session.setAttribute("upladeStatus", newUploadStatus);
	}

	/**
	 * 
	 * 为了进度条监听器不会引起性能问题
	 * 解决方案,是减少进步条的活动数
	 * 比如,只有当上传了1兆字节的时候才反馈给用户
	 * 
	 */
	public void update(long pBytesRead, long pContentLength, int pItems) {
		/*long mBytes = pBytesRead / 1048576;
		if (megaBytes == mBytes) {
			return;
		}
		megaBytes = mBytes;*/
		FileUploadStatus status = (FileUploadStatus) session.getAttribute("upladeStatus");
		if (pContentLength == -1) {
			status.setStatusMsg("已完成" + pItems +"个文件的上传");
		}else {
			status.setStatusMsg("正在上传第" + pItems +"个文件");
		}
		status.setError("0");
	    status.setReadedBytes(pBytesRead);
	    status.setTotalBytes(pContentLength);
	    status.setCurrentItem(pItems);
	}
	
}

 

 

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

package com.yangpan.upload.progressbar;


/**
 * 
 * 上传状态类
 * 
 * @author 妞见妞爱
 *
 */
public class FileUploadStatus {
	
	private String statusMsg = "";
	private long readedBytes = 0L;
	private long totalBytes = 0L;
	private int currentItem = 0;
	// 1 : 错误  0 : 正常  2:完成
	private String error = "0";
	
	public String getStatusMsg() {
		return statusMsg;
	}

	public void setStatusMsg(String statusMsg) {
		this.statusMsg = statusMsg;
	}

	public long getReadedBytes() {
		return readedBytes;
	}

	public void setReadedBytes(long readedBytes) {
		this.readedBytes = readedBytes;
	}

	public long getTotalBytes() {
		return totalBytes;
	}

	public void setTotalBytes(long totalBytes) {
		this.totalBytes = totalBytes;
	}

	public int getCurrentItem() {
		return currentItem;
	}

	public void setCurrentItem(int currentItem) {
		this.currentItem = currentItem;
	}
 
	public String getError() {
		return error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public String toJSon() {
		StringBuffer strJSon = new StringBuffer();
		strJSon.append("{");
		strJSon.append("error:'").append(error).append("',");
		strJSon.append("statusMsg:'").append(statusMsg).append("',");
		strJSon.append("readedBytes:'").append(readedBytes).append("',");
		strJSon.append("totalBytes:'").append(totalBytes).append("',");
		strJSon.append("currentItem:'").append(currentItem).append("'");
		strJSon.append("}");
		return strJSon.toString();
	}	
}

 

 

web.xml

 

	<servlet>
		<servlet-name>UploadFileProgressBar</servlet-name>
		<servlet-class>
			com.yangpan.upload.progressbar.UploadFileProgressBar
		</servlet-class>
	</servlet>
 
	<servlet-mapping>
		<servlet-name>UploadFileProgressBar</servlet-name>
		<url-pattern>/servlet/UploadFileProgressBar</url-pattern>
	</servlet-mapping>

 

 

客户端代码:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%
	String path = request.getContextPath();
 %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    
    <title>妞见妞爱 QQ:609865047</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">
	<link rel="stylesheet" href="css/jquery-ui-1.8.16.custom.css" type="text/css"></link>
    <link rel="stylesheet" href="css/main.css" type="text/css"></link>
	<script type="text/javascript" src="js/jquery-1.6.2.min.js" ></script>
	<script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js" ></script>
	<script type="text/javascript" src="js/script.js" ></script>
	<script type="text/javascript">
	 	
	 	
		function uploadFile(){
			var file = document.getElementById("file").value;
			if(file == ""){
				alert("请选项上传文件!");
				return false;
			}
			document.getElementById("editForm").submit();
			document.getElementById("updateButton").disabled = "disabled";
			ajaxBackState();
		}
		
		var bool = true;
		
		var readedBytes = 0;
		var totalBytes = 0;
		function ajaxBackState(){
			
			$.post("<%=path%>/servlet/UploadFileProgressBar",{uploadStatus:"uploadStatus"},function(result){
				var obj = eval("("+result+")");
				var txt = document.getElementById("txt");
				
				readedBytes = obj["readedBytes"];
				totalBytes = obj["totalBytes"];
				
				if(obj["error"] == "0"){
					txt.innerHTML = obj["statusMsg"]+":"+ readedBytes +"/"+totalBytes;
				}else if(obj["error"] == "1"){
					txt.innerHTML = obj["statusMsg"];
					bool = false;
				}else{
				    txt.innerHTML = obj["statusMsg"]+":"+ readedBytes +"/"+totalBytes;
					bool = false;
				}
			});
			document.getElementById("bytes").innerHTML += readedBytes + "<br>";
			progressbar(readedBytes,totalBytes)
			if(bool){
					setTimeout("ajaxBackState()",1000); 					
			}
		}
		
		function progressbar(readedBytes,totalBytes){
				 
			 $('#progress').children('.pbar').progressbar();
			 iPerc = (readedBytes > 0) ? (readedBytes / totalBytes) * 100 : 0; // percentages
			 
			 $('#progress').children('.percent').html('<b>'+iPerc.toFixed(1)+'%</b>');
			 $('#progress').children('.pbar').children('.ui-progressbar-value').css('width', iPerc+'%');
			 if (iPerc >= 100) {
                  $('#progress').children('.percent').html('<b>100%</b>');
                  $('#progress').children('.elapsed').html('Finished');
             }
			 
		}
		
		/***
		*
		*
		var readedBytes = 0;
		var totalBytes = 100000;
		function test(){
			
			readedBytes = readedBytes + 1000;
			
			progressbar(readedBytes,totalBytes);
			if(readedBytes >= totalBytes){
				clearInterval(intervalProcess);
			}
		}
		
		var intervalProcess = setInterval("test()",1000);
		**/ 
	</script>

	</head>
  
  <body>
  	<iframe name="uploadIfr" style="display:none;"></iframe>
    <form id="editForm" action="<%=path%>/servlet/UploadFileProgressBar" method="post" enctype="multipart/form-data" target="uploadIfr" > 
	    <input type="file" id="file" name="file" style="width: 300px;" >&nbsp;
	    <input type="button" style="height:20px;"  id="updateButton" value=" 上 传 " onclick="uploadFile()" ><br> 
	    <span id='txt' ></span><br><br>
	   <div id="progress" style="width: 400px" >
            <div class="percent"></div>
            <div class="pbar"></div>
            <div class="elapsed"></div>
        </div>
        <span id=bytes ></span><br>
    </form>
  </body>
</html>

 

 

 三、总结

     疑惑一:

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

 

   

     扩展:

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

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


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

 

  • 大小: 47.6 KB
  • 大小: 26.8 KB
分享到:
评论
1 楼 suchiheng6 2012-09-26  
谢谢啊!正用的上!还是iteye上的资料有用啊

相关推荐

    ajax文件上传进度条

    为了提供更好的用户体验,引入了Ajax文件上传和进度条功能。这个话题主要涵盖了如何使用jQuery库和Apache的FileUpload组件来创建一个动态的、实时显示上传进度的界面。 **jQuery** 是一个流行的JavaScript库,它...

    ASP.NET Ajax 文件上传进度条源码示例

    比如带进度条的文件上传,看了网上很多资料还没找到真正意义上的ASP.NET实现进度条上传.Ajax 文件上传进度条,ASP.NET 文件上传进度条示例,ASP.NET 文件上传,asp.net文件上传,ajax文件上传.源码示例

    php+ajaxfileupload+文件上传进度条

    它利用Ajax技术,使得文件上传无需刷新页面即可完成。这极大地提升了用户体验,因为用户可以在上传文件的同时继续浏览其他内容。 3. **上传进度条**: 上传进度条是用户界面中显示文件上传状态的元素,它通常以...

    ajax 无刷新上传文件带进度条

    结合进度条展示,可以提供更优秀的用户体验,让用户清晰地看到文件上传的进度,消除等待的不确定感。 首先,要实现Ajax无刷新上传文件,我们需要了解XMLHttpRequest对象,这是Ajax的核心组件。通过创建...

    Ajax实现文件上传进度条

    Ajax技术的出现为解决这一问题提供了可能,它允许我们在不刷新整个页面的情况下进行异步通信,从而实现文件上传进度条的功能。下面将详细讲解如何利用Ajax实现文件上传进度条。 首先,我们需要理解Ajax的基本原理。...

    struts2+ajax文件进度条的实现

    总的来说,"struts2+ajax文件进度条的实现"是一个典型的前后端协同工作的示例,它展示了如何在Java web应用中优化用户体验,特别是在处理大文件上传时。通过理解Ajax的工作原理、Struts2的文件上传机制以及前端组件...

    Layui实现文件上传进度条

    Layui实现文件上传进度条 Layui是一个优秀的前端框架...通过使用Layui的进度条组件和AjaxUpload组件,我们可以轻松地实现文件上传进度条。使用Layui可以让我们快速构建Web应用程序,并提供了很多实用的UI组件和功能。

    ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签

    在这个项目中,SSH2框架与Ajax技术结合,实现了一个带进度条的文件上传功能,并且这个功能已经被封装成了自定义标签,方便在页面上直接使用。 首先,让我们深入理解SSH框架的每个组件: 1. **Struts2**:Struts2是...

    ajax上传进度条,form上传文件进度条

    在文件上传场景中,传统的表单提交方式会刷新整个页面,导致用户体验不佳。而Ajax上传则能实现无刷新上传,通过XMLHttpRequest对象发送异步请求,保持页面状态不变。 1. 原理: Ajax上传文件时,浏览器将文件分块...

    jquery ajax上传 带进度条

    总结来说,"jquery ajax上传 带进度条"涉及到使用jQuery和Uploadify插件实现文件上传功能,并通过AJAX实时更新上传进度条,从而提供一个友好的用户界面。服务器端的处理同样重要,需要接收文件并给予适当的响应。...

    ajax上传文件进度条及springMVC上传

    总结,通过Ajax与SpringMVC的结合,我们可以实现文件上传过程中前端的进度条显示。关键在于利用Ajax的异步特性,监听文件上传的进度,并通过自定义后端组件将这些信息传递回前端。这样的设计不仅提升了用户体验,也...

    Ajax实现上传文件进度条

    实现Ajax文件上传进度条,我们需要以下几个关键步骤: 1. **HTML表单设计**:创建一个包含文件输入控件的表单,通常还需要一个按钮来触发上传操作。例如: ```html 上传 ``` 2. **JavaScript事件监听**:绑定...

    AJAXFileUpload ajax 异步文件上传 进度条

    AJAXFileUpload是一种基于AJAX技术的异步文件上传组件,它允许用户在不刷新页面的情况下上传文件,并且可以实时显示上传进度,提供良好的用户体验。本文将深入探讨AJAXFileUpload的工作原理、实现方式以及其在实际...

    js实现文件上传进度条

    在JavaScript中实现文件上传进度条是一项重要的用户交互优化工作,它可以显著提升用户体验,尤其是在处理大文件上传时。本文将深入探讨如何实现这一功能,主要涉及以下几个关键知识点: 1. **进度条的实现**:...

    【ASP.NET编程知识】asp.net单文件带进度条上传的解决方案.docx

    在本文中,我们使用jquery的ajax方法来实现文件上传,并且使用jquery-ui库来实现进度条的显示。 知识点2:使用ASP.NET缓存机制实现文件上传进度条显示 在本文中,我们使用ASP.NET缓存机制来实现文件上传进度条的...

    ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签)

    标题 "ssh2(struts2+spring2.5+hibernate3.3+ajax)带进度条文件上传(封装成标签)" 涉及到的是一个基于Java Web的项目,利用了Struts2、Spring2.5、Hibernate3.3和Ajax技术,实现了文件上传并带有进度条显示的功能...

    ajax带进度条的上传功能

    对于文件上传,Ajax可以发送二进制数据,使得在后台处理文件上传的同时,用户仍能在前台进行其他操作。 要实现带进度条的Ajax上传,关键在于HTML5的File API和ProgressEvent接口。File API允许我们直接访问和操作...

    php文件上传进度条

    在文件上传进度条的实现中,AJAX被用来异步获取服务器端上传进度信息,并实时更新页面上的进度条显示,从而提供更流畅的用户体验。 ### 实现步骤 #### 步骤一:创建UploadProgressMeter类 首先,需要创建一个`...

    java 和ajax编写带进度条的附件上传

    在带进度条的文件上传中,Ajax起到了关键作用。前端通过Ajax发送文件数据,可以避免整个页面刷新,保持用户的交互界面不中断。在Ajax请求中,我们通常会使用XMLHttpRequest对象,通过设置onprogress事件监听上传进度...

    文件上传(ajax) 带进度条 fileupload 类部分重写

    1. **Ajax文件上传**:传统的文件上传方式通常会刷新整个页面,用户体验不佳。Ajax(Asynchronous JavaScript and XML)技术允许我们在后台与服务器进行通信,不刷新页面即可完成文件上传。通过XMLHttpRequest对象...

Global site tag (gtag.js) - Google Analytics