筆者在網上查找流行的上傳元件,swfupload引入眼簾,受到JavaEye的一篇文章啟發,曆時三天,加以研究,現将心得奉上,獻禮JavaEye。
由于筆者才疏學淺,經驗匮乏,介紹不深入,僅供菜鳥參考,還望高手賜教。
一、準備工作
swfupload.swf是上傳元件的核心,一個特制的FLASH,具有浏覽檔案,上傳檔案的功能,以按鈕形式展現在使用者眼前,上文中提及的PNG圖檔浮在按鈕上,可增強視覺效果。SWFUpload.js與swfupload.swf互動,向開發者提供操作接口。
文檔中指出,SWFUpload并不是拖放式的上傳控件,它需要使用者具備JavaScript(以下簡稱JS)和DOM的知識,進行UI界面的設計。
二、使用步驟
筆者借助J2EE平台執行個體,步步為營,介紹其使用方法。
1.部署元件
将swfupload.swf、SWFUpload.js和upload.png圖檔(上文提及的圖檔)正确放置于WEB項目中,并且建立upload.jsp檔案與前三者置于同一目錄中。下圖中tryswfupload為WEB項目名稱。
在upload.jsp中引入swfupload.js元件:
<script type="text/javascript" src="swfupload.js"></script>
2.執行個體化swfupload元件
執行個體化swfupload元件的任務就是正确配置參數,方法是編寫JS代碼,目前急需配置兩方面内容:一是指定swfupload.swf的實體位置;二是準确配置flash中的上傳按鈕。
button_placeholder_id屬性的值spanButtonPlaceholder為上傳按鈕的ID值,是以可以顯示在JSP中。讀者須注意,按鈕的高和寬一定要指定,否則flash無法顯示。至此,JSP頁面已經實作使用者選擇檔案的功能。
讀者不妨試試,便會看到運作效果圖。
點選“選擇檔案”按鈕,檔案對話框即刻跳出,使用者選擇多個檔案後,對話框立即關閉,選擇的檔案進入排隊序列,等待上傳。當調用SWFUpload 對象的startUpload方法執行上傳指令。在此例中,swfu已經執行個體化為SWFUpload 對象,故可以在JSP中添加一個按鈕,在其點選事件中調其該方法。在JSP中添加代碼:
<button onclick="swfu.startUpload()">上傳</button>
雖如此,但檔案沒有上傳到伺服器上,至少用戶端不知道上傳的目的地。
3.指定用戶端将上傳資訊發送至伺服器的URL——struts2登場
swfupload将upload_url屬性值作為用戶端将檔案上傳請求資訊發送至伺服器的URL,讀者可了解為struts2表單中的action屬性值,upload_url屬性值預設為web項目的首頁。筆者僅介紹struts2如何接收請求。
struts2已經實作了上傳功能,筆者不作詳細介紹(由于struts2實作了無縫整合,開發者僅需要将上傳的臨時進行複制即可,其使用方法易于掌握)。
使用struts2的上傳功能,開發者需要知道file标簽的name屬性值,在此基礎上,編寫action類即可,并在struts.xml檔案中配置名字其名字。在swfupload中,file标簽的name屬性等價為file_post_name屬性,其預設值為Filedata。至此,具備了URL和name屬性值,便可開始struts2整合之旅。
首先将action的名字指派給 swfupload中upload_url屬性。接着編寫自己的action類,類中包含兩個屬性Filedata和Filename,Filedata和file_post_name值相同(文檔推薦使用預設值Filedata)。 Filedata指向了struts2上傳的臨時檔案路徑(action中的execute函數執行完畢,臨時檔案将被删除),Filename為上傳檔案的名字。Execute函數實作将臨時檔案複制到指定的目錄(此例将它放在WEB項目下bin目錄下的upload中)。此例action的名字為“upload”,在JSP中将upload_url屬性指派為upload。
4.添加捕獲事件函數
swfupload僅實作了背景操作,前台的處理空間留給了開發者,它采用事件觸發機制,讓開發者捕獲特定事件,并鼓勵開發者自定義對應的事件處理函數(筆者定義為:捕獲事件函數)進行相應處理。即當swfupload内部某一特定事件發生,便觸發JS函數,JS函數通過回調機制将函數參數繼續傳入自定義的JS函數中。Swfupload通過固定的事件函數名屬性值尋找自定義的JS函數,是以在初始化工作中,将自定義的JS函數名指派給swfupload指定的對應屬性即可。
比如,當你選擇上傳檔案後,檔案對話框随即關閉,産生關閉對話框完成的事件,内置的fileDialogComplete函數被觸發,函數執行完必要的操作後,将整個參數資訊傳入file_dialog_complete_handler屬性值對應的JS函數。是以,開發者僅需将自定義的JS函數名指派給file_dialog_complete_handler屬性即可。Swfupload向外提供的所有事件以及對應的函數定義,文檔有詳細說明。筆者将“添加捕獲XXX事件函數”定義為:自定義JS函數用來捕捉XXX事件,XXX表示swfupload内部捕獲事件函數,并函數名指派給XXX事件對應的屬性。比如“添加捕獲fileDialogComplete事件函數”表示先自定義JS函數(假設函數名為fileDialogCompleteHandler),用來捕獲fileDialogComplete事件,并且将fileDialogCompleteHandler指派給fileDialogComplete事件對應的屬性file_dialog_complete_handler。
為便于管理,筆者建議建立一個JS檔案,專門用來存放捕獲事件函數,此例為handler.js,注意在JSP中要将其引入。
<script type="text/javascript" src="handler.js"></script>
5.實作批量上傳
swfupload不自動批量上傳,讀者可以嘗試選擇兩個檔案點選上傳按鈕,在伺服器端卻僅有一個檔案,當再次點選上傳按鈕後,伺服器端又多出一個檔案。Swfupload雖支援批量上傳,但本質仍是單個檔案依次上傳,這有别于傳統設計模式,但其益處卻避免了開發者編寫大量代碼,疊代分析所選檔案。
文檔指出,添加捕獲uploadComplete事件函數(其對應屬性為upload_complete_handler),并在其中調用上傳函數startUpload,通過遞歸的方式實作批量上傳,即在某個檔案上傳完成後,再次啟動檔案上傳。此例,該函數被定義為uploadComplete。
在JSP中添加upload_complete_handler屬性并指派為uploadComplete。
6.顯示上傳檔案清單
顯示出上傳檔案清單能夠增強使用者體驗,因為使用者将看見選擇的檔案資訊。下文介紹将選擇的檔案以表格形式顯示出來,每行内容為依次為檔案名、大小、狀态(QUEUED、ERROR、COMPLETE)。
讀者不妨在文檔中仔細查找是否存在其參數包含file類型集合的API函數,其結果必然徒勞,因為隻有參數為file類型的API函數。這在上文已有介紹:swfupload本質依靠單個檔案形式上傳。該知識點對于對于靈活掌握swfupload舉足輕重。故當選擇某一檔案後,在表格追加顯示該檔案資訊,在檔案對話框關閉後,顯示表格(表格初始狀态為隐藏,在JSP中定義)。
fileDialogComplete事件在選擇上傳檔案後産生,其對應的事件屬性為file_dialog_complete_handler,對應的内置函數為fileDialogComplete(number of files selected, number of files queued, total number of files in the queued),雖然三個整型參數無法提供所選檔案具體資訊,但可實作讓隐藏的表格顯示出來。添加捕獲fileDialogComplete事件函數。
在JSP中添加file_dialog_complete_handler屬性并指派為fileDialogComplete。
在fileDialogComplete事件産生前, fileQueued事件已經發生。fileQueued事件表示所選檔案進入上傳排隊序列,對應的事件屬性為file_queued_handler,對應的内置函數為fileQueued(file object),它的發生頻率取決于所選檔案的個數。通過添加捕獲fileQueued事件函數,可實作檔案清單動态顯示。
fileQueued函數配合狀态轉換函數showStatus動态添加表格行,其中在showStatus函數中,SWFUpload是全局對象,它包含一些隻讀對象,文檔中有說明,此例僅使用FILE_STATUS常量。
在JSP中添加file_queued_handler屬性并指派為fileQueued。
表格行能動态生成,但其中的狀态字段仍然保持最初狀态QUEUED,無法動态展現檔案上傳後的實際狀态(ERROR、COMPLETE)。筆者的方法是通過row.id = file.id将檔案和表格的行綁定,根據檔案定位其所屬表格行,由此改變狀态單元格資料。
上傳錯誤将發生uploadError事件,屬性為upload_error_handler,内置函數為uploadError(file object, error code, message);上傳成功将發生uploadSuccess事件,屬性為 upload_success_handler,内置函數為uploadSuccess(file object, server data, received response)。分别添加這兩個捕獲事件函數,在函數内檔案取出狀态,動态改變狀态字段值。
在JSP中添加upload_error_handler屬性并指派為uploadError,添加upload_success_handler屬性并指派為uploadSuccess。
至此,JSP中SWFUpload的執行個體化代碼為:
三、從頁面跳轉到請求流程
此時,本應劃上句号,因為所選檔案已經上傳到upload目錄下,但筆者還是想就部分朋友反映“上傳完成後,頁面不跳轉”現象談談個人觀點。頁面不跳轉是一個不争的事實,你大可反複嘗試。難道這意味着struts2頁面跳轉功能失效呢?筆者在沒搞清楚swfupload原理前,也為之困擾。struts2頁面跳轉功能仍然良好地在運轉,不過它将跳轉的頁面回響至swfupload,swfupload用内置函數uploadSuccess捕獲。對此,了解使用者從通路上傳頁面到頁面跳轉的整個請求過程至關重要。
首先浏覽器通路WEB伺服器,打開上傳頁面,這個過程和打開網頁原理相同。當點選“選擇檔案”按鈕後,浏覽器通過JS啟用swfupload後退出舞台,flash登場。當點選“上傳”按鈕,flash模拟浏覽器向WEB伺服器發起連接配接(新開session),向WEB伺服器發送上傳資訊。可見,當WEB伺服器傳回資訊,目的地不是浏覽器,而是flash。整個過程,flash始終和JS緊密交融,将發生的事件通知JS,給開發者留下了足夠的程式設計空間。這不得不贊歎swfupload,将flash設計得淋漓盡緻,将JS、WEB伺服器、浏覽器天衣無縫融入一體。
當WEB伺服器響應代碼為200時(swfupload表示上傳成功的預設代碼,可通過修改http_success屬性值改變),swfupload便産生上傳成功事件,故可通過添加捕獲上傳成功事件函數得到struts2傳回的頁面,但不可通過uploadError事件處理struts2攔截器抛出的異常資訊,因為swfupload無法解析WEB伺服器傳回的資訊,它僅靠WEB伺服器傳回代碼産生相應事件。
上傳成功事件對應的内置函數為uploadSuccess(file object, server data, received response),其中第一個參數為上傳的檔案,第二個參數為伺服器傳回的資料,第三個參數為布爾值,從字面上看,估計表示是否收到資訊。struts2跳轉的頁面以HTML代碼形式指派給第二個參數,故可在該捕獲事件函數中,置入document.write(server_data)語句,實作頁面跳轉。
筆者認為swfupload并不希望開發者這樣做,因為單個檔案的上傳機制将導緻出現上傳完一個檔案頁面就跳轉一次的荒唐現象。其實,隻要任何時候調用document.write方法,swfupload立即失效,切忌這樣做。
對于實作批量上傳成功頁面跳轉的方法,筆者建議可将server_data緩存,在捕獲uploadSuccess事件函數中,如果上傳隊列為空(getStats().files_queued > 0),再用document.write向swfupload say Goodbye。
下載下傳次數: 1311
<a href="http://tommy---2005.iteye.com/blog/725641">檢視圖檔附件</a>