?? 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 + -