📄 ajax实现基于web的文件上传的进度控制 - liuzuochen的专栏 - csdnblog.htm
字号:
target=_blank>BLOG首页</A> | <A id=Header1_MyLinks1_PersonalHome
title="访问 liuzuochen的专栏" href="http://blog.csdn.net/liuzuochen/"
target=_blank>我的首页</A> | <A id=Header1_MyLinks1_PersonalResume
href="http://job.csdn.net/resumes/liuzuochen.aspx">个人档案</A> |
<A id=Header1_MyLinks1_ContactLink accessKey=9
href="http://blog.csdn.net/liuzuochen/contact.aspx">联系作者</A> |
<A id=Header1_MyLinks1_Syndication
href="http://blog.csdn.net/liuzuochen/Rss.aspx">聚合</A> <A class=XMLLink
id=Header1_MyLinks1_XMLLink
href="http://blog.csdn.net/liuzuochen/Rss.aspx"><IMG
src="AJAX实现基于WEB的文件上传的进度控制 - liuzuochen的专栏 - CSDNBlog.files/xml.gif"
border=0></A> | <A id=Header1_MyLinks1_HyperLink1
href="http://search.csdn.net/search_blog.asp"
target=_blank>搜索</A> | <A id=Header1_MyLinks1_Admin
href="http://writeblog.csdn.net/">登录</A> <IMG id=Header1_BlueTab
src="AJAX实现基于WEB的文件上传的进度控制 - liuzuochen的专栏 - CSDNBlog.files/BlueTabRight.jpg"
align=absMiddle border=0> </TD>
<TD class=HeaderBarTabBack noWrap width="100%">
<DIV class=BlogStatsBar>
<TABLE class=BlogStatsBar>
<TBODY>
<TR>
<TD width="100%"></TD>
<TD class=BlogStatsBar noWrap> 1篇原创: 0篇翻译: 0篇转载: 1897次点击:
27个评论: 0个Trackbacks
</TD></TR></TBODY></TABLE></DIV></TD></TR></TBODY></TABLE></DIV></DIV>
<DIV id=leftmenu>
<H3 class=listtitle>文章</H3>
<UL class=list></UL>
<H3 class=listtitle>收藏</H3>
<UL class=list></UL>
<H3 class=listtitle>相册</H3><!--category title-->
<UL class=list>
<LI class=listitem><A
href="http://blog.csdn.net/liuzuochen/Gallery/280560.aspx">运行界面</A></LI></UL>
<H3 class=listtitle>存档</H3>
<UL class=list>
<LI><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02.aspx">2007年02月(1)</A></LI></UL><SPAN
id=Anthem_RecentComments_ltlComments__><SPAN id=RecentComments_ltlComments>
<H3 class=listtitle>最近评论</H3>
<UL class=list>
<LI class=listitem>liq330:<A title=点击查看《回复:AJAX实现基于WEB的文件上传的进度控制》
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#543360">给我,谢谢<BR>lizy-123@163.com</A>
<LI class=listitem>liq330:<A title=点击查看《回复:AJAX实现基于WEB的文件上传的进度控制》
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#543353">jsp的<BR><BR>liq330@gmail.com</A>
<LI class=listitem>wenzhoufeng:<A title=点击查看《回复:AJAX实现基于WEB的文件上传的进度控制》
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#543325"><A
href="http://www.66soft.com/"><img
src=http://www.66soft.com/Linkpic/2007261625564033.gif alt=66软站
border=0></A><BR>你好,你能给我的站点做一个友情链接吗.<BR>我们的友情链接申请添加是:http://www.66soft.com/service/Re……</A>
<LI class=listitem>wenzhoufeng:<A title=点击查看《回复:AJAX实现基于WEB的文件上传的进度控制》
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#543324"><A
href="http://www.66soft.com/"><img
src=http://www.66soft.com/Linkpic/2007261625564033.gif alt=66软站
border=0></A><BR>你好,你能给我的站点做一个友情链接吗.<BR>我们的友情链接申请添加是:http://www.66soft.com/service/Re……</A>
<LI class=listitem>wubaojie:<A title=点击查看《回复:AJAX实现基于WEB的文件上传的进度控制》
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#543300">wubj757@163.com<BR>谢谢</A></LI></UL></SPAN></SPAN><BR><BR></DIV>
<DIV id=main>
<DIV class=Tag>
<SCRIPT language=javascript
src="AJAX实现基于WEB的文件上传的进度控制 - liuzuochen的专栏 - CSDNBlog.files/urltag.aspx"></SCRIPT>
<DIV style="CLEAR: both"></DIV></DIV>
<SCRIPT>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</SCRIPT>
<DIV class=post>
<DIV class=postTitle><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx"><IMG
height=13
src="AJAX实现基于WEB的文件上传的进度控制 - liuzuochen的专栏 - CSDNBlog.files/authorship.gif"
width=15 border=0> AJAX实现基于WEB的文件上传的进度控制</A> </DIV>
<DIV class=postText>
<STYLE type=text/css>BODY {
MARGIN: 15px; FONT: 13px Georgia, "Lucida Grande", Arial, sans-serif; COLOR: #000; LETTER-SPACING: 0.01em; BACKGROUND-COLOR: white
}
PRE.programlisting {
PADDING-RIGHT: 6px; PADDING-LEFT: 6px; FONT-SIZE: small; PADDING-BOTTOM: 6px; PADDING-TOP: 6px; FONT-FAMILY: Courier New, monospace; BACKGROUND-COLOR: #f4f4f4
}
</STYLE>
<A id=d0 name=d0></A>
<DIV class=toc>
<DL>
<DT>1. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d1">引言</A>
<DT>2. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d2">实现代码</A>
<DD>
<DL>
<DT>2.1. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d201">服务器端代码</A>
<DD>
<DL>
<DT>2.1.1. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20101">文件上传状态类(FileUploadStatus)</A>
<DT>2.1.2. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20102">文件上传状态侦听类(FileUploadListener)</A>
<DT>2.1.3. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20103">后台服务类(BackGroundService)</A>
<DT>2.1.4. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20104">文件上传状态控制类(BeanControler)</A>
</DT></DL>
<DT>2.2. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d202">客户端代码</A>
<DD>
<DL>
<DT>2.2.1. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20201">AjaxWrapper.js</A>
<DT>2.2.2. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20202">fileUpload.html</A>
<DT>2.2.3. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20203">result.jsp</A>
<DT>2.2.4. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d20204">fileUpload.css</A>
</DT></DL>
<DT>2.3. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d203">配置文件</A>
</DT></DL>
<DT>3. <A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d3">结语</A>
</DT></DL></DIV>
<DIV>
<DIV>
<H2 class=title><A id=d1 name=d1></A> 1. 引言</H2></DIV></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV>
<DIV></DIV>
<P> 基于浏览器的文件上传,特别是对于通过<input
type="file">标签来实现上传的情况,<BR>存在着严重的性能问题,因为用户提交了文件之后,在浏览器把文件上传到服务器的过程中,界面看上去<BR>似乎是静止的,如果是小文件还好些,如果不幸需要上传的是几兆、几十兆甚至上百兆的文件,我相信那是<BR>一种非常痛苦的体验,我们中间的很多人应该都有过此种不堪的经历。(一笑)</P>
<P> 现在我就针对这个问题给出一个解决方案,我们将实现一个具有监控能力的WEB上传的程序——它不仅<BR>把文件上传到服务器,而且"实时地"监视文件上传的实际过程。</P>
<P>解决方案的基本思路是这样的:<BR><BR></P>
<UL>
<LI> 在Form提交上传文件同时,使用AJAX周期性地从Servlet轮询上传状态信息
<LI> 然后,根据此信息更新进度条和相关文字,及时反映文件传输状态
<LI> 如果用户取消上传操作,则进行相应的现场清理工作:删除已经上传的文件,在Form提交页面中显示相关信息
<LI> 如果上传完毕,显示已经上传的文件内容(或链接) </LI></UL>
<P>在介绍源代码之前,我们先来看看程序运行界面:<BR><IMG alt=""
src="AJAX实现基于WEB的文件上传的进度控制 - liuzuochen的专栏 - CSDNBlog.files/o_pic.jpg"> </P>
<DIV>
<DIV>
<H2 class=title><A id=d2 name=d2></A> 2. 实现代码</H2></DIV></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV>
<DIV></DIV>
<P> 实现代码想当然的有服务器端代码和客户端代码(呵呵),我们先从服务器端开始。</P>
<DIV>
<DIV>
<H2 class=title style="CLEAR: both"><A id=d201
name=d201></A> 2.1. 服务器端代码</H2></DIV></DIV>
<DIV>
<DIV>
<H3 class=title><A
name=d20101></A> 2.1.1. 文件上传状态类(FileUploadStatus)</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P>
使用FileUploadStatus这个类记录文件上传状态,并将其作为服务器端与web客户端之间通信的媒介,通过对这个类对象提供上传状态作为服务器回应发送给web客户端,web客户端使用JavaScript获得文件上传状态。源代码如下:</P><PRE class=programlisting> /**<BR> * 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。<BR> *<BR> * 如需要转载,请注明作者。<BR> *<BR> * 作者: 刘作晨<BR> * <BR> */<BR> package liuzuochen.sample.upload;<BR> import java.util.*;<BR> public class FileUploadStatus {<BR> //上传用户地址<BR> private String uploadAddr;<BR> //上传总量<BR> private long uploadTotalSize = 0;<BR> //读取上传总量<BR> private long readTotalSize = 0;<BR> //当前上传文件号<BR> private int currentUploadFileNum = 0;<BR> //成功读取上传文件数<BR> private int successUploadFileCount = 0;<BR> //状态<BR> private String status = "";<BR> //处理起始时间<BR> private long processStartTime = 0l;<BR> //处理终止时间<BR> private long processEndTime = 0l;<BR> //处理执行时间<BR> private long processRunningTime = 0l;<BR> //上传文件URL列表<BR> private List uploadFileUrlList = new ArrayList();<BR> //取消上传<BR> private boolean cancel = false;<BR> //上传base目录<BR> private String baseDir = "";<BR> <BR> public FileUploadStatus() {<BR> <BR> }<BR> <BR> public String getBaseDir() {<BR> return baseDir;<BR> }<BR> <BR> public void setBaseDir(String baseDir) {<BR> this.baseDir = baseDir;<BR> }<BR> <BR> public boolean getCancel() {<BR> return cancel;<BR> }<BR> <BR> public void setCancel(boolean cancel) {<BR> this.cancel = cancel;<BR> }<BR> <BR> public List getUploadFileUrlList() {<BR> return uploadFileUrlList;<BR> }<BR> <BR> public void setUploadFileUrlList(List uploadFileUrlList) <BR>{ this.uploadFileUrlList = uploadFileUrlList;<BR> }<BR> <BR> public long getProcessRunningTime() {<BR> return processRunningTime;<BR> }<BR> <BR> public void setProcessRunningTime(long <BR>processRunningTime) {<BR> this.processRunningTime = processRunningTime;<BR> }<BR> <BR> public long getProcessEndTime() {<BR> return processEndTime;<BR> }<BR> <BR> public void setProcessEndTime(long processEndTime) {<BR> this.processEndTime = processEndTime;<BR> }<BR> <BR> public long getProcessStartTime() {<BR> return processStartTime;<BR> }<BR> <BR> public void setProcessStartTime(long processStartTime) {<BR> this.processStartTime = processStartTime;<BR> }<BR> <BR> public long getReadTotalSize() {<BR> return readTotalSize;<BR> }<BR> <BR> public void setReadTotalSize(long readTotalSize) {<BR> this.readTotalSize = readTotalSize;<BR> }<BR> <BR> public int getSuccessUploadFileCount() {<BR> return successUploadFileCount;<BR> }<BR> <BR> public void setSuccessUploadFileCount(int <BR>successUploadFileCount) {<BR> this.successUploadFileCount = <BR>successUploadFileCount;<BR> }<BR> <BR> public int getCurrentUploadFileNum() {<BR> return currentUploadFileNum;<BR> }<BR> <BR> public void setCurrentUploadFileNum(int <BR>currentUploadFileNum) {<BR> this.currentUploadFileNum = currentUploadFileNum;<BR> }<BR> <BR> public String getStatus() {<BR> return status;<BR> }<BR> <BR> public void setStatus(String status) {<BR> this.status = status;<BR> }<BR> <BR> public long getUploadTotalSize() {<BR> return uploadTotalSize;<BR> }<BR> <BR> public String getUploadAddr() {<BR> return uploadAddr;<BR> }<BR> <BR> public void setUploadTotalSize(long uploadTotalSize) {<BR> this.uploadTotalSize = uploadTotalSize;<BR> }<BR> <BR> public void setUploadAddr(String uploadAddr) {<BR> this.uploadAddr = uploadAddr;<BR> }<BR> <BR> public String toJSon() {<BR> StringBuffer strJSon = new StringBuffer();<BR> strJSon.append("<BR>{UploadTotalSize:").append(getUploadTotalSize()).append(<BR> ",")<BR> .append<BR>("ReadTotalSize:").append(getReadTotalSize()).append<BR>(",")<BR> .append<BR>("CurrentUploadFileNum:").append(getCurrentUploadFileNum()).<BR> append(",")<BR> .append<BR>("SuccessUploadFileCount:").append(<BR> <BR> getSuccessUploadFileCount()).append(",") .append<BR>("Status:'").append(getStatus()).append("',") .append<BR>("ProcessStartTime:").append(getProcessStartTime()). append(",")<BR> .append("ProcessEndTime:").append(getProcessEndTime()).append( ",")<BR> .append("ProcessRunningTime:").append(getProcessRunningTime()).<BR> append(",") .append("Cancel:").append(getCancel()).append("}");<BR> return strJSon.toString();<BR> <BR> }<BR> }<BR> </PRE>
<DIV>
<DIV>
<H3 class=title><A
name=d20102></A> 2.1.2. 文件上传状态侦听类(FileUploadListener)</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P> 使用Common-FileUpload 1.2版本(20070103)。此版本提供了能够监视文件上传情况的
ProcessListener接口,<BR>使开发者通过FileUploadBase类对象的setProcessListener方法植入自己的Listener。<BR>FileUploadListener类实现了ProcessListener,在整个文件上传过程中,它对上传进度进行监控,<BR>并且根据上传
情况实时的更新上传状态Bean。源代码如下:</P><PRE class=programlisting> /**<BR> * 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。<BR> *<BR> * 如需要转载,请注明作者。<BR> *<BR> * 作者: 刘作晨<BR> * <BR> */<BR> package liuzuochen.sample.upload;<BR> <BR> import org.apache.commons.fileupload.ProgressListener;<BR> import javax.servlet.http.HttpServletRequest;<BR> <BR> public class FileUploadListener implements ProgressListener{<BR> private HttpServletRequest request=null;<BR> <BR> <BR> public FileUploadListener(HttpServletRequest request){ <BR> this.request=request; <BR> } <BR> <BR> /** <BR> * 更新状态 <BR> */ <BR> public void update(long pBytesRead, long pContentLength, int pItems){ <BR> FileUploadStatus statusBean= BackGroundService.getStatusBean(request); <BR> statusBean.setUploadTotalSize(pContentLength); <BR> //读取完成 <BR> if (pContentLength == -1) { <BR> statusBean.setStatus("完成对" + pItems +"个文件的读取:读取了 " + pBytesRead + " bytes."); <BR> statusBean.setReadTotalSize(pBytesRead); <BR> statusBean.setSuccessUploadFileCount(pItems); <BR> statusBean.setProcessEndTime(System.currentTimeMillis()); <BR> statusBean.setProcessRunningTime(statusBean.getProcessEndTime()); <BR> //读取中 <BR> } else { <BR> statusBean.setStatus("当前正在处理第" + pItems +"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes."); <BR> statusBean.setReadTotalSize(pBytesRead); <BR> statusBean.setCurrentUploadFileNum(pItems); <BR> statusBean.setProcessRunningTime(System.currentTimeMillis()); <BR> } <BR> BackGroundService.saveStatusBean(request,statusBean); <BR> }<BR> } </PRE>
<DIV>
<DIV>
<H3 class=title><A
name=d20103></A> 2.1.3. 后台服务类(BackGroundService)</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P> BackGroundService这个Servlet类负责接收Form Post数据、回应状态轮询请求、处理取消文件上传的请求。
<BR>尽管可以把这些功能相互分离开来,但为了简单明了,还是将它们放到Servlet中,只是由不同的方法进行分割。<BR>源代码如下:</P><PRE class=programlisting> <BR> /**<BR> * 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。<BR> *<BR> * 如需要转载,请注明作者。<BR> *<BR> * 作者: 刘作晨<BR> * <BR> */ <BR> package liuzuochen.sample.upload;<BR> <BR> import java.io.File;<BR> import java.io.IOException;<BR> import java.util.List;<BR> <BR> <BR> import javax.servlet.ServletException;<BR> import javax.servlet.http.HttpServletRequest;<BR> import javax.servlet.http.HttpServletResponse;<BR> <BR> import org.apache.commons.fileupload.FileItem;<BR> import org.apache.commons.fileupload.FileUploadException;<BR> import org.apache.commons.fileupload.disk.DiskFileItemFactory;<BR> import org.apache.commons.fileupload.servlet.*;<BR> <BR> <BR> public class BackGroundService extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {<BR> <BR> public static final String UPLOAD_DIR = "/upload";<BR> public static final String DEFAULT_UPLOAD_FAILURE_URL = "./result.jsp";<BR> <BR> public BackGroundService() {<BR> super();<BR> }<BR> <BR> <BR> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<BR> doPost(request, response);<BR> } <BR> /**<BR> * 从文件路径中取出文件名<BR> */<BR> private String takeOutFileName(String filePath) {<BR> int pos = filePath.lastIndexOf(File.separator);<BR> if (pos > 0) {<BR> return filePath.substring(pos + 1);<BR> } else {<BR> return filePath;<BR> }<BR> }<BR> <BR> /**<BR> * 从request中取出FileUploadStatus Bean<BR> */<BR> public static FileUploadStatus getStatusBean(<BR> HttpServletRequest request) {<BR> BeanControler beanCtrl = BeanControler.getInstance();<BR> return beanCtrl.getUploadStatus(request.getRemoteAddr());<BR> } <BR> /**<BR> * 把FileUploadStatus Bean保存到类控制器BeanControler<BR> */<BR> public static void saveStatusBean( HttpServletRequest request, FileUploadStatus statusBean) {<BR> statusBean.setUploadAddr(request.getRemoteAddr());<BR> BeanControler beanCtrl = BeanControler.getInstance();<BR> beanCtrl.setUploadStatus(statusBean);<BR> }<BR> <BR> /**<BR> * 删除已经上传的文件<BR> */<BR> private void deleteUploadedFile(HttpServletRequest request) {<BR> FileUploadStatus satusBean = getStatusBean(request);<BR> for (int i = 0; i < satusBean.getUploadFileUrlList().size(); i++) {<BR> File uploadedFile = new File(request.getRealPath(UPLOAD_DIR) + File.separator + satusBean.getUploadFileUrlList(). get(i));<BR> uploadedFile.delete();<BR> }<BR> satusBean.getUploadFileUrlList().clear();<BR> satusBean.setStatus("删除已上传的文件");<BR> saveStatusBean(request, satusBean);<BR> }<BR> <BR> /**<BR> * 上传过程中出错处理<BR> */<BR> private void uploadExceptionHandle( HttpServletRequest request, String errMsg) throws ServletException, IOException {<BR> //首先删除已经上传的文件<BR> deleteUploadedFile(request);<BR> FileUploadStatus satusBean = getStatusBean(request);<BR> satusBean.setStatus(errMsg);<BR> saveStatusBean(request, satusBean);<BR> }<BR> <BR> /**<BR> * 初始化文件上传状态Bean<BR> */<BR> private FileUploadStatus initStatusBean(HttpServletRequest<BR> request) {<BR> FileUploadStatus satusBean = new FileUploadStatus();<BR> satusBean.setStatus("正在准备处理");<BR> satusBean.setUploadTotalSize(request.getContentLength());<BR> satusBean.setProcessStartTime(System.currentTimeMillis());<BR> satusBean.setBaseDir(request.getContextPath() + UPLOAD_DIR);<BR> return satusBean;<BR> }<BR> <BR> /**<BR> * 处理文件上传<BR> */<BR> private void processFileUpload(HttpServletRequest request,<BR> <BR> HttpServletResponse response) throws ServletException, IOException {<BR> DiskFileItemFactory factory = new DiskFileItemFactory();<BR> //设置内存缓冲区,超过后写入临时文件<BR> factory.setSizeThreshold(10240000);<BR> //设置临时文件存储位置<BR> factory.setRepository(new File(request.getRealPath("/upload/temp")));<BR> ServletFileUpload upload = new ServletFileUpload(factory);<BR> //设置单个文件的最大上传值<BR> upload.setFileSizeMax(102400000);<BR> //设置整个request的最大值<BR> upload.setSizeMax(102400000);<BR> upload.setProgressListener(new FileUploadListener(request));<BR> //保存初始化后的FileUploadStatus Bean<BR> saveStatusBean(request, initStatusBean(request));<BR> <BR> String forwardURL = "";<BR> try {<BR> List items = upload.parseRequest(request);<BR> //获得返回url<BR> for (int i = 0; i < items.size(); i++) {<BR> FileItem item = (FileItem) items.get(i);<BR> if (item.isFormField()) {<BR> forwardURL = item.getString();<BR> break;<BR> }<BR> }<BR> //处理文件上传<BR> for (int i = 0; i < items.size(); i++) {<BR> FileItem item = (FileItem) items.get(i);<BR> <BR> //取消上传<BR> if (getStatusBean(request).getCancel()) {<BR> deleteUploadedFile(request);<BR> break;<BR> }<BR> //保存文件<BR> else if (!item.isFormField() && item.getName().length() > 0) {<BR> String fileName = takeOutFileName(item.getName());<BR> File uploadedFile = new File(request.getRealPath(UPLOAD_DIR) +<BR> File.separator + fileName); item.write(uploadedFile); //更新上传文件列表 FileUploadStatus <BR>satusBean = getStatusBean(request); <BR> satusBean.getUploadFileUrlList().add(fileName);<BR> saveStatusBean(request, satusBean);<BR> Thread.sleep(500);<BR> }<BR> }<BR> <BR> } catch (FileUploadException e) {<BR> uploadExceptionHandle(request, "上传文件时发生错误:" + e.getMessage());<BR> } catch (Exception e) {<BR> uploadExceptionHandle(request, "保存上传文件时发生错误:" + e.getMessage());<BR> }<BR> if (forwardURL.length() == 0) {<BR> forwardURL = DEFAULT_UPLOAD_FAILURE_URL;<BR> }<BR> request.getRequestDispatcher(forwardURL).forward(request, response);<BR> }<BR> <BR> /**<BR> * 回应上传状态查询<BR> */<BR> private void responseStatusQuery(HttpServletRequest request,<BR> <BR> HttpServletResponse response) throws IOException {<BR> response.setContentType("text/xml");<BR> response.setCharacterEncoding("UTF-8");<BR> response.setHeader("Cache-Control", "no-cache");<BR> FileUploadStatus satusBean = getStatusBean(request);<BR> response.getWriter().write(satusBean.toJSon());<BR> }<BR> <BR> /**<BR> * 处理取消文件上传<BR> */<BR> private void processCancelFileUpload(HttpServletRequest request,<BR> <BR> HttpServletResponse response) throws IOException {<BR> FileUploadStatus satusBean = getStatusBean(request);<BR> satusBean.setCancel(true);<BR> saveStatusBean(request, satusBean);<BR> responseStatusQuery(request, response);<BR> }<BR> <BR> protected void doPost(HttpServletRequest request,<BR> HttpServletResponse response) throws ServletException, IOException {<BR> boolean isMultipart = ServletFileUpload.isMultipartContent(request);<BR> if (isMultipart) {<BR> processFileUpload(request, response);<BR> } else {<BR> request.setCharacterEncoding("UTF-8");<BR> <BR> if (request.getParameter("uploadStatus") != null) {<BR> responseStatusQuery(request, response);<BR> }<BR> if (request.getParameter("cancelUpload") != null) {<BR> processCancelFileUpload(request, response);<BR> }<BR> <BR> }<BR> }<BR> }<BR> </PRE>
<DIV>
<DIV>
<H3 class=title><A
name=d20104></A> 2.1.4. 文件上传状态控制类(BeanControler)</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P> 这是一个单例类,它的功能是为客户端保存文件上传状态,这里我没有使用Session来存储
文件上传状态,<BR>因为对于AJAX这种异步调用,服务器会开启不同的Session,所以无法通过Session保存文件上传状态。<BR>我并不认为这种方法最好,如果有更好的方法,欢迎大家一起讨论。
源代码如下:</P><PRE class=programlisting> <BR>/**<BR> * 本例程演示了通过Web上传文件过程中的进度显示。您可以对本例程进行任何修改和使用。<BR> *<BR> * 如需要转载,请注明作者。<BR> *<BR> * 作者: 刘作晨<BR> * <BR> */ <BR> package liuzuochen.sample.upload;<BR> <BR> import java.util.Vector;<BR> <BR> public class BeanControler {<BR> private static BeanControler beanControler = new BeanControler();<BR> private Vector vector = new Vector();<BR> private BeanControler() {<BR> }<BR> <BR> public static BeanControler getInstance() {<BR> return beanControler;<BR> }<BR> <BR> /**<BR> * 取得相应FileUploadStatus类对象的存储位置<BR> */<BR> private int indexOf(String strID) {<BR> int nReturn = -1;<BR> for (int i = 0; i < vector.size(); i++) {<BR> FileUploadStatus status = (FileUploadStatus) vector.elementAt(i);<BR> if (status.getUploadAddr().equals(strID)) {<BR> nReturn = i;<BR> break;<BR> }<BR> }<BR> return nReturn;<BR> }<BR> /**<BR> * 取得相应FileUploadStatus类对象<BR> */<BR> public FileUploadStatus getUploadStatus(String strID) {<BR> return (FileUploadStatus) vector.elementAt(indexOf(strID));<BR> }<BR> /**<BR> * 存储FileUploadStatus类对象<BR> */<BR> public void setUploadStatus(FileUploadStatus status) {<BR> int nIndex = indexOf(status.getUploadAddr());<BR> if ( -1 == nIndex) {<BR> vector.add(status);<BR> } else {<BR> vector.insertElementAt(status, nIndex);<BR> vector.removeElementAt(nIndex + 1);<BR> }<BR> }<BR> /**<BR> * 删除FileUploadStatus类对象<BR> */<BR> public void removeUploadStatus(String strID){<BR> int nIndex = indexOf(strID);<BR> if(-1!=nIndex)<BR> vector.removeElementAt(nIndex);<BR> }<BR> } </PRE>
<DIV>
<DIV>
<H2 class=title style="CLEAR: both"><A id=d202
name=d202></A> 2.2. 客户端代码</H2></DIV></DIV>
<P> 客户端我们采用Prototype框架。</P>
<DIV>
<DIV>
<H3 class=title><A
name=d20201></A> 2.2.1. AjaxWrapper.js</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P> AjaxWrapper.js对Prototype进行了封装。 源代码如下:</P><PRE class=programlisting> <BR>//类工具<BR> var ClassUtils=Class.create();<BR> ClassUtils.prototype={<BR> _ClassUtilsName:'ClassUtils',<BR> initialize:function(){<BR> },<BR> /**<BR> * 给类的每个方法注册一个对类对象的自我引用<BR> * @param reference 对类对象的引用<BR> */<BR> registerFuncSelfLink:function(reference){<BR> for (var n in reference) {<BR> var item = reference[n]; <BR> if (item instanceof Function) <BR> item.$ = reference;<BR> }<BR> }<BR> }<BR> //Ajax操作封装类:<BR> //由于调用AjaxRequest类进行XMLHTTPRequest操作时,this引用(指向当前的对象)会出现了call stack问题,从而指向当前的对象。<BR> //所以,对putRequest、callBackHandler、以及callback方法都要使用arguments.callee.$来获得正确的类对象引用<BR> var AjaxWrapper=Class.create();<BR> AjaxWrapper.prototype={<BR> debug_flag:false,<BR> xml_source:'',<BR> /**<BR> * 初始化<BR> * @param isDebug 是否显示调试信息<BR> */<BR> initialize:function(isDebug){<BR> new ClassUtils().registerFuncSelfLink(this);<BR> this.debug_flag=isDebug;<BR> <BR> },<BR> /**<BR> * 以get的方式向server发送request<BR> * @param url<BR> * @param params<BR> * @param callBackFunction 发送成功后回调的函数或者函数名<BR> */<BR> putRequest:function(url,params,callBackFunction){<BR> var funcHolder=arguments.callee.$;<BR> var xmlHttp = new Ajax.Request(url,<BR> {<BR> method: 'get', <BR> parameters: params, <BR> requestHeaders:['my-header-encoding','utf-8'],<BR> onFailure: function(){<BR> alert('对不起,网络通讯失败,请重新刷新!');<BR> },<BR> onSuccess: function(transport){<BR> },<BR> onComplete: function(transport){<BR> funcHolder.callBackHandler.apply(funcHolder,[transport,callBackFunction]);<BR> }<BR> });<BR> },<BR> /**<BR> * 以post的方式向server发送xml请求<BR> * @param url<BR> * @param postDataBody<BR> * @param callBackFunction 发送成功后回调的函数或者函数名<BR> */<BR> pushRequest:function(url,postDataBody,callBackFunction){<BR> var funcHolder=arguments.callee.$;<BR> var options={<BR> method: 'post', <BR> parameters:'',<BR> requestHeaders:['my-header-encoding','utf-8'],<BR> postBody: postDataBody,<BR> onFailure: function(transport){<BR> alert('对不起,网络通讯失败,请重新发送!');<BR> },<BR> onComplete: function(transport){<BR> funcHolder.callBackHandler.apply(funcHolder,[transport,callBackFunction]);<BR> }<BR> };<BR> var xmlHttp = new Ajax.Request(url,options);<BR> },<BR> /**<BR> * 远程调用的回调处理<BR> * @param transport xmlhttp的transport<BR> * @param callBackFunction 回调时call的方法,可以是函数也可以是函数名<BR> */<BR> callBackHandler:function(transport,callBackFunction){<BR> var funcHolder=arguments.callee.$;<BR> if(transport.status!=200){<BR> alert("获得回应失败,请求状态:"+transport.status);<BR> }<BR> else{<BR> funcHolder.xml_source=transport.responseText;<BR> if (funcHolder.debug_flag)<BR> alert('call callback function');<BR> if (typeof(callBackFunction)=='function'){<BR> if (funcHolder.debug_flag){<BR> alert('invoke callbackFunc');<BR> }<BR> callBackFunction(transport.responseText);<BR> }<BR> else{<BR> if (funcHolder.debug_flag){<BR> alert('evalFunc callbackFunc');<BR> }<BR> new execute().evalFunc(callBackFunction,transport.responseText);<BR> }<BR> if (funcHolder.debug_flag)<BR> alert('end callback function');<BR> }<BR> },<BR> //显示xml信息<BR> showXMLResponse:function(){<BR> var funcHolder=arguments.callee.$;<BR> alert(funcHolder.xml_source);<BR> }<BR> }<BR> <BR> var XMLDomForAjax=Class.create();<BR> XMLDomForAjax.prototype={<BR> isDebug:false,<BR> //dom节点类型常量<BR> ELEMENT_NODE:1,<BR> ATTRIBUTE_NODE:2,<BR> TEXT_NODE:3,<BR> CDATA_SECTION_NODE:4,<BR> ENTITY_REFERENCE_NODE:5,<BR> ENTITY_NODE:6,<BR> PROCESSING_INSTRUCTION_NODE:7,<BR> COMMENT_NODE:8,<BR> DOCUMENT_NODE:9,<BR> DOCUMENT_TYPE_NODE:10,<BR> DOCUMENT_FRAGMENT_NODE:11,<BR> NOTATION_NODE:12,<BR> <BR> initialize:function(isDebug){<BR> new ClassUtils().registerFuncSelfLink(this);<BR> this.isDebug=isDebug;<BR> },<BR> /**<BR> * 建立跨平台的dom解析器<BR> * @param xml xml字符串<BR> * @return dom解析器<BR> */<BR> createDomParser:function(xml){<BR> // code for IE<BR> if (window.ActiveXObject){<BR> var doc=new ActiveXObject("Microsoft.XMLDOM");<BR> doc.async="false";<BR> doc.loadXML(xml);<BR> }<BR> // code for Mozilla, Firefox, Opera, etc.<BR> else{<BR> var parser=new DOMParser();<BR> var doc=parser.parseFromString(xml,"text/xml");<BR> }<BR> return doc;<BR> },<BR> /**<BR> * 反向序列化xml到javascript Bean<BR> * @param xml xml字符串<BR> * @return javascript Bean<BR> */<BR> deserializedBeanFromXML:function (xml){<BR> var funcHolder=arguments.callee.$;<BR> var doc=funcHolder.createDomParser(xml);<BR> // documentElement总表示文档的root<BR> var objDomTree=doc.documentElement;<BR> var obj=new Object();<BR> for (var i=0; i0){<BR> objFieldValue[objFieldValue.length]=nodeText;<BR> }<BR> }<BR> else{<BR> objFieldValue=new Array();<BR> }<BR> }<BR> else if (node.getAttribute('type')=='long' <BR> || node.getAttribute('type')=='java.lang.Long'<BR> || node.getAttribute('type')=='int'<BR> || node.getAttribute('type')=='java.lang.Integer'){ <BR> objFieldValue=parseInt(nodeText);<BR> }<BR> else if (node.getAttribute('type')=='double' <BR> || node.getAttribute('type')=='float'<BR> || node.getAttribute('type')=='java.lang.Double'<BR> || node.getAttribute('type')=='java.lang.Float'){<BR> <BR> objFieldValue=parseFloat(nodeText);<BR> }<BR> else if (node.getAttribute('type')=='java.lang.String'){<BR> objFieldValue=nodeText;<BR> }<BR> else{<BR> objFieldValue=nodeText;<BR> }<BR> //赋值给对象<BR> obj[node.getAttribute('name')]=objFieldValue;<BR> if (funcHolder.isDebug){<BR> alert(eval('obj.'+node.getAttribute('name')));<BR> }<BR> }<BR> else if (node.nodeType == funcHolder.TEXT_NODE){<BR> if (funcHolder.isDebug){<BR> //alert('TEXT_NODE');<BR> }<BR> <BR> }<BR> else if (node.nodeType == funcHolder.CDATA_SECTION_NODE){<BR> if (funcHolder.isDebug){<BR> //alert('CDATA_SECTION_NODE');<BR> }<BR> }<BR> }<BR> return obj;<BR> },<BR> /**<BR> * 获得dom节点的text<BR> */<BR> getNodeText:function (node) {<BR> var funcHolder=arguments.callee.$;<BR> // is this a text or CDATA node?<BR> if (node.nodeType == funcHolder.TEXT_NODE || node.nodeType == funcHolder.CDATA_SECTION_NODE) {<BR> return node.data;<BR> }<BR> var i;<BR> var returnValue = [];<BR> for (i = 0; i < node.childNodes.length; i++) {<BR> //采用递归算法<BR> returnValue.push(funcHolder.getNodeText(node.childNodes[i]));<BR> }<BR> return returnValue.join('');<BR> }<BR> }<BR> <BR> //委托者类<BR> var Dispatcher=Class.create();<BR> Dispatcher.prototype={<BR> name:'Dispatcher',<BR> //对class中的每个function都赋值一个值为this的$属性<BR> initialize:function(){<BR> new ClassUtils().registerFuncSelfLink(this);<BR> },<BR> /**<BR> * 委托调用<BR> * @param caller 调用者,func的拥有者<BR> * @param func 如果是function对象,则使用Dispatcher对象自己的name作为参数;否则直接调用func<BR> */<BR> dispatch:function(caller,func){<BR> if (func instanceof Function){<BR> var funcArguments=new Array();<BR> funcArguments[0]=arguments.callee.$.name;<BR> func.apply(caller,funcArguments);<BR> }<BR> else{<BR> eval(func);<BR> }<BR> }<BR> }<BR> //祈祷者类<BR> var Invoker=Class.create();<BR> Invoker.prototype={<BR> name:'Invoker',<BR> initialize:function(){<BR> },<BR> invoke:function(showMsg){<BR> alert(showMsg+"——this.name="+this.name);<BR> }<BR> } </PRE>
<DIV>
<DIV>
<H3 class=title><A
name=d20202></A> 2.2.2. fileUpload.html</H3></DIV>
<DIV><A
href="http://blog.csdn.net/liuzuochen/archive/2007/02/28/1516522.aspx#d0">返回</A></DIV></DIV>
<P> fileUpload.html是文件上传界面。 源代码如下:</P><PRE class=programlisting><BR> <html><BR> <head><BR> <meta http-equiv="Content-Type" content="text/html; charset=GBK"><BR> <script type="text/javascript" src="./javascript/prototype.js"></script><BR> <script type="text/javascript" src="./javascript/AjaxWrapper.js"></script><BR> <link href="./css/fileUpload.css" type="text/css" rel="stylesheet"/><BR> <title>文件上传</title><BR> <BR> </head><BR> <body><BR> <div id="controlPanel"><BR> <div id="readme">测试说明: 最大上传量:100M,单个文件最大长度:100M</div><BR> <div id="uploadFileUrl"></div><BR> <BR> <form id="fileUploadForm" name="fileUploadForm" action="./BackGroundService.action" <BR> enctype="multipart/form-data" method="post"><BR> <input type="file" name="file" id="file" size="40"/><br><BR> <input type="file" name="file" id="file" size="40"/><br><BR> <input type="file" name="file" id="file" size="40"/&g
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -