淺談如何使用swfupload工具及其與struts2無縫相接


淺談如何使用swfupload工具及其與struts2無縫相接

JSPFlash瀏覽器WebIDEA

      筆者在網上查找流行的上傳組件,swfupload引入眼簾,受到JavaEye的一篇文章啟發,歷時三天,加以研究,現將心得奉上,獻禮JavaEye。

      由於筆者才疏學淺,經驗匱乏,介紹不深入,僅供菜鳥參考,還望高手賜教。

一、准備工作

      從官網上http://www.swfupload.org/下載發布版v2.2.0.1,僅取下載文件中的SWFUpload.js和swfupload.swf即可,另外可利用官網上的DEMO,從中獲取一張PNG圖片。

      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。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com