簡介:借助 Rich Internet Application(RIA)的理念,Adobe® Flex 將您帶到了 Web 應用 程序開發的更高級別,而 IBM® WebSphere® Portal則提供了復合工具來構建基於 SOA 的靈 活解決方案。但是如何將這二者結合起來呢?一種方法是直接將 Flex 集成到WebSphere Portal 服務器 。本文帶您親歷面向 WebSphere Portal 快速構建基於富客戶端和組件的 Flex 應用程序的全過程,並 提供了一種很有效的方法來減少 WAR 文件的大小。
先決條件
本文面向的讀者是想要用 WebSphere Portal 集成應用程序的Flex 開發人員。本文 假設您對 Flex 的基本編程以及 Java™ 編程都比較熟悉。此外,本文的相關部分還需要您具有對 WebSphere Portal 服務器的管理員權限。不過,本文並不要求您熟悉 WebSphere Portal 的編程或管理 。
為了跟隨本文的學習,您需要安裝如下工具以確保本文給出的示例能夠很好地工作。
Adobe Flex Builder — 本文用 Adobe Flex Builder 3 進行編程。當然,您也可以用適當的JDK 和文本 編輯器進行編寫,但額外的工作量會比較多。
WebSphere Portal V6.0.1 或更高 — 如果 您使用的是 WebSphere Portal V6.0,則應該升級您的WebSphere Portal V6 環境。
IBM Rational Software Architecture v7.0.0
IBM DB2 Enterprise v9.1
示例應用程序概覽
讓我們簡單看看這個名為 TODOList 的示例應用程序的業務要求。很多用戶都希望能夠為約會、 周年紀念、提醒或其他的一些活動保留記錄。而且他們還希望能夠方便地查閱他們將來的一些內容項、 創建新內容項或在需要的時候刪除任意項。我們能否為他們的這種需要提供一種靈活的工具呢?在本文 中,我們將向您闡釋如何以一種類似於大多數開發人員創建應用程序的方式構建這個應用程序並展示完 整的開發過程。
如下所示的圖 1 給出了這個示例應用程序的基礎架構。在用 Adobe Flex 和 IBM WebSphere Portal 構建實際的應用程序之前,我們先快速介紹一下這個示例的技術層面。整個應用 程序將在一個 WAR 文件中構建,其中包括表示層和業務層模塊,這些模塊是在不同項目中開發的。
頂部的方框代表的是作為表示層的一個 Flex 項目,由 MXML 和 ActionScript 構建,底部的方框代 表的是作為業務層的一個 Java 項目,由 Java 和 JDBC 構建。Flex 應用程序通過一個 RemoteObject 調用 Java 服務,RemoteObject 是 Flex 所提供的遠端過程調用(RPC)組件之一。在這個示例應用程 序內,我們將導入 BlazeDS 來實現這個遠端對象。
圖 1. 基礎架構
構建 Flex 項目
Adobe Flex 是一個高效、免費的開源框架,可用來構建和維護表述性的Web 應用程序,這些應用程 序被一致地部署在所有主要的浏覽器、桌面和操作系統上。
它包含一個豐富的組件庫,內有 100 多個經過證明的可擴展 UI 組件,可用來創建 RIA。它還提供 一種基於標准的語言和編程模型,該模型支持常見的設計模式。MXML 是一種基於 XML 的聲明式語言, 用來表示 UI 布局和行為,並且每個 MXML 文件都是一個單獨的組件。ActionScript 則是一種功能強大 的面向對象的編程語言,用來創建客戶邏輯。ActionScript 提供了 MXML 內所沒有的流控制和對象處理 特性。Flex 3 在 2008 年 2 月底發布,在 Adobe Flex Web 站點可以更多地了解 Flex 3 的有關特性 。
Flex 應用程序可以只使用免費的Flex SDK 構建,Flex SDK 包含 Flex 框架(組件類庫)和 Flex 編譯器,讓您能夠使用自選的任意一個 IDE 自由開發和部署 Flex 應用程序。開發人員可以使用 Adobe Flex Builder 3 來顯著加快開發。
Flex 向導會指導您如何快速輕松地在 Flex Builder 3 內創建這個示例。
打開 Flex Builder 3,並選擇 File --> New --> Flex Project。
輸入 TODOListFlex 作為項目名稱。
選擇 default 位置,作為項目的位置,也是我們的工作空間。
選擇 Web application 作為應用程序類型。
對於應用服務器類型,如果有服務器,可能需要遵循 Adobe Flex 3 Help\Using Flex Builder 3 \Flex Builder Basic\Working With Projects 內的步驟。但是在本例中,由於我們不需要這樣,因此 我們選擇了 None,如圖 2 的屏幕快照所示。
圖 2. 新建 Flex 項目
為這個 Flex 應用程序保留全部默認設置並在接下來的兩個配置頁面中構建路徑。
單擊 Finish 創建此項目。
之後,Flex Builder 3 將生成一個主 MXML,名稱與新項目的名稱相同。這個應用程序包含一個 MXML 文件,並以 <mx:Application> 根標記開始,如清單 1 所示。
清單 1. MXML 應用程序根
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
</mx:Application>
在本節,您只需關注這個主要的文件 TODOListFlex.mxml。可以使用 Flex 導航視圖將其他資源 (MXML、ActionScript 和 Image)從我們的示例代碼中導入到此項目。項目類別如圖 3 所示。
圖 3. Flex 項目類別
Flex Builder 3 內的MXML 編輯器允許您在編輯器區域的頂部工作在 Source 或 Design 模式下。請 確保您處於 Source 模式,然後添加一個 <mx:Panel> 組件作為主應用程序的子程序來表示 UI 布局,並在這個面板內放上一個 <mx:VBox> 組件並確保它被垂直放置。參見清單 2。
清單 2. 在 MXML 文件內添加面板和 VBox
<mx:Panel title="TODO List" width="100%" height="100%"
paddingLeft="4" paddingTop="8" paddingRight="8" paddingBottom="4">
<mx:VBox width="100%">
</mx:VBox>
</mx:Panel>
在 <mx:VBox> 標記之間放上一個 <mx:DataGrid> 組件以列出所有 to-do 項。定義一 個 ArrayCollection todoItemColl 並將其指派為 DataGrid 的dataProvider(參見清單 3)。在 “在 Flex 中使用 RemoteObject” 一節中,我們將會調用 RemoteObject 服務來為此 ArrayCollection 獲 得數據。
清單 3. 在 VBox 內添加 DataGrid
<mx:DataGrid id="todoListDG" dataProvider="{todoItemColl}">
<mx:columns>
<mx:DataGridColumn visible="false" dataField="id"/>
<mx:DataGridColumn width="100" headerText="Date" dataField="deadlineStr"/>
<mx:DataGridColumn width="400" headerText="Subject" dataField="task"/>
...
</mx:columns>
</mx:DataGrid>
在 VBox 下有一個表單,允許用戶添加新的to-do 項。此表單包含三個文本字段(Date、Subject 和 Owner)和一個按鈕。我們使用一個 <mx:Grid> 組件來控制這個 UI 的對齊(參見清單 4)。
清單 4. 為項目表單添加網格
<mx:Grid>
<mx:GridRow>
<mx:GridItem>
<mx:Label text="Date:"/>
</mx:GridItem>
<mx:GridItem>
<mx:DateField id="deadlineDateField" formatString="YYYY-MM-DD"/>
</mx:GridItem>
</mx:GridRow>
...
<mx:GridRow>
<mx:GridItem colSpan="2" horizontalAlign="right">
<mx:Button label="Add" click="saveNewItem()"/>
</mx:GridItem>
</mx:GridRow>
</mx:Grid>
之後,我們再在 <mx:Script> 標記內用 ActionScript 代碼創建客戶邏輯並將內容包裝成一 個 CDATA 結構(參見清單 5)。為了訪問不同的數據源,我們定義了一個常量 USE_MOCK_DATA 來控制 此應用程序是否可以訪問遠端數據或本地 mock 數據。現在,我們將常量值設置為 true,這是因為我們 此時只需將其顯示為一個單獨的應用程序。我們在隨後的“在 Flex 內使用 RemoteObject” 一節中將 詳細介紹如何使用 RemoteObject 服務來訪問數據。
清單 5. 添加腳本來調用數據源
<mx:Script>
<![CDATA[
…
private static const USE_MOCK_DATA:Boolean = true; …
private function getTodoList():void
{
if(USE_MOCK_DATA) {
// Creat the mock data
}
else {
// Use remote object to access the back-service
}
}
…
]]>
</mx:Script>
在本文的隨附部分可以找到更多示例代碼。完成上述步驟後,選擇 TODOListFlex.mxml 並單擊工具 欄中的Run 按鈕。Flex Builder 將會編譯這個應用程序並顯示如下頁面,如圖 4 所示。
圖 4. TODOList 頁面
構建 portal 項目
WebSphere Portal 是一個框架,允許添加稱為 portlet 的新特性或擴展。Portlet 是 WebSphere Portal 內的應用程序,這些應用程序封裝了可重用組件,綜合了基於 Web 的內容、應用程序功能性和 對資源的訪問。
WebSphere Portal 最初的版本是 5.0.2.1,為 JSR 168 Portlet API 和 IBM Portlet API 均提供 了一個運行時環境。JSR 168 是來自 Java Community Process 的一種規范,用於 portlet 的標准化。 此規范的作用是提供在 JSR 168 portlet 容器的任何供應商實現上運行 portlet 的互操作性。在 WebSphere Portal V6.0 中已經淡化了 IBM Portlet API 以顯示 IBM 對 JSR 168 標准 portlet API 的大力支持。而且,很多新功能都將只對標准 portlet 可用。在我們的示例中,我們將使用 JSR 168 標准 portlet。
本節顯示了如何使用 Rational Software Architecture(RSA)向導創建一個新的portlet 項目(參 見圖 5)。
打開 RSA 並選擇 File --> New --> Project。
選擇 Portlet Project 來創建一個項目。
輸入 TODOList 作為項目名稱。
目標運行時應為 WebSphere Portal V6.0 stub。
Portlet API 應為 JSR 168 Portlet。
選擇 “Create a portlet” 的復選框。
確保 Basic Portlet 被選中為 Portlet 類型。
單擊 Next,保留所有字段的默認設置。
單擊 Finish 創建這個 portlet 項目。
圖 5. 新建 portlet 項目
完成以上步驟後,這個項目的類別應該如圖 6 所示。
圖 6. Portlet 項目類別
實際上,您現在已經可以將這個 portlet 部署到您的portal 服務器上了。但首先我們要將前面小節 中所創建的這個 Flex 應用程序集成到此 portlet 項目中。
將 Flex 集成到 portlet 項目中
要想將 Flex 應用程序集成進我們的portlet 項目,必須要完成幾個步驟。
引入 Web-tier 編譯器
Flex 編譯器可以創建能夠在 Adobe Flash Player 中運行的SWF 文件。Flex 提供了很多種編譯器: Web-tier 編譯器、mxmlc 命令行編譯器及 Flex Builder 項目編譯器。在本文中,我們將使用 Web- tier 編譯器,Web-tier 編譯器是一組運行在 J2EE 應用服務器內的servlet 和 servlet 過濾器。應用 服務器將請求從 *.mxml 文件傳遞到 servlet 容器,此容器之後再將它們編譯到一個 SWF 文件並將結 果返回給此客戶端。在本例中,只需將 Flex 文件簡單復制到服務器可見的目錄下即可,並且在您用 Web 游覽器請求主應用程序文件時,flex 代碼將會自動編譯。這就讓您可以快速地編譯、測試與部署一 個應用程序,而不必將 MXML 文件編譯成 SWF 文件,然後再將它的包裝程序部署到 Web 服務器上。
可以從 Adobe 開源 Web 站點下載 FlexModule_J2ER。按以下步驟將它引入到這個示例 portlet 項 目。
將 webtier.war 文件解壓縮到一個名為 webtier 的目錄下。
將 flex-bootstrap.jar 和 flex-bootstrap-jsp.jar 從 webtier\WEB-INF\lib 復制到 portlet 項 目對應的WEB-INF\lib 目錄下。
將所有文件和目錄從 webtier\WEB-INF\flex 目錄復制到 portlet 項目對應的WEB-INF\flex 目錄下 。
根據 webtier\WEB-INF 中的web.xml 文件更新 portlet 項目 WEB-INF\ 目錄下的web.xml 文件內容 。
引入 BlazeDS
Flex SDK 具有訪問服務器端數據的特性。這些組件使用 RPC 來與服務器環境進行交互以為 Flex 應 用程序提供數據並將數據發送給後端數據資源。
Flex 支持三種 RPC 組件:HTTPService、WebService 和 RemoteObject。客戶端 RPC 組件可以調用 遠端服務,然後將響應數據保存到 ActionScript 對象以便於您獲取數據。
RemoteObject
在本例中我們使用 RemoteObject 組件,因為它可以讓您像用 HTTPService 或 WebService 那樣直 接訪問原生格式的業務邏輯,而不必先將它們轉換為 XML 格式。這就節省了將現有邏輯公開為 XML 所 耗費的時間。Flex 應用程序可以通過對一個指定對象上的方法的遠程調用來直接訪問 Java 對象。而該 服務器上的那些對象隨後就可以作為參數處理原生數據類型、從這些參數查詢數據庫並作為值返回其原 生數據類型。
RemoteObject 服務的另一個優點就是網絡上的通信速度。仍然會通過 HTTP 或 HTTPS 發生數據交換 ,但數據本身已被序列化為 Action Message Format (AMF),AMF 是用於數據序列化/反序列化及遠程方 法調用的一種二進制格式。由於大大壓縮了傳輸數據量,且將二進制數據解析到內存中的對象要遠比解 析 XML 數據高效,因此它的性能得到了很大的提高。
使用 BlazeDS
BlazeDS 是一個 Adobe 開源項目,它采用 RemoteObject 組件來訪問遠端 Java 對象。它包含一些 可配置通道並能夠運行在一個 J2EE 應用服務器上,這些通道用來在客戶端與服務器間傳輸數據。
可以從 Adobe 開源 Web 站點下載 BladeDS 程序包。執行下面的步驟以使這個 portlet 應用程序使 用 BlazeDS:
將 blazeds.war 解壓縮到 blazeds 目錄。
將所有 jar 文件從 blazeds\WEB-INF\lib 復制到 WEB-INF\lib 目錄。
將所示配置文件從 blazeds\WEB-INF\flex 目錄復制到此應用程序的WEB-INF\flex 目錄下。如果目 錄下已經有同名文件,那麼要全部覆蓋。
在這個 portlet 應用程序的WEB-INF\web.xml 中定義 MessageBrokerServlet 和 一個會話偵聽程序 ,如清單 6 所示。如果您已經從我們的示例代碼中復制了這個 web.xml,可以跳過這個步驟。
清單 6. 定義 MessageBrokerSerlet 和會話偵聽程序
<!-- Http Flex Session attribute and binding listener support -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<!-- MessageBroker Servlet -->
<servlet>
<servlet-name>MessageBrokerServlet</servlet-name>
<display-name>MessageBrokerServlet</display-name>
<servlet-class> flex.messaging.MessageBrokerServlet </servlet-class>
<init-param>
<param-name>services.configuration.file</param-name>
<param-value>/WEB-INF/flex/services-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
將 Flex 代碼復制到 portlet 項目
將 src 目錄下的所有文件從 Flex 項目復制到 WebContent/_TODOList/jsp/html 目錄。portle 項 目的類別應如圖 7 中所示 。
圖 7.將 Flex 代碼復制到 portlet
創建 Java RemoteObject 類
為了簡單起見,我們只需要一個 Java RemoteObject 類(TodoItemRO)作為遠程業務服務。您可以 將 Java 源代碼和 jdbc.properties 文件從 示例代碼(WEB-INF\src)復制到 portlet 項目。 TodoItem 是本例中的惟一一個實體 Java bean(參見圖 8)。
圖 8. Java RemoteObject 類
在 portal 內配置 RemoteObject
Flex 依據 WEB-INF\flex 內的配置文件 services-config.xml 尋找遠端服務。因此需要在 BlazeDS services-config.xml 文件或者它所引用的文件(比如 remoting-config.xml)中,在遠端服務目標的 源屬性中指定完全限定類名。這個類還必須具有一個 no-arg 構造函數,該函數將被 Flex 用來實例化 一個實例。我們在位於 WEB-INF\flex 內的remoting-config.xml 文件中配置這個 Java RemoteObject ,如清單 7 所示。
清單 7. 在 portal 內配置 RemoteObject
<destination id= ‘todoItemRO’ >
<properties>
<source> todolist.ro.TodoItemRO </source>
</properties>
</destination>
在 Flex 內使用 RemoteObject
在創建並配置了遠端對象之後,就可以將其用作一個遠端服務了。
首先在 TODOListFlex.mxml 內創建一個具有惟一 ID srvTODOList 的RemoteObject 組件。目標的值 應該匹配此 portal 項目的WEB-INF\flex\remoting-config.xml 文件內的目標項,在本例中,為 todoItemRO(參見清單 8)。
清單 8. 在 Flex 內創建 RemoteObject 組件
<mx:RemoteObject id="srvTODOList" destination="todoItemRO" showBusyCursor="true"
requestTimeout="10"/>
接下來,利用 RemoteObject 組件的惟一 ID 創建一個 AsyncToken 對象來調用在此目標服務內定義 的Java 方法。此 AsyncToken 類提供了一個位置,可用來為異步 RPC 操作設置額外的或標記(token) 級的數據。
它還允許為單個的調用(或回調方法)附加一個 IResponder。我們定義了一個簡單的 responder 類 TokenResponder,它能實現 IResponder Interface(參見 代碼示例, TODOListFlex\src\util\TokenResponder.as)。它在 Java 為了處理某個錯誤而返回或發出特定的告警 時調用特定的回調方法。我們將其作為 AsyncToken 對象的響應者添加,獲得響應數據並將其轉變為一 個 Flex 變量類型(參見清單 9)。
清單 9. 在 Flex 內創建回調方法
var asyncToken:AsyncToken = AsyncToken (srvTODOList.getTodoItems());
asyncToken.addResponder(new TokenResponder(displayTodoItems, "Error Getting TODO List"));
private function displayTodoItems(event:ResultEvent):void
{
todoItemColl = event.result as ArrayCollection;
todoItemColl.refresh();
}
將 Flex 組件包括到 JSP 內
面向 J2EE 應用服務器的Flex 編譯器模塊還提供了一個 JSP 標記庫,可用來將 Flex 應用程序包括 到 JSP 內。將如下的標記庫聲明添加到您的JSP 頁面以將 Flex 3 Tag Library 導入到 JSP: WebContent\_TODOList\jsp\html\TODOListPortletView.jsp(參見清單 10)。
清單 10. 將 Flex 標記庫包括進 JSP
<%@ taglib uri="FlexTagLib" prefix="mm" %>
您可以引用一個單獨的MXML 文件,也可以通過 <mm:mxml> 標記將 MXML 語法直接包括到 JSP 內(參見清單 11)。
清單 11. 將 Flex 項目包括到 JSP 內
<mm:mxml source="TODOListFlex.mxml" width="100%" height="768">
</mm:mxml>
您可以刪除由 RSA 所生成的JSP 的所有舊的內容。
部署
使用 RSA 內的J2EE Web 應用程序的歸檔特性來導出一個 WAR 文件,以便將其安裝在一個准備 (staging)或生產 portal 服務器上。
請確保 WebContent\_TODOList\jsp\html\TODOListFlex.mxml 文件內的常量 USE_MOCK_DATA 被設為 false,以便用 RemoteObject 獲得 TODO 列表。將 DB2 JDBC 驅動程序 jar 從示例代碼復制到 WEB- INF\lib。
執行如下步驟將 WAR 文件從示例項目導出。
右鍵單擊此示例項目名稱並從彈出菜單選擇 Export。
在 Export 窗口選擇 WAR 文件,然後選擇 Next。
為新 WAR 文件指定一個位置。
單擊 Finish 並確保在此位置下能夠找到這個 WAR 文件。
用管理員身份登錄到 WebSphere Portal Server,並轉到 Administrative 頁面,按照如下步驟安裝 這個 WAR 文件。
如果 portal 服務器尚未運行,就啟動這個 portal 服務器。從控制面板,選擇 Portlet Management,Web Modules。
在 “Manage Web Modules” 頁面,單擊 Install。
在 “Installing a Web module” 頁面,使用 Browse 按鈕來定位這個 WAR 文件。 單擊 Next 和 Finish。由於文件較大,這一步驟可能會耗時幾分鐘。您可以使用共享的lib 來減少 WAR 文件的大小(參考 “減小 WAR 的大小 一節”)。
安裝了 portlet 後,我們需要將 其放入頁面。從 portal 服務器的Administrative 頁面,執行如下步驟。
導航到 Portal -- > User Interface --> Manage Pages。
定位此頁面並添加一個 portlet,然後單擊 Edit Page Layout。
在此頁面內添加 portlet(TODOList),並單擊 Done 來保存這些更改。
現在,轉到此頁面並驗證這個 TODOList portlet。
圖 9. TODOList Portlet
如果是在 Linux® 系統上托管的portal 服務器(如果您使用的是 Windows® 系統,可以跳 過這個小節),那麼這個 flash 可能不會顯示。您可能需要為 portal 服務器的JVM 將 java.awt.headless 參數設置為值 true。執行如下步驟,實現此目的:
啟動 WebSphere Application Server: /opt/IBM/WebSphere/AppServer/bin/startServer.sh server1
打開 WebSphere Application Server Administrative Console: http://server:10001/ibm/console
導航到 Server --> Application Server --> WebSphere_Portal --> Process Definition --> Java Virtual --> Custom Properties
圖 10. 配置 java.awt.headless
重啟 WebSphere Application Server 和 Portal Server。
減小 WAR 的大小(共享的lib)
此步驟可選。由於 WAR 可能大於 20MB,所以可以將某些內容移入 WebSphere Application Service 共享 lib 以便減小文件的大小。參考 developerWorks 文章 “Using resource environment providers in WebSphere Application Server” 其中的“Create a shared library” 一節。
結束語
本文涵蓋了在集成 Adobe Flex 和 WebSphere Portal 期 間的主要特性和增強。我們還研究了用來顯示示例應用程序的運行時環境,以及在發布此應用程序之前 創建一個 RIA 應用程序並集成 Portal 特性來提升用戶體驗是多麼容易。