隨筆-18  評論-20  文章-0  trackbacks-0

                2006 年 11 月發布   最近,我所工作的機構(威斯康星大學伊奧克萊爾分校)將一個用 Cobol 編寫且運行在 Unisys 大型機上的老舊系統的一部分移植到了 Java/J2EE 環境中。 我們的 IT 小組主要使用開放源代碼工具(包括 Eclipse、Tomcat 和 Spring)來編寫應用程序。但是,許可方式上的更改使我們可以考慮 Oracle 工具,因此我們使用 Oracle JDeveloper 10g 和 Oracle 應用程序開發框架 (ADF) 編寫了一個應用程序來測試開發模型。本文將對該應用程序進行描述,從而快速而詳細地介紹如何使用 Oracle ADF 進行 UI 開發。(有關更進一步的技術信息,請參閱 Oracle 技術網上的 Oracle ADF 教程和 Oracle ADF 開發人員指南、Oracle ACE Steve Muench 在 Oracle 雜志上內容精彩的 ADF 專欄以及 Oracle JDeveloper 論壇中的評論。)

              在本文中,我不會描述構建應用程序所需的每一個步驟,但希望這里的信息足以使您作出自己的決策。本文假設您十分了解 Java,熟悉 Eclipse 或 JDeveloper,并具有普通編程知識。(我沒有在每個步驟后提醒您 Save All,但該步驟不應省略。)

              改變給定體系結構和開發模型總是很困難,因此我將首先提供一些背景知識,以說明 JDeveloper 和 ADF 的價值所在,從而證明這種轉變的有利性。我還會在一個單獨的部分中提供一些“提示與技巧”。

          背景

              當前應用程序直接使用了 Java (JDK 1.5)、Spring(MVC、Web Flow、JDBC 模板)和 jsp 頁面。數據也復制到了一個 Oracle 數據庫 10g 第 2 版數據庫中。盡管我們了解如何使用 JBoss Hibernate 作為對象關系映射 (ORM) 工具,但我們的數據訪問既不復雜也不是動態的,而且 Spring JDBC 模板已經充分滿足了我們的需要。

              由于我們在生產中使用的是 Oracle 數據庫 10g 第 2 版,因此在基于 Windows 的試用版中使用 Oracle 數據庫 10g 快捷版 (XE)(Oracle 數據庫的免費入門級版本)順理成章,我們希望能夠在其中輕松地訪問數據。在決定使用 Oracle 的 TopLink ORM 工具后使用 Oracle 數據庫也很有意義,這樣我們就可以輕松地將映射移植到其他數據源(如果決定使用測試用例作為生產應用程序的基礎)。我們對 XE 所作的唯一更改就是在系統主頁中更改系統全局區 (SGA),以減少它使用的內存。

              我們選擇的 TopLink 比預期的效果還要好,因為它抽象了許多使用 JDBC 甚至接口(如 Spring 的 JDBC 模板)的繁復的詳細信息。(Dustin Marx 在 OTN 上的“在 JDBC 編程中添加一些 Spring 代碼”一文中提供了一個優秀示例,該示例使用 JDBC 模板,無需配置復雜的 Spring 環境。)JBoss Hibernate 是一個出色的 ORM 工具,但在端到端 ADF 解決方案中集成 TopLink 映射的能力也令人大開眼界并且非常高效。

              根據 Oracle 的建議,我們創建了一個 EJB 會話 Bean 來封裝對數據庫的訪問。這只有在應用程序和數據庫之間有一個層(以便在其中根據需要使用業務邏輯)的情況下才有意義。迄今為止,我們的應用程序中沒有任何需要狀態的事物,而使用 Session Facade 設計模式時通常會需要狀態。

              使用 ADF 的一個標準步驟是創建一組能夠訪問數據信息庫的數據控件,我們將遵循該原則。在不需要業務邏輯的情況下(通常是查詢,有時是更新和刪除),通過 UI 控件直接訪問信息十分高效。在較復雜的情況下,可以通過在會話 Bean 方法中包含業務規則實現來應用業務規則。(ADF 開發人員指南第 1.1 章很好地說明了 ADF 和 JSF 如何協同工作以提供高效的開發環境。)

              我們還使用標準的 JSF 導航創建了一組 jspx 文件。盡管我們熟悉 Struts,但這里并不使用它。我們將使用 jspx 文件,因為這是 Oracle 建議的做法。

              JDeveloper 10.1.3 在整個項目中充當 IDE。這可能很明顯,但忘了提醒您它無法識別 JDeveloper 在構建 ADF 應用程序的過程中所扮演的基本角色。JDeveloper 是一個 Java 開發工具,但它還可以為您提供對 TopLink、ADF UI 及數據訪問控件的功能、JSF 功能以及 XML 和 JSP 文件的端到端訪問,還可以提供測試部署和數據庫訪問環境。

          同時,當您在 JDeveloper 中編輯文件時,系統會自動在窗口中調整更改,您在使用 Eclipse 和其他 IDE 時通常看不到這些更改。這些更改提供了各種視圖和編輯方法,因此學習使用 JDeveloper 的豐富功能是有一定難度的。您需要了解在哪里雙擊、何時使用 StrUCture 和 Data Control 窗口、何時在屬性編輯器中設置值,以及(偶爾)何時使用 Source 窗口并編寫 Java 或 JSP 代碼。

           

          項目

              我們的項目是一個簡單的學生會銀行帳戶。所需的基本功能是輸入和編輯支出與存款。該項目基本上是 ADF 教程中描述的功能子集,因此熟悉 SRDemo 的人可以識別出其中許多元素。SRDemo 是一個完整的示例應用程序,您可以通過 JDeveloper 的 Help 下拉菜單中的“檢查更新”機制下載該應用程序。該程序包含完整的源代碼,ADF 開發人員指南使用它來說明如何使用 ADF 進行開發。

          第 0 階段:構建應用程序的初始設置

          第 1 步:使用 JSF、EJB 和 TopLink 模板創建一個新的 Web 應用程序。(另請參閱 Oracle ADF 教程 1-10。)選擇模板并不重要,所有選項都可用,即使它們最初沒有被選中。通過該模板,創建標準的 Model 和 ViewController 項目,從而保留應用程序的前端和后端。您應該設置默認程序包名稱,因為在創建 Java 類時,該名稱可在 JDeveloper 中用作默認名稱。

          第 2 步:設置數據庫。盡管我們可以嘗試使用 New Gallery 的 Database Tier 中的 Offline Database Objects,但我們先前已經創建了所需的 SQL,以使用一組表(3 個)創建模式。我們登錄到 XE Web 界面,并使用腳本(您可以在 SQL Command 頁面上的引用中找到該腳本)創建了用戶和表。為這些表指定主鍵很重要,這樣至少可以使 TopLink 具有足夠的信息來生成更復雜的映射:
          • Account 用于保存有關帳戶的基本信息。
          • Details 用于保存所有帳戶的交易信息。
          • Manager 是與帳戶關聯的個人列表。

              為了填充表,我們編寫了一個使用 DBUnit 的 Java 應用程序,并使用引用中的數據集創建了一個 CampusAccounts.xml 文件。如果愿意,您可以克隆 XML 元素來擴展數據集。由于這是應用程序中的第一個 Java 類,我們選擇在 Model 項目中創建一個 New/General/Java 類,以便創建程序包。然后,將類的主體復制并粘貼到新創建的類中。如果類已經創建,我們將選擇 File/Import 選項將 Java Source 復制到 Model 項目中。

          public static void main(String[] argv) throws Exception {
          Class driverClass = Class.forName("oracle.jdbc.OracleDriver");
          Connection jdbcConnection =
          DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE",
          "CampusAccounts", "xxxxxx");
          IDatabaseConnection connection = new DatabaseConnection(jdbcConnection);
          IDataSet dataSet = new FlatXmlDataSet(new File("c:\\CampusAccounts.xml"));
          try {
          DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
          }
          finally {
          connection.close();
          }
          }
          
              主要片段的主體演示了利用 DBUnit 功能是多么簡單。它顯示了用于連接到 Oracle Database XE 數據庫的 URL,這也是標準 Oracle JDBC 驅動程序的名稱。

           

              但是,您需要在項目中添加一個來自 DBUnit 的 jar 文件和一個庫,以編譯代碼。首先,您需要從 DBUnit zip 文件中提取 jar 文件。從 Model 項目的 Properties 中,選擇 Libraries/Add Jar,然后將 DBUnit jar 文件添加到項目中。通過從 Model 屬性中選擇 Libraries/Add Library,您可以添加 Oracle JDBC 庫,該庫包含 Oracle JDBC 驅動程序。一旦 jar 文件和庫可用,就可以使用 JDeveloper 的 Alt-Enter 代碼完成選項自動添加所需的導入。(確保導入了 java.sql.Connection。)要運行該 Java 應用程序,請在 Applications 窗口中選擇該文件和綠色箭頭。一旦連接創建(下一步),就簡單多了。

          第 1 階段:創建初始模型

          第 3 步:在創建模式之后創建 TopLink 對象關系映射。(另請參閱 Oracle ADF 教程 1-8 和 2-2。)在使用 TopLink 之前需要創建一個連接。選擇 View/Connection Navigator(如果窗口未打開)。 選擇 New Connection on Database,指定一個名稱,并確保選擇了 Oracle (JDBC) 類型。輸入模式名稱和密碼。如果您使用的是 XE,則將 sid 更改為 XE。測試連接以確保成功。

          返回到 Applications 窗口,右鍵單擊 Model,然后從 Tables 中選擇 New/Business Tier/TopLink/Java Objects。為映射命名并更改連接(如果需要)。查詢第 2 步中的模式,并加入所有表。檢查程序包名稱。系統在您指定的程序包中創建了一組數據訪問對象 (DAO),每個表一個。通過打開 Model 的 TopLink 文件夾中的映射,您可以看到每個模式表的域映射。如果您在 Structure 窗口中選擇了一個表,Map 窗口就會轉而顯示映射的不同視圖。嘗試這個操作是種不錯的做法,因為它可以讓您熟悉 JDeveloper 如何在窗口中調整更改。

           

              在 Detail 映射中選擇 Queries 選項卡,您會注意到 TopLink 為每個表自動創建了一個 findAll 查詢。要添加一個簡單查詢(將得到表行的較小子集),請在 Named Queries 中選擇 Add,并為查詢命名。然后,在 Parameters 窗口中選擇 Add,設置參數類型(通過指定完全限定的 Java 類名,如 java.lang.Integer),然后單擊 Name 列更改參數名。針對您需要指定的每個參數選擇 Add。在我們的示例中,已經將 findAccountTransactionsByAccount() 添加到 Detail 映射以根據帳號檢索特定帳戶的所有行,并將 findOneTransaction() 添加到 Detail 映射以檢索特定交易,交易通過帳號(序列號對)區分。findOneTransaction() 是一個 ReadObjectQuery,而 findAccountTransactionsByAccount() 是一個 ReadAllQuery:

          了解 Oracle ADF:入門示例(圖一) 點擊查看大圖

              如果您選擇 Format 選項卡,可以使用 TopLink 編輯器創建查詢或輸入查詢字符串。要使用查詢表達式創建器,請選擇 EXPression/Edit。在創建器中,選擇 Add,并將 Second Argument 更改為剛剛創建的參數。如果有其他參數,則再次選擇 Add,創建器將自動創建一個 AND 子句:

          了解 Oracle ADF:入門示例(圖二)

              系統會創建一個默認的 TopLink 會話,對應于所創建的連接。您可以打開 sessions.xml 文件,并通過在 Structure 窗口中選擇 Default 來查看默認值。更改諸如日志記錄之類的選項非常簡單。

          第 4 步:創建 EJB 會話。(另請參閱 Oracle ADF 教程 2-14。)對于 Model,選擇 New/Business Tier/EJB/Session Bean。無需更改默認設置,除非不需要遠程接口。如果查看創建的 Bean,您將看到系統已經創建了可用于表行的 merge、persist、refresh 和 remove 方法。您還將看到,系統已經為您創建的每個命名查詢創建了一個方法。EJB 向導自動生成的 Java 代碼會在該方法內創建一個會話事務。當然,您不必編輯該代碼,并且現有方法的文本也不會被覆蓋(如果在重新生成 Bean 時,它仍然是您的首選項)。

          第 5 步:創建 ADF 數據控件。(另請參閱 Oracle ADF 教程 2-16。)ADF 數據控件為前面步驟中創建的會話 Bean 和 DAO 提供了一個接口。在創建用于訪問數據庫的用戶界面控件時,數據控件會提供“粘合劑”。如果您從 View 菜單中打開 Data Control 選項板,應該看到它是空白的。右鍵單擊會話 Bean 并選擇最后一項:Create Data Control。Data Control 選項板將填充有以下內容:

          了解 Oracle ADF:入門示例(圖三)
          為項目創建可用后端的初步工作就完成了。盡管諸如 ADF 控件之類的產物的實際值在構建某些頁面時才會顯現出來,但所花費的精力之少仍然令人驚奇。

           

          第 2 階段:創建初始視圖

          第 6 步:使用初始的 faces-config.xml 文件。在首次打開應用程序時,打開 Web Content/WEB-INF 文件夾和所創建的 faces-config.xml 文件。如果由于某種原因尚未創建配置文件,則右鍵單擊 ViewController 項目并選擇 New/Web Tier/JSF/JSF Page Flow & Configuration。faces-config.xml 的默認名稱是正確的。如果您選擇 Overview 選項卡,將看到配置文件的空白視圖:

          了解 Oracle ADF:入門示例(圖四) 點擊查看大圖


              在 JSF 應用程序中,該視圖是進入中央配置文件的重要窗口。除了一組描述用戶如何在 Faces 應用程序中從一個頁面轉換到另一個頁面的 XML 元素以外,還有用于 Bean 的元素,這些 Bean 包括在用戶與界面控件(輔助 Bean)交互時調用其方法的 Bean,以及用于存儲長久信息(如用戶狀態)的 Bean。

          第 7 步:創建初始導航圖和對應頁面。(另請參閱 Oracle ADF 教程 3-2。)現在,需要一組初始頁面(主要基于 SRDemo 中使用的頁面模板),以及描述用戶如何從一個頁面轉移到另一個頁面的初始導航規則。選擇針對 faces-confix.xml 文件的 Diagram 選項卡,確保 Configuration 選項板處于開啟狀態,然后將 JSF 頁面拖到配置圖上。此時,您已經在配置文件(而不是頁面)中創建了一個導航元素。

              雙擊無標題頁面圖標,以啟動一個將實際創建文件的向導。將名稱更改為 index;將文件后綴更改為 jspx(Oracle 的普遍建議);確保系統沒有自動公開該頁面的 UI 組件;然后移動 ADF Faces 組件、JSF 內核、ADF Faces 和 JSF Html 庫。選擇您喜歡的 HTML 版本 — 我們在 4.0.1 Transitional 版上運行良好。

              index.jspx 將重定向到應用程序的實際第一頁,這是創建 Web 應用程序的標準做法。這可能會創造一個糟糕的先例,但可以在 Source 窗口中查找 index.jspx,并用以下 scriptlet 替換 f:view 標記。注意,您要創建一個目錄結構來管理頁面 — 管理涵蓋所有應用程序的所有頁面,而名為 campusaccounts 的子目錄將用于保存該項目的所有頁面。將 scriptlet 插入 index.jspx 文件之后,您就可以安全地保存并關閉該文件了。

          <jsp:scriptlet>
          response.sendRedirect("faces/administration/welcome.jspx");
          </jsp:scriptlet>
          

              從 Component 選項板中,將另一個 JSF 頁拖到 faces-config.xml 圖上。雙擊圖標打開向導,以設置其 jsp 頁面。將名稱更改為 welcome,將文件類型更改為 jspx — 并確保設置目錄,以創建您希望創建的任何子目錄結構。例如,在本案例中,我們將目錄設置為 ../public_html/administration,以便對應于 sendRedirect。移動選項應該與創建 index.jspx 時所使用的移動選項相同,HTML 版本也應該相同。

              將內容添加到 JSP 頁面實際上就是在 Diagram、Property Editor 和 Structure 窗口之間切換。有時,您甚至可以通過 Source 窗口編輯頁面。在 Structure 窗口中,打開 faces 視圖元素并刪除默認的 f:view 標記,以便能夠使用包含面板頁的以下文本替換它。面板頁是一個復雜的 UI 控件,它包含頁眉、頁腳、用于選擇幫助的全局控件以及版權部分等內容。在使用該頁時,您將發現使用標準界面組件創建復雜頁面是多么輕松。粘貼文本的最簡單方法就是切換到 Source 窗口,并確保游標跟隨文件開頭的三個 jsp 標記。

          <f:view>
          <f:loadBundle basename="edu.uwec.financial.resources.UIResources"
          var="res"/>
          <af:document title="#{res['uacct.campusAccounts.title']}"
          initialFocusId="start">
          <af:form>
          <af:panelPage>
          <!-- Page Content End -->
          <f:facet name="branding">
          <af:panelHorizontal>
          <af:objectImage source="/images/banner.jpg"/>
          </af:panelHorizontal>
          </f:facet>
          <f:facet name="menu1">
          <af:menuTabs var="menuTab" value="http://www.QQread.com/oracle/2006/12/#{menuModel.model}">
          <f:facet name="nodeStamp">
          <af:commandMenuItem text="#{menuTab.label}"
          action="#{menuTab.getOutcome}"
          rendered="#{menuTab.shown and menuTab.type=='default'}"
          disabled="#{menuTab.readOnly}"/>
          </f:facet>
          </af:menuTabs>
          </f:facet>
          <f:facet name="menu2">
          <af:menuBar/>
          </f:facet>
          <f:facet name="menuGlobal">
          <af:menuButtons>
          <af:commandMenuItem text="#{res['uacct.menu.logout']}"
          action="GlobalLogout" immediate="true"
          icon="images/blafIcons/logout.gif"/>
          <af:commandMenuItem text="#{res['uacct.menu.help']}"
          action="GlobalHelp" immediate="true"
          icon="../images/blafIcons/help.gif"/>
          </af:menuButtons>
          </f:facet>
          <f:facet name="messages">
          <af:messages/>
          </f:facet>
          <f:facet name="appCopyright">
          <!--Copyright msg-->
          <h:panelGroup>
          <af:objectSpacer width="10" height="10" id="objectSpacer4"/>
          <af:panelHorizontal halign="center">
          <af:outputText value="#{res['uacct.copyright']}"/>
          </af:panelHorizontal>
          </h:panelGroup>
          </f:facet>
          <f:facet name="appAbout">
          <!-- The About this Application Link-->
          <af:panelHorizontal halign="center">
          <af:commandLink text="#{res['uacct.about']}" action="GlobalAbout"
          immediate="true"/>
          </af:panelHorizontal>
          </f:facet>
          <f:facet name="infoUser">
          <!-- Show the Logged in user -->
          <h:outputFormat value="#{res['uacct.connectedUser']}"
          rendered="#{userInfo.authenticated}" escape="false">
          <f:param value="#{userInfo.userName}"/>
          </h:outputFormat>
          </f:facet>
          </af:panelPage>
          </af:form>
          </af:document>
          </f:view>
          您將注意到 Structure 窗口中報告了錯誤,這些錯誤將在下一步中解決。
          

           

           

          第 8 步:不擇手段地占為己有。(另請參閱 Oracle ADF 教程 4-2。)我們建議從 SRDemo 中借用幾個文件,以使您快速了解如何創建應用程序。由于使用資源文件很簡單,我們決定始終使用它來標記所有 UI 組件,甚至是按鈕上很明顯的標記(如 Submit)。 我們預計大部分內聯網應用程序都沒有國際化需求,但這是一個設計決策,它創造了一個較好的先例。我們還建議借用幾個類(如 ADFUtils 和 JSFUtils),因為它們非常有用。如果您必須通過 Java 代碼訪問 JSF 和 ADF 框架中存儲的變量,則有一點麻煩。一旦您了解 Oracle 使用的綁定和命名標準,就會覺得這些實用程序類十分簡單,示例如下。導入圖像文件夾也很有意義,因為它包含了瀏覽器外觀 (BLAF) 文件夾和界面中使用的幾個圖標。

              我們導入文件的方法是選擇 ViewController 項目,選擇 File/Import/Java Source,然后瀏覽到 SRDemo 項目中的類。SRDemo 中的完整路徑與 mywork 位于同一級別 — 參見 samples/SRDemo/UserInterface/src/oracle/srdemo/view。將 ADFUtils 和 JSFUtils 添加到 util,然后將它們復制到程序包結構中(我們在 src 文件夾中使用的是 edu/uwec/financial/util);將 ResourceAdapter 和 UIResources 添加到 resources(我們使用的是 edu/uwec/financial/resources);然后通過菜單(我們使用的是 edu/uwec/financial/menu)添加 MenuItem、MenuModelAdapter 和 MenuTreeModelAdapter。注意,當您導入 Java 文件后,可能需要修改程序包名稱以匹配目錄結構。

              您可以導入一些標準圖像,方法是選擇 File/Import/Web Source,瀏覽到 UserInterface/public_html,然后選擇圖像 — 確保將 images 文件夾復制到 public_html 文件夾中。這個步驟有一點麻煩,因為在瀏覽時很容易過于深入:

          了解 Oracle ADF:入門示例(圖五)

              此時,jspx 文件中的錯誤應該已經消失,但可能需要修正面板頁上的元素,例如,要包含在 branding 控件 (facet) 中的所有圖像。如果您要將某個圖像包含在頁面頂部,應將其作為 WebContent 導入 ViewController 項目的 images 文件夾。在 Structure 窗口的面板頁中,選擇 branding/panelHorizontal,然后在 Properties 窗口中重設其對象圖像。您還應該確保頁面上的圖標(如 logout 和 help)具有正確的 Source 屬性。在 Property 窗口的 Source 屬性中選擇每個圖標和 ... 按鈕,并在 Source 窗口中查找圖像。您需要在 welcome.jspx 中編輯諸如 loadBundle 標記之類的項,以便與程序包結構相匹配。

          示例屬性文件項與 welcome.jspx 中引用的屬性不對應。以下是我們添加的初始名/值對集。

          uacct.about=About MyBlugold
          uacct.copyright=\u00a9 2006 University of Wisconsin - Eau Claire
          uacct.menu.help=Help
          uacct.menu.logout=Logout
          uacct.menu.campusAccounts=Campus Accounts
          uacct.campusAccounts.title=Campus Accounts
          uacct.connectedUser=Logged in as <b>{0}</b>
          

              ADFUtils 類沒有編譯,因為它需要一個庫。在 ViewController 項目上打開 Properties,然后添加 ADF Model Runtime 庫。

              如果您選擇 index.jspx 并運行應用程序(選擇綠色箭頭),應該看到與以下類似的內容 — 當然,還包含標幟。

          實際上,歡迎頁面將為我們提供更加“全局”的按鈕(如 Help 和 Logout),因為您可以從任何頁面選擇它們。

           

          第 9 步:創建菜單。這一部分將介紹從 SRDemo 中借用以創建菜單的代碼,如果您希望該簡介簡短些,可以跳過該部分。


              管理頂層菜單所需的標記和 Java 代碼已添加至項目,但需要在 faces-config.xml 文件中添加相關項以將其連接。一般而言,JDeveloper 會提供所需項,您也可以打開 faces-config.xml 文件并從 Overview 選項卡添加 Bean 定義。另一種方法是通過 Source 窗口將以下示例復制到文件,從而使用托管 Bean 元素作為項模型以獲得類似的 Bean(如 Bean 注釋標記中所述)。

          <!-- Global menu tab for logout (we also added a tab for help -->
          <managed-bean>
          <managed-bean-name>menuItem_GlobalLogout</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.menu.MenuItem</managed-bean-class>
          <managed-bean-scope>session</managed-bean-scope>
          <managed-property>
          <property-name>label</property-name>
          <value>#{resources['uacct.menu.logout']}</value>
          </managed-property>
          <managed-property>
          <property-name>icon</property-name>
          <value>/images/logout.gif</value>
          </managed-property>
          <managed-property>
          <property-name>type</property-name>
          <value>global</value>
          </managed-property>
          <managed-property>
          <property-name>viewId</property-name>
          <value>/administration/Logout.jsp</value>
          </managed-property>
          <managed-property>
          <property-name>outcome</property-name>
          <value>GlobalLogout</value>
          </managed-property>
          </managed-bean>
          <!-- Campus Accounts menu tab (we also added tabs for Purchasing and Accounting) -->
          <managed-bean>
          <managed-bean-name>menuItem_CampusAccounts</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.menu.MenuItem</managed-bean-class>
          <managed-bean-scope>session</managed-bean-scope>
          <managed-property>
          <property-name>label</property-name>
          <value>#{resources['uacct.menu.campusAccounts']}</value>
          </managed-property>
          <managed-property>
          <property-name>viewId</property-name>
          <value>/administration/campusaccounts/CampusAccounts.jspx</value>
          </managed-property>
          <managed-property>
          <property-name>outcome</property-name>
          <value>GlobalCampusAccounts</value>
          </managed-property>
          </managed-bean>
          <!-- create the main menu menuModel bean, only one needed -->
          <managed-bean>
          <managed-bean-name>menuModel</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.menu.MenuModelAdapter</managed-bean-class>
          <managed-bean-scope>session</managed-bean-scope>
          <managed-property>
          <property-name>viewIdProperty</property-name>
          <value>viewId</value>
          </managed-property>
          <managed-property>
          <property-name>instance</property-name>
          <value>#{menuTreeModel.model}</value>
          </managed-property>
          </managed-bean>
          <!-- create the main menu menuTreeModel bean, only one needed -->
          <managed-bean>
          <managed-bean-name>menuTreeModel</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.menu.MenuTreeModelAdapter</managed-bean-class>
          <managed-bean-scope>session</managed-bean-scope>
          <managed-property>
          <property-name>childProperty</property-name>
          <value>children</value>
          </managed-property>
          <managed-property>
          <property-name>listInstance</property-name>
          <list-entries>
          <value-class>edu.uwec.financial.menu.MenuItem</value-class>
          <value>#{menuItem_GlobalLogout}</value>
          <value>#{menuItem_GlobalHelp}</value>
          <value>#{menuItem_CampusAccounts}</value>
          <value>#{menuItem_Purchasing}</value>
          <value>#{menuItem_Accounting}</value>
          </list-entries>
          </managed-property>
          </managed-bean>
          <managed-bean>
          <managed-bean-name>resources</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.resources.ResourceAdapter</managed-bean-class>
          <managed-bean-scope>application</managed-bean-scope>
          </managed-bean>
          


          由于這些 Bean 將引用資源文件,因此 faces-config.xml 文件還需要一個為其定義的項。在應用程序標記中,除了添加 default-render-kit 以外,還需要添加以下 xml 元素:

           

          <message-bundle>edu.uwec.financial.resources.UIResources</message-bundle>
          

              再次運行 index.jspx 文件將顯示一個與以下類似的頁面(如果您沒有添加用于購買、幫助等的托管 Bean,那么該頁面將只顯示 Campus Accounts 選項卡):

          了解 Oracle ADF:入門示例(圖七) 點擊查看大圖

           

          第 10 步:創建第一個輸入頁面。第一個“有用的”頁面將是一個允許用戶輸入帳號的頁面,這是管理帳戶的第一步。打開 faces-config.xml 圖并將一個新頁面拖至其上,然后雙擊圖標對該頁面進行編輯。 在本例中,我們希望為校園帳戶 (campusaccounts) 創建另一個組織級別,因此在 /administration/campusaccounts 中創建了 choose.jspx(在 public html 之后添加 administration\campusaccounts)。我們決定讓 JDeveloper 在第二步中創建托管 Bean。choose.jspx 的輔助 Bean 將自動命名為 Choose.java,并包含每個用戶界面組件的域。這意味著,您在每次添加組件時(即便是如 spacer 般簡單的組件),它都會通過自己的 getter 和 setter 顯示為一個域。對于編寫 Java 代碼以更改 spacer 中的屬性大小(如高度)來說,這十分有意義,然而還是會因此創建出復雜的輔助 Bean。在本例中,從自動創建的輔助 Bean 開始要更為簡單些(如果我們希望了解它執行的操作)。

              使用 Structure 窗口,將 替換為 welcome.jspx 中的 view 標記。實質上,您已將歡迎頁面用作模板。在 choose.jspx 的 Structure 窗口中,您可以刪除 view 標記,然后將 view 標記從 welcome.jspx 復制并粘貼到 choose.jspx 中。如果您選擇在 Source 窗口中進行更改,請注意保留指示 jspx 具有輔助 Bean 的 html 注釋 — 該 Oracle 慣例如下所示:

          <!--oracle-jdev-comment:auto-binding-backing-bean-name:backing_administration_campusaccounts_choose-->
          

              向在 GlobalCampusAccounts 上指定導航規則的 faces 配置文件添加導航規則,界面將導航至應用程序的第一個頁面。這是一個全局規則,因為您可以通過在任何應用程序的任意位置選擇 CampusAccounts 的選項卡來更改為 CampusAccounts。在 faces-config.xml 中輸入的標記是

          <navigation-rule>
          <navigation-case>
          <from-outcome>GlobalCampusAccounts
          <to-view-id>/administration/campusaccounts/choose.jspx
          </navigation-case>
          </navigation-rule>
          

              您可能需要編輯 commandMenuItems 中的 logout 和 home 圖標屬性,并更改它們的圖標值以使用 blaf 文件夾中的 gif 文件。

              您需要將 PanelHorizontal 插入面板頁以保存輸入文本組件。盡管也可以使用組件選項板 (Component palette),但通常我們認為利用 Structure 頁來執行該操作更為簡單(右鍵單擊 PanelPage 元素并選擇 ADF Faces Core 組件即可)。注意,ADF 表單包含有 PanelPage,因此您已經具有了自己的 html 表單元素。向水平面板添加一個 InputText 組件。在 Properties 窗口中,更改標簽以使用存儲在資源文件中的屬性。一種簡單的方法是先編輯資源文件并添加屬性,然后在 Structure 窗口中雙擊 inputText 元素,選擇 Bind 在 JSF 對象中查找 res,并選擇您剛才輸入的屬性值。一旦您習慣了訪問資源所需的 EL 格式,就會發現在 Property Editor 中鍵入屬性值也很簡單。在水平面板上的輸入文本組件后面添加一個 CommandButton,并更改其名稱以使用資源文件中定義的另一個屬性 — 再次建議您使用 Structure 窗口。

              雙擊按鈕轉至輔助 Bean。您需要從 InputText 組件獲取文本,并將其置于用戶狀態,以便當用戶訪問 CampusAccounts 應用程序的選項時它始終可用。

          public String commandButton1_action() {
          Object text = getInputText1().getValue();
          UserSystemState.storeCurrentAcctNum(new Integer(acctNum));
          return "list";
          }
          

              注意,此處無需任何驗證,而您在使用 Faces 組件的選項時會進行不必要的驗證。如果您在 InputText 元素上設置必需屬性,則會強迫用戶輸入值。如果您在 InputText 標記內插入一個 ValidateRegExp 驗證程序并添加模式 [0-9]+,則會要求用戶至少為帳號輸入一位數字。

          在本例中,我們添加了來自 SRDemo 的 UserSystemState,以將其用作模型并創建用于保存帳號的靜態函數。我們還必須添加 userSystemState(u 為小寫) 作為 faces-config.xml 文件中的托管 Bean 的名稱。您可以通過 managed-bean-class 域來推斷我們使用的程序包名。JDeveloper 管理 faces-config.xml 文件的明顯特征之一是,如果在編譯代碼或指定程序包名時出現問題,您就會在其標記中看到警告。JDeveloper 會主動分析 xml 配置文件。

           

          <managed-bean>
          <managed-bean-name>userSystemState</managed-bean-name>
          <managed-bean-class>edu.uwec.financial.view.backing.UserSystemState</managed-bean-class>
          <managed-bean-scope>session</managed-bean-scope>
          </managed-bean>
          

          以下是 UserSystemState 的起始代碼,用于創建 Command 按鈕中使用的靜態函數;它將替代所有來自 SRDemo 的域和方法。記住檢查程序包名:

          private HashMap _settings = new HashMap();
          private static final String CURRENT_ACCT_NUM = "CURRENT_ACCT_NUM";
          public Integer getCurrentAcctNum() {
          return (Integer)_settings.get(CURRENT_ACCT_NUM);
          }
          public void setCurrentAcctNum(Integer acctNum) {
          _settings.put(CURRENT_ACCT_NUM, acctNum);
          System.out.println("setCurrentAcctNum:"+acctNum); // some old fashioned testing
          }
          public static void storeCurrentAcctNum(Integer acctNum) {
          JSFUtils.setManagedBeanValue("userSystemState.currentAcctNum", acctNum);
          }
          public static void retrieveCurrentAcctNum() {
          JSFUtils.getManagedBeanValue("userSystemState.currentAcctNum");
          }
          

              該代碼比較奇特。userSystemState.currentAcctNum 似乎是 UserSystemState 中某個域的引用,但這個名稱沒有域。JSFUtils.getManagedBeanValue 函數調用的參數被解析為 getter;因此,userSystemState.currentAcctNum 將導致對 getCurrentAcctNum() 進行調用。

              如果運行 index.jspx 并選擇 CampusAccounts 選項卡,您應該看到應用程序的初始頁面將如下所示:

          了解 Oracle ADF:入門示例(圖八) 點擊查看大圖

           

          第 11 步:創建第一個 ADF 數據控件。(另請參閱 ADF 教程 5-2。)這一步充滿了樂趣,并且 ADF 的價值將在這一步真正體現出來。創建了允許用戶輸入帳號的頁面后,您現在希望獲取所有與該帳號關聯的交易 — 文件上的所有存款和支出。

              在 faces 導航圖中創建一個名為 /administration/campusaccounts/list.jspx 的頁面,并在編輯 list.jspx 時自動公開 UI 組件。復制來自 welcome.jspx 的 view 標記,如第 9 步中執行的操作。

              您需要連接列表頁以顯示 Detail 表(或 Detail DAO,具體取決于您如何考慮)中的相應行。請牢記,ADF 數據控件是構建 ADF 應用程序的關鍵,因此請打開 Data Control 選項板。

          了解 Oracle ADF:入門示例(圖九)

          您可以將 findAccountTransactionsByAccount() 函數拖放到列表頁 — 在這種情況下,您能夠創建諸如 Command 按鈕或參數表單之類的組件。

              而將 Detail 拖放到 panelPage 將創建一組可以從 Detail 表顯示的行 — 這些行具有一個通用帳號。考慮到在這種情形下一個較長的組件列表比較有用,因此選擇 Tables/ADF Read-only Table...Action Binding Editor 將顯示,因此您需要從選擇頁面獲取為帳號存儲的值,并將其作為要用于 findAccountTransactionsByAccount 的值進行綁定:

          了解 Oracle ADF:入門示例(圖十)


              現在,顯示所有域并啟用選擇和排序功能。您還可以通過在 Structure 窗口中雙擊每一列,來編輯列屬性以有選擇地啟用/禁用排序功能并更改列標題。在本例中,我們向資源文件添加了列標題,然后將 HeaderText 綁定到引用,如 #{res['uacct.campusAccounts.account']}。(您還可以通過在 Structure 窗口中雙擊組件,來重置表的選擇控件中的文本。)我們發現 Bind 按鈕比較有用。

              如果運行該應用程序并輸入一個有效帳號,您希望看到的內容將如下所示:

          了解 Oracle ADF:入門示例(圖十) 點擊查看大圖

              如果輸入 1000 作為帳號,您會發現自己仍位于選擇頁面。您需要指定一個從選擇頁面到列表頁面的轉換。在 faces-config.xml 文件中,打開 Design 窗口并確保 Component 選項板可見。選擇 JSF Navigation Case,然后單擊選擇頁面和列表頁面(請按此順序操作)。編輯轉換標簽并將 success 更改為 list,從而與 Choose.java 中 Command 按鈕操作返回的值相對應。現在,數據將顯示在列表頁面中。

              注意顯示這個表(包含 Detail 數據庫表中的項)是多么輕松。界面組件是一個 ADF JSF 組件,因此可以說您免費獲得了包括各種功能在內的復雜顯示對象,如分頁(總共 33 行結果,一次打印 10 行,如果結果全部匹配,可以一次打印全部 33 行)、分層(每行具有一種不同的顏色)、排序以及通過單選按鈕選擇單個行的能力(例如,能夠編輯其中的內容)。這個頁面的外觀使用默認的 Oracle 外觀,但是,更改用于指定組件標簽的 Css 文件可以獲得不同的顏色、字體和圖標。

              此外,您還會注意到利用 ADF 提供的復雜數據控件可以十分輕松地實現數據訪問。在將 ADF Read-Only 表拖放到頁面之后,系統會推斷返回的輔助對象類型 (Detail.java),并自動將其用于創建相應列。系統提供了行集行為(一次 10 行),正如基于派生自原始數據庫表的元數據的類型解析一樣。

          第 12 步:創建編輯頁面。(另請參閱 Oracle ADF 教程 10-2。)在列表頁面上,用于選擇的 Table 控件 (facet) 包含一個 af:tableSelectOne 標記,該標記內部有一個 Command 按鈕。如果雙擊 Command 按鈕,將打開輔助 Bean,您可以在其中調用輔助函數來獲取數據以唯一標識選定行,以便將其存儲以用于下一頁面的檢索。

          public String commandButton1_action() {
          setCurrentTransactionIdFromRow();
          return "edit";
          }
          
          List.java 中的輔助函數如下所示:
          private void setCurrentTransactionIdFromRow() {
          FacesContext ctx = FacesContext.getCurrentInstance();
          JUCtrlValueBindingRef tableRowRef = 
          (JUCtrlValueBindingRef) this.getTable1().getRowData(); Integer transId = (Integer)tableRowRef.getRow().getAttribute("cdPostSequence"); UserSystemState.storeCurrentTransId(transId); }
          
          

              需要將 storeCurrentTransId() 添加至 UserSystemState,以便將第 9 步中的 storeCurrentAcctNum() 用作模型。

              到目前為止,已經介紹了選擇要編輯的行所需進行的更改。現在,需要創建一個要在其中進行編輯的新 jspx 頁面。在 faces-config.xml 文件中,添加一個 jsp 頁面,然后對其進行編輯以命名為 edit.jspx。在 Component 選項板中,選擇 JSF Navigation Case,并在 Design 窗口中將轉換標簽更改為編輯,以匹配 Command 按鈕中指定的返回值。

              轉到 edit.jspx 頁面,從 Data Control 選項板中選擇 findOneTransaction/Detail,并使用 Forms/ADF Form 將其拖放至面板頁。在其中包含一個 Submit 按鈕,并更改域順序(如果需要)。將參數設置為 JSF 對象中的值,以使用 UserSystemState 中的 acctNum 和 transId。完成操作綁定之后,您可以將不希望用戶編輯的域的 readOnly 屬性設置為 true。在 Structure 窗口中雙擊每一個 inputText 域,然后從資源文件設置它們的標簽。首先在資源文件中編輯值要更為簡單。允許用戶從編輯頁面退出可能是最好的做法,因此您可以用 PanelGroup 圍繞 Submit 按鈕,然后在 Submit 之前或之后添加另一個 CommandButton。您需要選擇這些按鈕并添加返回值。對于 Cancel 按鈕,無需調用與該按鈕對應的輔助函數,就可以編輯 action 屬性并指定導航轉換值。Cancel 按鈕的一些原始內容(如“cancel”)將生效。在 faces-config.xml Design 窗口中添加一個用于提交返回值的 jsf 導航示例,以便從編輯頁面返回列表頁面。另一種比較好的方法是,首先在 faces-config.xml 文件中設置導航值,在這種情況下,選擇這些按鈕的 action 屬性值時,該值將顯示為選項 — JDeveloper 使用配置文件比較有利。


              您仍然需要編寫代碼來保持在編輯頁面上所作的更改。但在本示例中,您將再次使用 ADF 開發范例。換言之,與其在輔助 Bean 中編寫代碼,不如依靠 JDeveloper/ADF 向導來編寫保持更改所需的代碼。您還將使用在最初創建 ORM 并生成會話 Bean 時自動創建的 mergeEntity() 函數。

              如 ADF 教程第 10 章所建議,在 edit.jspx 頁面上打開 Design 窗口,然后打開 Data Control 選項板。將 mergeEntity() 方法拖放到 Submit 按鈕上,并選擇 Bind Existing CommandButton。下一個顯示的頁面是 Action Binding Editor。 雙擊向導下一步中的值框(或如果 ... 按鈕顯示選擇該按鈕),打開 ADF Bindings 中的綁定。請牢記該綁定引用 ADF 中提供的所有綁定。打開 findOneTransactionIter 節點并選擇 currentRow 中的 dataprovider。構建的表達式(指定當前記錄)是 ${bindings.findOneTransactionIter.currentRow.dataProvider}。注意,Submit 按鈕的 ActionListener 屬性已重置為 #{bindings.mergeEntity.execute}。可將 action 屬性設置為“list”,以便完成對數據庫的更改后,我們的界面將返回到列表頁面。將其值可進行更改的所有文本域的 immediate 屬性設置為 true。編輯頁面應如下所示:

          了解 Oracle ADF:入門示例(圖十二)
          此外,ADF 可以非常輕松地添加編輯事務的功能。雖然此處未提及,但您還可以向會話 Bean 添加另一個函數,以便在調用 mergeEntity 之前將業務規則應用到編輯域 (Apply Business Rules to Edited Field)。

          適可而止

           

          還有許多演示無法全部囊括在本次練習中,但您仍可以通過教程或開發人員指南來完成:

          • 您沒有為應用程序添加任何安全措施,以確保只有簽名信息庫中的用戶可以添加記錄(或編輯記錄)。簡單的安全性將允許您打印用戶名而不是空值。
          • 您沒有處理錯誤或特殊條件。
          • 您沒有使用 ADF 的驗證功能。例如,確保輸入文本框在用戶輸入新交易時不為空就比較有意義。
          • 添加一個選擇以允許用戶從交易列表刪除存款或支出,這樣比較有趣。

          但是您必須適可而止!

          感謝并總結

           

              我們衷心感謝 JDeveloper 團隊就本文中有關 JDeveloper 功能的語句精確性進行了檢查。Oracle 文檔詳細列出了許多此處未提及的 JDeveloper 特性。

              正如我們在簡介中所述,在您已經熟悉了某種特定開發方法后很難再轉而使用另一種技術。本文中,我們使用了 Spring JDBC 模板進行數據建模、利用 Spring MVC 和 Spring Web Flow 進行導航,以及將 Eclipse 用作開發環境。回想起來,開始我們是希望了解如何在新環境中做我們已經知曉的事情,而選件(如輔助 Bean)則助了我們一臂之力。最初我們沒有打算嘗試 TopLink,甚至尋求另一種方法來使用 ADF 控件。值得高興的是,我們閱讀了 Oracle 參考,這些參考使我們對于嘗試 ADF 提供的其他功能充滿了信心。

              對于應用程序開發框架而言,ADF 無疑是一個卓越的工具、一個不錯的助手。我們力圖通過 ADF 和 JDeveloper 探索出若干其他方法,包括

          • 使我們現有的基于 Spring 的后端服務能夠用作可從 ADF Faces 接口調用的 Web 服務。Oracle ACE Lucas Jellema 撰寫的網志給予了我們嘗試這種想法的靈感。
          • 使用 Oracle XML Publisher 作為構建報表頁面的另一種方法
          • 將 BPEL 插件用于 JDeveloper,以根據業務流程中人為干預的需要進行建模。據說,BPEL 之于流程管理正如 SQL 之于數據管理。

          Oracle 提供的開發工具系列可以很好地滿足我們的需求。

          提示與技巧

          1. 一不做,二不休。文中數次提及的其當之無愧的一個事實是:JDeveloper 和 ADF 是功能強大的端到端解決方案。它們具有挑戰開發環境(如 .net)的實力。例如,我們最初計劃不使用 TopLink 將示例應用程序放在一起,并認為在應用程序中編寫基于 Spring 的數據訪問很輕松。閱讀 ADF 教程激發了我們對 TopLink 的好奇,因此我們決定嘗試使用它,并在開始時只是認為這是無害的。在為交易添加第一個列表表單花費了大約 90 秒后,我們的態度發生了根本性轉變。最初,mergeEntity 函數似乎只是由 TopLink 創建的另一個產物。在添加了編輯頁面之后,我們了解了其價值,以及可對 Faces 組件進行無縫訪問的 ADF 控件的價值。JDeveloper 提供了集成的開發環境。ADF 不僅是一組 UI 組件,還是一個完善的前端、后端框架,可提供能夠顯著提高工作效率的工具。

          2. JDeveloper 與 Eclipse 或 Websphere Application Developer 在創建程序包、復制和移動文件方面存在著區別。對于圖像和其他非 Java 文件,我們發現復制和移動文件最簡單的方法是在 Windows Explorer 中進行操作,然后在 Applications 窗口中進行刷新。使用 File 中的 Import 選項時,請確保編輯 CopyTo 行以將完整的文件夾(程序包)名包括在內。重命名文件和移動文件還會對配置文件和屬性值造成重大破壞。我們一般使用 Property Editor 中的 ... 選項來設置圖像和其他文件的屬性值。編輯配置文件需要敏銳的眼光和一定的耐心。我們可能犯的最嚴重錯誤就是在 faces 配置文件中將 campusAccounts 更改為 campusaccounts。頁面之間不會出現轉換,從而浪費了大量時間。誠然,使用 JDeveloper 時保持程序包一致的確令人煩躁。

          3. 下載 SRDemo 非常簡單,如果您剛好安裝了 JDeveloper。在 Help 菜單中,選擇 Check for Updates,然后選擇 Official Oracle Extensions。選取 ADF SRDemo,并按向導完成相應操作。要運行它,請轉至 SRDemo 應用程序并選擇 index.jspx 和綠色箭頭。一旦下載了演示程序,您就可以訪問其全部文件,包括幾乎所有應用程序都需要的幫助類(如 JSFUtils 和 UserSystemState)。您需要為 SRDemo 提供數據庫模式。

          4. 您不必離開 JDeveloper 就可查看數據庫表的值。從 Connections 選項卡中,選擇您的 Connection 和模式,然后打開一個表。表值將顯示在 Data 選項卡(可能位于窗口底部)中。

              Tom Moore 是威斯康星大學伊奧克萊爾分校的高級顧問,專攻知識與技術服務。Tom 持有威斯康星大學密爾沃基分校的計算機科學碩士學位,熱衷于 Java 和開放源代碼產品(如 Struts 和 Spring)。在他將注意力轉向 Oracle 開發工具和框架之前,已是威斯康星大學伊奧克萊爾分校計算機科學系的老成員。
            posted on 2007-08-18 10:29 JavaPoint 閱讀(1716) 評論(1)  編輯  收藏 所屬分類: Java

            評論:
            # re: 了解 Oracle ADF:入門示例 2016-08-05 17:11 | 鄭州
            hhhh  回復  更多評論
              
            主站蜘蛛池模板: 邳州市| 通城县| 丽江市| 德州市| 五河县| 三都| 胶州市| 曲麻莱县| 哈尔滨市| 扎囊县| 玉田县| 西宁市| 景泰县| 启东市| 北安市| 临清市| 舞阳县| 建瓯市| 丰镇市| 阿拉尔市| 石景山区| 绵竹市| 廊坊市| 花垣县| 金寨县| 南宁市| 宜黄县| 融水| 临湘市| 称多县| 平顺县| 孙吴县| 鹤壁市| 彭水| 大石桥市| 奉节县| 新龙县| 武清区| 望奎县| 循化| 乡城县|