- 浏览: 173190 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
spzjby:
这。。应该不行吧,在上传的时候文件正在写入,cancel操作要 ...
基于AJAX的文件上传显示进度条实现 -
lomodd:
准备做一个,拿来参考了。
基于AJAX的文件上传显示进度条实现 -
BackMe:
终于找到需要的东西了,学习中! 好东西果断收藏!
Ajax留言本实现 -
benlsoft:
谢谢了,试下先。
VirtualBox 安装ghost版windows XP -
yexin218:
plkong 写道cqllang 写道偶比较关注楼主咋把每张图 ...
最新版easyMule-VeryCD-src v1.1.13编译
基于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。其源码如下:
package com.ncu.upload; import java.util.*; public class FileUploadStatus { //上传总量 private long uploadTotalSize=0; //读取上传总量 private long readTotalSize=0; //当前上传文件号 private int currentUploadFileNum=0; //成功读取上传文件数 private int successUploadFileCount=0; //状态 private String status=""; //处理起始时间 private long processStartTime=0l; //处理终止时间 private long processEndTime=0l; //处理执行时间 private long processRunningTime=0l; //上传文件URL列表 private List uploadFileUrlList=new ArrayList(); //取消上传 private boolean cancel=false; //上传base目录 private String baseDir=""; public String getBaseDir() { return baseDir; } public void setBaseDir(String baseDir) { this.baseDir = baseDir; } public boolean getCancel() { return cancel; } public void setCancel(boolean cancel) { this.cancel = cancel; } public List getUploadFileUrlList() { return uploadFileUrlList; } public void setUploadFileUrlList(List uploadFileUrlList) { this.uploadFileUrlList = uploadFileUrlList; } public long getProcessRunningTime() { return processRunningTime; } public void setProcessRunningTime(long processRunningTime) { this.processRunningTime = processRunningTime; } public long getProcessEndTime() { return processEndTime; } public void setProcessEndTime(long processEndTime) { this.processEndTime = processEndTime; } public long getProcessStartTime() { return processStartTime; } public void setProcessStartTime(long processStartTime) { this.processStartTime = processStartTime; } public long getReadTotalSize() { return readTotalSize; } public void setReadTotalSize(long readTotalSize) { this.readTotalSize = readTotalSize; } public int getSuccessUploadFileCount() { return successUploadFileCount; } public void setSuccessUploadFileCount(int successUploadFileCount) { this.successUploadFileCount = successUploadFileCount; } public int getCurrentUploadFileNum() { return currentUploadFileNum; } public void setCurrentUploadFileNum(int currentUploadFileNum) { this.currentUploadFileNum = currentUploadFileNum; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public long getUploadTotalSize() { return uploadTotalSize; } public void setUploadTotalSize(long uploadTotalSize) { this.uploadTotalSize = uploadTotalSize; } }
由于要在客户端要显示进度条,所以在上传过程中服务器端需要监视和维护上传状态的信息,此过程需要处理的数据信息是:不断更新Session中保存的FileUploadStatus实例的信息,如:已经上传的字节数,上传文件的总大小等。FileUpload现在的1.2版本为监视上传进度提供了内建的支持,可以直接继承类ProgressListener,然后重载update()方法,在该方法中添加自己要处理的代码,最后在文件上传处理代码(后面会讲到)中通过为ServletFileUpload对象注册创建的监听类。监听类UploadListener的源代码如下:
package com.ncu.upload; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.ProgressListener; public class UploadListener implements ProgressListener { private HttpSession session=null; public UploadListener (HttpSession session){ this.session=session; } /** * 更新状态 * @param pBytesRead 读取字节总数 * @param pContentLength 数据总长度 * @param pItems 当前正在被读取的field号 */ public void update(long pBytesRead, long pContentLength, int pItems) { FileUploadStatus fuploadStatus = UploadServlet.takeOutFileUploadStatusBean(this.session); fuploadStatus.setUploadTotalSize(pContentLength); //读取完成 if (pContentLength == -1) { fuploadStatus.setStatus("完成对" + pItems + "个文件的读取:读取了 " + pBytesRead + "/" + pContentLength+ " bytes."); fuploadStatus.setReadTotalSize(pBytesRead); fuploadStatus.setCurrentUploadFileNum(pItems); fuploadStatus.setProcessEndTime(System.currentTimeMillis()); fuploadStatus.setProcessRunningTime(fuploadStatus.getProcessEndTime()); }else{//读取过程中 fuploadStatus.setStatus("当前正在处理第" + pItems+"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes."); fuploadStatus.setReadTotalSize(pBytesRead); fuploadStatus.setCurrentUploadFileNum(pItems); fuploadStatus.setProcessRunningTime(System.currentTimeMillis()); } //System.out.println("已经读取:" + pBytesRead); UploadServlet.storeFileUploadStatusBean(this.session, fuploadStatus); } }
有了前面两个类的基础,下来我们可以动手去实现真正处理整个操作Servlet类。源代码如下。
package com.ncu.upload; import java.io.*; import java.util.List; import javax.servlet.ServletException; 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.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.*; /** * Servlet implementation class for Servlet: UploadServlet * */ public class UploadServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { static final long serialVersionUID = 1L; public static final String UPLOAD_STATUS="UPLOAD_STATUS"; public static final String UPLOAD_DIR="/upload"; public UploadServlet() { super(); } /** * 从文件路径中取出文件名 * @param filePath * @return */ private String takeOutFileName(String filePath){ int pos=filePath.lastIndexOf(File.separator); if (pos>0){ return filePath.substring(pos+1); } else{ return filePath; } } /** * 从request中取出FileUploadStatus Bean * @param request * @return */ public static FileUploadStatus takeOutFileUploadStatusBean(HttpSession session){ Object obj=session.getAttribute(UPLOAD_STATUS); if (obj!=null){ return (FileUploadStatus)obj; } else{ return null; } } /** * 把FileUploadStatus Bean保存到session * @param request * @param uploadStatusBean */ public static void storeFileUploadStatusBean( HttpSession session, FileUploadStatus uploadStatusBean){ session.setAttribute(UPLOAD_STATUS,uploadStatusBean); } /** * 删除已经上传的文件 * @param request */ private void deleteUploadedFile(HttpServletRequest request){ FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession()); for(int i=0;i<fUploadStatus.getUploadFileUrlList().size();i++){ File uploadedFile = new File(request.getRealPath(UPLOAD_DIR)+ File.separator+fUploadStatus.getUploadFileUrlList().get(i)); uploadedFile.delete(); } fUploadStatus.getUploadFileUrlList().clear(); fUploadStatus.setStatus("删除已上传的文件"); storeFileUploadStatusBean(request.getSession(),fUploadStatus); } /** * 上传过程中出错处理 * @param request * @param errMsg * @throws IOException * @throws ServletException */ private void uploadExceptionHandle( HttpServletRequest request, String errMsg) throws ServletException, IOException{ //首先删除已经上传的文件 deleteUploadedFile(request); FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession()); fUploadStatus.setStatus(errMsg); storeFileUploadStatusBean(request.getSession(),fUploadStatus); } /** * 初始化文件上传状态Bean * @param request * @return */ private FileUploadStatus initFileUploadStatusBean(HttpServletRequest request){ FileUploadStatus fUploadStatus=new FileUploadStatus(); fUploadStatus.setStatus("正在准备处理"); fUploadStatus.setUploadTotalSize(request.getContentLength()); fUploadStatus.setProcessStartTime(System.currentTimeMillis()); fUploadStatus.setBaseDir(request.getContextPath()+UPLOAD_DIR); return fUploadStatus; } /** * 处理文件上传 * @param request * @param response * @throws IOException * @throws ServletException */ private void processFileUpload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ DiskFileItemFactory factory = new DiskFileItemFactory(); //设置内存阀值,超过后写入临时文件 //factory.setSizeThreshold(10240000*5); //设置临时文件存储位置 //factory.setRepository(new File(request.getRealPath("/upload/temp"))); ServletFileUpload upload = new ServletFileUpload(factory); //设置单个文件的最大上传size //upload.setFileSizeMax(10240000*5); //设置整个request的最大size //upload.setSizeMax(10240000*5); //注册监听类 upload.setProgressListener(new UploadListener(request.getSession())); //保存初始化后的FileUploadStatus Bean storeFileUploadStatusBean(request.getSession(),initFileUploadStatusBean(request)); try { List items = upload.parseRequest(request); //处理文件上传 for(int i=0;i<items.size();i++){ FileItem item=(FileItem)items.get(i); //取消上传 if (takeOutFileUploadStatusBean(request.getSession()).getCancel()){ deleteUploadedFile(request); break; } //保存文件 else if (!item.isFormField() && item.getName().length()>0){ String fileName=takeOutFileName(item.getName()); File uploadedFile = new File(request.getRealPath(UPLOAD_DIR)+File.separator+fileName); item.write(uploadedFile); //更新上传文件列表 FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession()); fUploadStatus.getUploadFileUrlList().add(fileName); storeFileUploadStatusBean(request.getSession(),fUploadStatus); Thread.sleep(500); } } } catch (FileUploadException e) { e.printStackTrace(); //uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); //uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage()); } } /** * 回应上传状态查询 * @param request * @param response * @throws IOException */ private void responseFileUploadStatusPoll(HttpServletRequest request,HttpServletResponse response) throws IOException{ FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS); //计算上传完成的百分比 long percentComplete = (long)Math.floor(((double) fUploadStatus.getReadTotalSize()/(double) fUploadStatus.getUploadTotalSize())*100.0); System.out.println("com:"+percentComplete); response.setContentType("text/xml"); response.setCharacterEncoding("UTF-8"); response.setHeader("Cache-Control", "no-cache"); if ( ((long)fUploadStatus.getReadTotalSize() == (long)fUploadStatus.getUploadTotalSize()) || (fUploadStatus.getCancel() == true)){ response.getWriter().write(fUploadStatus.getStatus().toString()+"success"); }else{ response.getWriter().write(fUploadStatus.getStatus().toString()+"<div class=\"prog-border\"><div class=\"prog-bar\" style=\"width: " + percentComplete + "%;\"></div></div>"); } } /** * 处理取消文件上传 * @param request * @param response * @throws IOException */ private void processCancelFileUpload(HttpServletRequest request,HttpServletResponse response) throws IOException{ FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS); fUploadStatus.setCancel(true); request.getSession().setAttribute(UPLOAD_STATUS, fUploadStatus); responseFileUploadStatusPoll(request,response); } /** * 在上传文件列表中查找与文件名相关的id * @param request * @param fileName 文件名 * @return 找到返回id,否则返回-1 */ private int findFileIdInFileUploadedList(HttpServletRequest request,String fileName){ FileUploadStatus fileUploadStatus=takeOutFileUploadStatusBean(request.getSession()); for(int i=0;i<fileUploadStatus.getUploadFileUrlList().size();i++){ if (fileName.equals((String)fileUploadStatus.getUploadFileUrlList().get(i))){ return i; } } return -1; } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) { processFileUpload(request,response); }else{ request.setCharacterEncoding("UTF-8"); if (request.getParameter("uploadStatus")!=null){ responseFileUploadStatusPoll(request,response); } if (request.getParameter("cancelUpload")!=null){ processCancelFileUpload(request,response); } } } }
至此,服务器端的代码已经基本完成。
5. 客户端实现
由于在上传文件时需要在同一页面显示对应的进度条控件,因此,在提交表单时当前页面不能被刷新。我们可以通过将表单提交至一个隐藏的 iframe 中来实现。关于Ajax的技术前面讲过,这里就不再细说,直接给出源代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>基于Ajax的上传文件显示进度条</title> <style> .prog-border { height: 15px; width: 205px; background: #fff; border: 1px solid #000; margin: 0; padding: 0; } .prog-bar { height: 11px; margin: 2px; padding: 0px; background: #178399; font-size: 10pt; } body{ font-family: Arial, Helvetica, sans-serif; font-size: 10pt; } </style> <script language="javascript" type="text/javascript"> <!-- //var userName=document.getElementById("userName").value; //创建跨浏览器的XMLHttpRequest对象 var timer; function startListener(){ var xmlhttp; try{ //IE 5.0 xmlhttp = new ActiveXObject('Msxm12.XMLHTTP'); }catch(e){ try{ //IE 5.5 及更高版本 xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); }catch(e){ try{ //其他浏览器 xmlhttp = new XMLHttpRequest(); }catch(e){} } } var progressStatusText = document.getElementById("progressBar"); xmlhttp.open("get","UploadServlet?uploadStatus=true",true); /**此处Header设置非常重要,必须设置Content-type类型,负责会报错误 */ xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4){ if(xmlhttp.status == 200){ progressStatusText.innerHTML = ""; progressStatusText.innerHTML = xmlhttp.responseText; var temp = xmlhttp.responseText.indexOf("success"); if ( temp > 0 ){ window.clearTimeout(timer); }else{ timer = window.setTimeout(startListener,1000); } } } } xmlhttp.send(null); } function startUpload(){ timer = window.setTimeout(startListener,1000); return true; } function cancelUpload(){ var xmlhttp; try{ //IE 5.0 xmlhttp = new ActiveXObject('Msxm12.XMLHTTP'); }catch(e){ try{ //IE 5.5 及更高版本 xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); }catch(e){ try{ //其他浏览器 xmlhttp = new XMLHttpRequest(); }catch(e){} } } var progressStatusText = document.getElementById("progressBar"); xmlhttp.open("get","UploadServlet?cancelUpload=true",true); xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //xmlhttp.setRequestHeader("Content-type", "multipart/form-data"); xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4){ if(xmlhttp.status == 200){ progressStatusText.innerHTML = ""; progressStatusText.innerHTML = xmlhttp.responseText; } } } xmlhttp.send(null); return false; } //--> </script> </head> <body> <div id="controlPanel"> <!-- 这个是隐藏的<iframe>作为表单提交后处理的后台目标 通过表单form的target属性指定该<iframe>将返回信息显示在<iframe>框架中 --> <iframe id='target_upload' name='target_upload' src='' style='display: none'></iframe> <form id="fileUploadForm" name="fileUploadForm" action="UploadServlet" enctype="multipart/form-data" method="post" onsubmit="return startUpload();" target="target_upload"> <input type="file" name="file" id="file" size="40"/><br> <input type="submit" name="uploadButton" id="uploadButton" value="开始上传"/> <input type="button" name="cancelUploadButton" id="cancelUploadButton" value="取消上传" onclick="return cancelUpload();"/><br> </form> <div id="progressBar"> </div> </div> </body> </html>
至此,整个文件上传的实现到此完成,读者可以在此基础上,发挥自己的创新能力,去完善此实例。
Good Luck!
评论
swfupload 很不错,现在就用的是这个!
你的程序在并发下会有问题吧,应该测试下
发表评论
-
prototype.js 1.6
2012-09-13 22:59 814收藏下收藏prototype.js 1.6 中文手册 -
Ajax留言本实现
2008-07-15 20:06 2922创建一个Ajax应用程序的步骤做一总结: 第一步:创建X ... -
XMLHttpRequest对象详解(序)
2008-07-14 11:49 12197. 使用status属性判断请求的结果 statu ... -
Ajax 实现级联菜单
2008-07-14 08:32 6168自己动手实现的一个Ajax级联菜单,开发平台:Eclipse, ... -
XMLHttpRequest对象详解
2008-07-11 23:12 1506本文章参考自:《征服Ajax Web 2.0 开发技术详解》为 ... -
Ajax实现检测用户名是否存在
2008-07-11 12:35 2533在一般网站注册页面一般都有一个功能是检测用户名是否已经 ...
相关推荐
基于Ajax的带上传进度条的文件上传代码(Myeclipse下开发)
下面给大家分享下基于ajax实现文件上传并显示进度条。在jsp部分,需要设计一个表单,form的属性添加 enctype=”multipart/form-data”,设计一个iframe,作为隐藏。form的target等于iframe的name; 在servlet部分:...
一个基于AJAX+JSP实现的带进度条文件上传源程序代码
FormData 对象可以使用append 方法进行 key – value的数据添加,与以前我们常用的json不同的就是可以异步上传二进制文件。 1、FormDate对象的创建 var formData = new FormData(); 2、向 FormDate 对象添加数据 ...
在文件上传过程中,经常需要用户进行长时间的等待,为了让用户及时了解上传进度,可以在上传文件的同时,显示文件的上传进度条。运行本实例,如图1所示,访问文件上传页面,单击“浏览”按钮选择要上传的文件,注意...
主要介绍了基于HTML5 Ajax实现文件上传并显示进度条的相关资料,需要的朋友可以参考下
AjaxFileManager 是一款核心基于tinymce的PHP文件上传管理程序,操作动作显示进度条。可能本程序是把tinymce中的文件上传部分给摘录了出来,从测试情况看,大部分功能都保留着tinymce的风格。文件管理部分的功能:...
主要介绍了基于jquery ajax的多文件上传进度条过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
基于Jquery Uploadify asp.net无刷新上传文件,带进度条,支持多文件,上G的大文件 例子使用多图片上传,支持上传后的图片拖拽排序(JqueryUI)。
AJAX实现基于WEB的文件上传的进度控制源代码
JSP源码,上传下载,JSP文件上传实例,AJAX 基于AJAX的WEB上传程序,JSP环境,一次可上传多个文件,带进度条控制,单个文件最大可上传100M文件。
基于JQuery的文件上传进度条、文件上传的速度以及后台Servlet对文件的保存。 简单易懂,
基于uploadify的无刷新上传 带进度条,支持多文件上传
主要介绍了HTML5 Ajax文件上传进度条是如何显示的,基于原生html5实现,不需要falsh支持,进度可以自定义显示,控制灵活,感兴趣的小伙伴们可以参考一下
基于JavaScript+css+php支持断点续传的文件上传插件.zip jQuery文件上传插件,HTML5版uploadify,保持与uploadify一致的API,完全山寨。Uploadify官网:http://www.uploadify.com/ 在V2.0版本中,实现了文件的断点...