利用DWR開發基於Ajax的文件上載portlet

文件上載是當今 Web 門戶的一個基本功能。在本篇文章中,作者 Xiaobo Yang Rob Allan 描述瞭如何利用 DWRDirect Web Remoting)開發基於 Ajax 的文件上載 portlet(遵從 JSR 168 規範)。DWR Java™ 開發人員理想的 Ajax 框架,可基於服務器端已部署的 Java 類動態生成 JavaScript。您還將瞭解如何使用 DWR 從門戶服務器檢索文件上載過程。

簡介

Web 門戶爲用戶提供了訪問各種資源和服務的中心網關。與此同時,它們還爲用戶提供了與其他用戶進行資源共享的平臺。從照片到音頻、視頻文件再到研究用的科學數據集,用戶可以共享任何內容。因此,文件上載是 Web 門戶的一種基本的必備功能。

當今的 Web 門戶在很大程度上依賴於 Java portlet 技術。雖然很多使用 Ajax 的開發人員都給出了各種各樣的文件上載進度條解決方案,但我們還沒有聽說過哪個是基於 portlet 的。本文展示瞭如何開發基於 Ajax 的文件上載 portlet,此 portlet 能顯示文件上載過程的進度條。此 portlet 對於那些想要共享大型音頻、視頻和科學文件的人士尤其有用。

要跟上本文的進度,您應該對使用 Java Servlets JavaServer Pages (JSPs) 進行 Web 開發十分熟悉。而且,還必須瞭解門戶和 portlet 技術的開發。當然,如果您對 portlet 技術還不怎麼精通,也不要現在就放棄本文,因爲您會在本文中看到對 portlet 技術的簡單介紹,以及一些有用的資源可用來幫助您加快學習的進程。

在測試本文給出的這個文件上載 portlet 前,可以考慮嘗試使用一種遵從 JSR 168 規範的門戶框架,比如 IBM® WebSphere® Portal ServerApache PlutoeXo 平臺或 Liferay Portal。我們在本文中使用的是 Apache Pluto 1.0.1JDK 5.0 Update 10 Apache Ant Version 1.6.5

portlet 的基本概念

一般地,可以將 portlet 視爲一種 Web 組件。Portlet servlet 類似,但前者更關注於應用程序的表示層。portlet 的典型輸出是 HTML 片斷,這些片斷可由 Web 門戶隨後再組裝起來。Portlet 本身由 portlet 容器管理。portlet 的主要特性包括:

  • 多模式portlet 可以在不同的模式下有不同的視圖。例如,除了查看 模式,portlet 還支持編輯 模式以便用戶可以設置其自身的首選項。

  • 多個窗口狀態portlet 可以最小化、最大化等。

  • 可定製參數portlet 可以定義參數,而這些參數可以由用戶定製。

要獲得有關 portlet 的更多詳細信息,可以參考 Java Portlet Specification 1.0JSR 168JSR 168 的後續版本 JSR 286 預計會於 2007 年後半年發佈,其中包含了一些改進,比如 portlet 間通信和 portlet 過濾器)。相關鏈接,請參看 參考資料

開始創建文件上載 portlet

文件上載 portlet 的基石是 Apache Commons FileUpload 包(本文也稱之爲 FileUpload)。除了支持 servlet 內的文件上載外,Apache Commons FileUpload Version 1.1 包還支持 portlet 中的文件上載。本文使用的是 Apache Commons FileUpload 版本 1.2

基本上,開發文件上載進度條需要兩步:

  1. 在服務器端檢索文件上載過程

  2. 從門戶服務器進行客戶端的文件上載檢索和顯示

文件上載過程的服務器端檢索

FileUpload 包支持使用偵聽器檢索文件上載過程。在文件上載 portlet doUpload() 方法(稱爲 uk.ac.dl.esc.gtg.myportlets.fileupload.FileUploadPortlet,包括在本文 下載 部分所提供的源文件中),通過調用 setProgressListener() 方法爲 PortletFileUpload 設置過程偵聽器,如 清單 1 所示:


清單 1. 爲文件上載包設置過程偵聽器

               

DiskFileItemFactory factory = new DiskFileItemFactory();

PortletFileUpload pfu = new PortletFileUpload(factory);

pfu.setSizeMax(uploadMaxSize); // Maximum upload size

pfu.setProgressListener(new FileUploadProgressListener());

           

 

偵聽器 FileUploadProgressListener(參見 清單 2)可實現 org.apache.commons.fileupload.ProgressListener 接口。update() 方法自動由 FileUpload 包調用以刷新有關所傳輸字節數的最新信息。在本文的實現中,每傳輸 10KB 數據則更新一次進度。這有助於防止更新進行得太頻繁。 getFileUploadStatus() 方法用來計算當前文件上載進度,可由客戶機通過 DWR 調用(在下一節討論)。


清單 2. 檢索文件上載過程的文件上載偵聽器

               

package uk.ac.dl.esc.gtg.myportlets.fileupload;

 

import java.text.NumberFormat;

 

import org.apache.commons.fileupload.ProgressListener;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

 

public class FileUploadProgressListener implements ProgressListener {

        private static Log log = LogFactory.getLog(FileUploadProgressListener.class);

 

        private static long bytesTransferred = 0;

 

        private static long fileSize = -100;

 

        private long tenKBRead = -1;

 

        public FileUploadProgressListener() {

        }

 

        public String getFileUploadStatus() {

               // per looks like 0% - 100%, remove % before submission

               String per = NumberFormat.getPercentInstance().format(

                               (double) bytesTransferred / (double) fileSize);

               return per.substring(0, per.length() - 1);

        }

 

        public void update(long bytesRead, long contentLength, int items) {

               // update bytesTransferred and fileSize (if required) every 10 KB is

               // read

               long tenKB = bytesRead / 10240;

               if (tenKBRead == tenKB)

                       return;

               tenKBRead = tenKB;

 

               bytesTransferred = bytesRead;

               if (fileSize != contentLength)

                       fileSize = contentLength;

        }

 

}

     

 

文件上載過程的客戶端檢索

服務器和客戶間就文件上載過程的通信是通過使用 Ajax 實現的。我們選用 Direct Web Remoting (DWR) 來提供 portlet 中的 Ajax 支持。DWR 是一種面向 Java 開發人員的理想框架,可用來將 Ajax 引入 Web 開發過程中,原因是它可以讓瀏覽器中的 JavaScript 與服務器端的 Java 對象互動。要在 portlet 中使用 DWR,必須執行以下步驟 (更多有關如何配置 DWR 的信息,請參看 參考資料):

  • 通過 WEB-INF/web.xml 配置 DwrServlet(參見 清單 3)。

  • WEB-INF/dwr.xml 內定義一個或更多的客戶機可與之通信的服務器端對象。在 清單 4 中,FileUploadProgressListener 針對 DWR 定義以便客戶機可以調用這個自動生成的 JavaScript。此外,只有 getFileUploadStatus 方法可以被客戶機調用,另一個公共方法 update 則不允許被訪問(請參看 清單 2)。

  • 將與 DWR 有關的 JavaScript 代碼包括在 fileupload-view.jsp(參看 清單 5)。

  • DWR 庫包括在 portlet 應用程序。


清單 3. WEB-INF/web.xml 中配置 DwrServlet

               

<!-- DWR servlet -->

  <servlet>

    <servlet-name>dwr-invoker</servlet-name>

    <display-name>DWR Servlet</display-name>

    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>

    <init-param>

      <param-name>debug</param-name>

      <param-value>false</param-value>

    </init-param>

  </servlet>

 

<!-- DWR servlet mapping -->

  <servlet-mapping>

    <servlet-name>dwr-invoker</servlet-name>

    <url-pattern>/dwr/*</url-patter>

  </servlet-mappin>

 



清單 4. WEB-INF/dwr.xml

               

<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"

                     "http://getahead.org/dwr//dwr20.dtd">

 

<dwr>

  <allow>

    <create creator="new" javascript="FileUploadProgressListener">

      <param name="class"

             value="uk.ac.dl.esc.gtg.myportlets.fileupload.FileUploadProgressListener"/>

      <include method="getFileUploadStatus"/>

    </create>

  </allow>

</dwr>

 

 

清單 5 所示的 JSP 文件 fileupload-view.jsp 展示了 DWR 如何有助於從服務器端檢索文件上載過程。一旦選中了文件並單擊了 Upload 按鈕(參看 1),fileupload_ajax_query_upload_status() 方法會被即刻調用。此方法之後會以異步模式調用 FileUploadProgressListener getFileUploadStatus() 方法(參見 清單 2)。DWR 的妙處就在於此:客戶機可以和服務器端的 Java 對象交互。一旦收到響應,fileupload_ajax_show_upload_status() 方法會被調用以刷新此過程。如果文件上載沒有完成,更新後的過程就會在兩秒種之後檢索。


清單 5. 文件上載 portlet JSP 文件 —— fileupload-view.jsp

               

<%@ page session="false" %>

<%@ page contentType="text/html" %>

<%@ page import="javax.portlet.PortletURL" %>

<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

<portlet:defineObjects/>

 

<script type="text/javascript"

        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()

                               + "/dwr/interface/FileUploadProgressListener.js") %>'>

</script>

 

<script type="text/javascript"

        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()

                               + "/dwr/engine.js") %>'>

</script>

 

<script type="text/javascript"

        src='<%= renderResponse.encodeURL(renderRequest.getContextPath()

                               + "/dwr/util.js") %>'>

</script>

 

<script type="text/javascript">

  function fileupload_ajax_query_upload_status() {

    FileUploadProgressListener.getFileUploadStatus

 

                 (fileupload_ajax_show_upload_status);

    return true;

  }

 

  function fileupload_ajax_show_upload_status(status) {

    if (status == "100")

      document.getElementById("fileupload_progress").innerHTML

                                       ="File successfully uploaded";

    else {

      document.getElementById("progressBar").style.display = "block";

      document.getElementById("fileupload_progress").innerHTML=

                                       "Uploading file: " + status

                                       + "% completed, please wait...";

      document.getElementById("progressBarBoxContent").style.width =

                                       parseInt(status * 3.5) + "px";

      setTimeout(fileupload_ajax_query_upload_status, 2000);

    }

 

    return true;

  }

</script>

 

<style type="text/css">

  #progressBar {padding-top: 5px;}

  #progressBarBox {width: 350px; height: 20px; border: 1px insert; background: #eee;}

  #progressBarBoxContent {width: 0; height: 20px; border-right: 1px solid #444;

                                       background: #9ACB34;}

</style>

 

<h4>File Upload</h4>

 

<!-- the upload form -->

<% PortletURL pUrl = renderResponse.createActionURL();

 %>

<form action="<%= pUrl.toString() %>"

         enctype="multipart/form-data" method="post"

         οnsubmit="setTimeout('fileupload_ajax_query_upload_status()', 1000)">

         

  <input type="file" name="fileupload_upload" value="Upload File">

  <input type="submit" value="Upload">

</form>

 

<%-- file upload progress bar --%>

<div id="fileupload_progress"></div>

<div id="progressBar" style="display: none;">

  <div id="progressBarBoxContent"></div>

</div>

     

 

Apache Pluto 部署和測試文件上載 portlet

此過程的下一步是用 Apache Pluto 1.0.1. 部署和測試文件上載 portlet注意:本文使用的是二進制版本)。

代碼編譯和部署

本文附帶的可下載的 portlet 源代碼同時還提供有 Ant 腳本,以便能夠編譯 portlet 和構建部署所需要的 .war 文件。首先,必須將如下的二進制文件複製到源代碼根目錄下的 lib 目錄:

  • commons-fileupload-1.2/commons-fileupload-1.2.jar

  • commons-io-1.3/commons-io-1.3.jar

  • commons-logging-1.0.4/commons-logging-1.0.4.jar

  • dwr-2.0.1/dwr.jar

  • portletapi-1.0/portlet.jar

  • servletapi-2.4/servletapi-2.4.jar

之後,就可以運行 ant build ant war 以編譯代碼和相應構建部署所需的 .war 文件。如果一切順利,myportlets-fileupload.war 就會出現在 dist 目錄下。執行如下步驟以利用 Apache Pluto 1.0.1 部署 portlet

  1. 啓動 Apache Tomcat 並訪問 http://localhost:8080/pluto/portal

  2. 單擊 Pluto 屏幕左側的 Admin 鏈接來部署此 portlet

  3. 找到 myportlets-fileupload.war,然後單擊 Submit

  4. 定義 portlet 標題、描述和佈局,然後單擊 Submit

  5. 再次單擊所顯示頁面上的 Submit

現在,系統會提示您或者重啓 Tomcat,或者單擊鏈接 Hot deploy myportlets-fileupload portlet application。我們建議您單擊鏈接 Hot deploy myportlets-fileupload portlet application。之後,此 portlet 會被加載,如 1 所示:


1. 運行於 Apache Pluto 中的文件上載 portlet

測試文件上載 portlet

一旦部署完此 portlet 之後,就可以上載文件了。要顯示出此進度條,應該從計算機而不是從門戶服務器訪問此 portlet。執行如下步驟上載文件:

  1. 單擊 Browse... 按鈕選擇要上載的文件。

  2. 單擊 Upload 按鈕上載選中的文件。在文件上載期間,會顯示並更新進度條(參見 2)。

如果從安裝了 Pluto 的計算機測試此 portlet,就不會看到進度條,原因是所設置的上載大小最大爲 20MB。通過在 WEB-INF/portlet.xml 文件內更改 fileupload_upload_maxsize 可以改變此上載大小。


2. 文件上載 portlet 正在上載文件

在我們的 portlet 中,所上載的文件作爲磁盤文件保存在 java.io.tmpdir —— 比如,位於 $PLUTO_HOME $CATALINA_HOME 下的 temp。請注意在實際的 Web 應用程序中,可能還會需要進一步的處理。比如,所上載的文件可能需要存儲在數據庫中以備後用;如果是圖像文件,它就有可能顯示在 Web 瀏覽器內。

此技術的其他應用

本文所探討的技術已經被成功應用到文件傳輸 portlet,該 protlet 採用 GridFTP 協議管理兩個第三方數據網格節點之間的大型數據集。

結束語

本文討論瞭如何使用 Ajax 部署文件上載 portlet 以顯示進度條。介紹瞭如何利用過程偵聽器進行服務器端的文件上載過程檢索,如何使用 DWR 從門戶服務器進行客戶端的文件上載檢索,以及如何將進度條呈現給終端用戶。此 portlet 對於共享諸如音頻、視頻文件和科學數據這類大型數據集尤其有用。本文也展示了使用 DWR JSR 168 portlet 提供 Ajax 支持是多麼地容易。

下載

描述

名字

大小

下載方法

文件上載 portlet 的源代碼

wa-aj-dwr.zip

13KB

HTTP

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章