<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    世事如棋
    Aspire to Professionalism
    posts - 4,  comments - 12,  trackbacks - 0
    作者:Andrei Cioroianu
    轉(zhuǎn)自:Oracle Technology Network http://www.oracle.com/technology/global/cn/pub/articles/andrei_reuse.html

    了解如何利用 JSP 標(biāo)記文件、JSF 和 Oracle ADF Faces 重用 Web 內(nèi)容和 Java 代碼。

    本文相關(guān)下載:
    示例代碼
    Oracle JDeveloper 10g (10.1.3)

    2005 年 10 月發(fā)表

    代碼重用是提高開(kāi)發(fā)人員生產(chǎn)效率和應(yīng)用程序可維護(hù)性的一種非常好的方式。您應(yīng)當(dāng)總是尋找設(shè)計(jì)良好的框架和可自定義的組件,而不是從頭重來(lái)。應(yīng)用程序特有的代碼也可以在模塊甚至相關(guān)項(xiàng)目間重用。后一種可重用性可使您快速修改,整體利用新特性,并減少測(cè)試和調(diào)試的時(shí)間。

    雖然這些聽(tīng)起來(lái)像是針對(duì)程序員的不錯(cuò)建議,但 Web 開(kāi)發(fā)人員也應(yīng)當(dāng)注意這些事情。許多 Web 開(kāi)發(fā)人員已經(jīng)在使用諸如 Java Server Faces (JSF)、Oracle ADF Faces 和 Apache MyFaces 之類的框架,這些框架提供了許多內(nèi)置組件并支持創(chuàng)建其他可重用組件。然而,很多時(shí)候是將許多 HTML 和 JSP 標(biāo)記從一個(gè) Web 頁(yè)面復(fù)制粘貼到其他頁(yè)面中,這意味著當(dāng) Web 內(nèi)容改變時(shí)將不得不修改這些頁(yè)面中的重復(fù)標(biāo)記。此外,如果沒(méi)有更新某些頁(yè)面,那么應(yīng)用程序的外觀將會(huì)不一致。如果跨頁(yè)面重用 UI 組件就不會(huì)發(fā)生這種情況了,這是因?yàn)榘l(fā)生變化時(shí)只需在一個(gè)地方進(jìn)行編輯就可以了。

    在本文中,我將提供一些在基于 JSF 和 ADF Faces 的 Web 應(yīng)用程序中重用 UI 組件的最佳實(shí)踐。您將了解到如何創(chuàng)建定義 Web 頁(yè)面布局的模板,以及如何重用表單、菜單和按鈕欄。您還將了解到如何轉(zhuǎn)換現(xiàn)有的 JSP 頁(yè)面以使它們更易于維護(hù),以及如何將由 JSF 和 Oracle ADF Faces 提供的組件與 JSTL 和現(xiàn)代 JSP 特性(例如標(biāo)記文件)一起使用。

    Java Web 可重用特性

    自從第一個(gè)版本起,JSP 就已經(jīng)提供了一些鼓勵(lì)可重用的基本機(jī)制,例如 JavaBeans 支持、基于 Servlets API RequestDispatcher 的 <%@include%> 指令和 <jsp:include> 標(biāo)記。JSTL 增加了 <c:import> 標(biāo)記,它使您能夠包含某個(gè)資源的內(nèi)容,該資源可以位于同一個(gè)應(yīng)用程序、服務(wù)器中,甚至也可以在遠(yuǎn)程服務(wù)器上。Struts Tiles 圍繞著這種內(nèi)容包含特性構(gòu)建了一個(gè)完整的框架。JSF 也支持這一特性,允許您構(gòu)建使用 <f:subview> 標(biāo)記的子表單。JSP 2.0 增加了一個(gè)稱為“隱式包含”的新特性。這些特性使用 <include-prelude><include-coda> 在 web.xml 文件中聲明。正如您所能看到的,雖然頁(yè)面/片斷包含種類各異,但每一種都有其自己的用途和上下文。

    對(duì)自定義標(biāo)記的支持從 JSP 1.1 就有了,它為構(gòu)建標(biāo)記庫(kù)提供了一個(gè) API。JSP 1.2 對(duì)該 API 進(jìn)行了增強(qiáng),但很多人認(rèn)為它太復(fù)雜了。因此,JSP 2.0 定義了一個(gè)具有相同功能的全新 API。這個(gè)為標(biāo)記庫(kù)提供的新 API 稱為簡(jiǎn)單標(biāo)記 API,舊 API 現(xiàn)在稱為標(biāo)準(zhǔn)標(biāo)記 API。許多 Web 框架(如 Struts、JSF 和 JSTL)仍使用標(biāo)準(zhǔn)標(biāo)記 API,以便可以與 JSP 1.2 以及 JSP 2.0 一起使用。簡(jiǎn)單標(biāo)記 API 是另一種 JSP 2.0 特性 — 標(biāo)記文件 — 的基礎(chǔ),該特性使您能夠使用 JSP 語(yǔ)法構(gòu)建標(biāo)記庫(kù)。除了簡(jiǎn)單標(biāo)記和標(biāo)記文件之外,JSP 2.0 規(guī)范還定義了 EL 函數(shù),后者使您能夠使用 EL 語(yǔ)法從 JSP 頁(yè)面中調(diào)用靜態(tài) Java 方法。

    JSF 標(biāo)準(zhǔn)將組件定義為它的可重用單元。這些組件比自定義標(biāo)記更強(qiáng)大,但也更難設(shè)計(jì)和實(shí)施。因?yàn)橛袔讉€(gè)公司和開(kāi)放源代碼機(jī)構(gòu)正在制作可供使用的 JSF 組件庫(kù),所以您可能不需要構(gòu)建自己的 JSF 組件。本文的示例使用了 Oracle ADF Faces,它是基于 JSF 標(biāo)準(zhǔn)的最先進(jìn)的框架。

    創(chuàng)建頁(yè)面模板。典型 Web 應(yīng)用程序的所有頁(yè)面共享一個(gè)公共布局,該布局可以定義在一個(gè)地方,如 JSP 標(biāo)記文件中。該模板可以生成標(biāo)題和正文標(biāo)記、應(yīng)用程序的菜單以及在所有頁(yè)面中出現(xiàn)的其他部分。此外,它可以包含用于加載資源綁定、設(shè)置 JSP 變量等的設(shè)置標(biāo)記。在應(yīng)用程序的每個(gè) Web 頁(yè)面中重復(fù)該標(biāo)記是沒(méi)有意義的。在這一部分中,您將了解如何使用 Oracle JDeveloper 10g (10.1.3)(撰寫(xiě)此文時(shí)為早期試用版)基于 JSF 和 Oracle ADF Faces 構(gòu)建自定義模板。

    JDeveloper 提供了一個(gè)創(chuàng)建 JSF 頁(yè)面模板的向?qū)А?File 菜單中選擇 New 項(xiàng),打開(kāi) New Gallery 窗口。然后,轉(zhuǎn)至 Web Tier 中的 JSF 類別,在右側(cè)面板中選擇 JSF JSP Template 并單擊 OK:

    圖 1

    單擊 Next 跳過(guò) Welcome 頁(yè)面,然后選擇您使用的 J2EE 版本,并再次單擊 Next:

    圖 2

    為模板提供一個(gè)文件名:

    圖 3

    選擇組件綁定樣式:

    圖 4

    指定是否要使用錯(cuò)誤頁(yè)面:

    圖 5

    選擇要使用的標(biāo)記庫(kù):

    圖 6

    提供頁(yè)面標(biāo)題和其他頁(yè)面屬性:

    圖 7

    單擊 Finish。JDeveloper 將創(chuàng)建該模板并在可視化編輯器中將其打開(kāi)。您可以使用 Component Palette 將 JSF 和 Oracle ADF Faces 組件添加到該模板中。然后,您可以在 New Gallery 窗口中從 Template 中選擇 JSF JSP,基于您剛創(chuàng)建的模板創(chuàng)建 JSF 頁(yè)面。這是從模板構(gòu)建頁(yè)面的一種非常簡(jiǎn)單的方法。另一種方法是將該共用的 JSF 標(biāo)記移到一個(gè)可重用的標(biāo)記文件中。以下段落使用了第二種方法。

    創(chuàng)建標(biāo)記文件。從 File 菜單中選擇 New 項(xiàng),打開(kāi) New Gallery 窗口。然后,轉(zhuǎn)至 Web Tier 中的 JSP 類別,在右側(cè)面板中選擇 JSP Tag File 并單擊 OK:

    圖 8

    JDeveloper 將打開(kāi)一個(gè)創(chuàng)建 JSP 標(biāo)記文件的向?qū)Т翱凇螕?Next 跳過(guò) Welcome 頁(yè)面,在 File Name 域中輸入 pageTemplate.tag 并單擊 Next:

    圖 9

    現(xiàn)在您就可以定義模板標(biāo)記的屬性了。假定您正在構(gòu)建一個(gè)基于 Web 的向?qū)ВM總€(gè)頁(yè)面都有一個(gè)步驟 ID 和一個(gè)標(biāo)題。標(biāo)記文件需要該信息來(lái)為每個(gè)頁(yè)面自定義模板標(biāo)記。單擊 Add 按鈕,輸入 step 屬性名,并將 Required 設(shè)為 true。對(duì)另一個(gè)名稱為 title 的屬性執(zhí)行同樣的操作:

    圖 10

    單擊 Next 和 Finish。JDeveloper 將在 WEB-INF 目錄的 tags 子目錄下創(chuàng)建 pageTemplate.tag 文件。用 <%@attribute%> 指令定義這兩個(gè)標(biāo)記屬性:
    <%@ attribute name="step" required="true" %>
    <%@ attribute name="title" required="true" %>
    
    在創(chuàng)建標(biāo)記文件之后,JDeveloper 將打開(kāi)它進(jìn)行編輯。以下段落介紹了本文通篇用到的示例應(yīng)用程序的模板代碼。

    在標(biāo)記文件中使用 JSF 和 Oracle ADF Faces。無(wú)論您是否想在普通頁(yè)面的標(biāo)記文件內(nèi)使用這些框架,您都必須用 <%@taglib%> 指令來(lái)對(duì)其進(jìn)行聲明。在 Component Palette 中選擇 JSP,然后單擊 Taglib。您需要在一個(gè)對(duì)話框中輸入要使用的標(biāo)記庫(kù)的 URI 和前綴:

    圖 11

    您還可以使用 Component Palette 來(lái)將任何標(biāo)記拖放到 JSP 頁(yè)面上,如果它的 <%@taglib%> 指令不在頁(yè)面中,那么 JDeveloper 將自動(dòng)添加它。pageTemplate.tag 示例使用了四個(gè)標(biāo)記庫(kù):JSTL Core、JSF Core、Oracle ADF Faces Core 和 Oracle ADF Faces HTML:
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
    <%@ taglib prefix="af" 
    uri="http://xmlns.oracle.com/adf/faces" %>
    <%@ taglib prefix="afh" 
    uri="http://xmlns.oracle.com/adf/faces/html" %>
    
    在同時(shí)使用 JSF 和 JSTL 時(shí),或者在標(biāo)記文件中使用 JSF 時(shí)有一件非常重要的事情您必須始終牢記:JSF 框架不支持頁(yè)面范圍,后者是 JSTL 標(biāo)記的默認(rèn) JSP 范圍。因此,您應(yīng)當(dāng)顯式指定與 JSTL、JSF 和 Oracle ADF Faces 的標(biāo)記結(jié)合使用的 JSP 變量的請(qǐng)求范圍。此外,標(biāo)記文件的所有屬性都可以通過(guò)保存在頁(yè)面范圍內(nèi)的 JSP 變量來(lái)訪問(wèn)。您必須復(fù)制請(qǐng)求范圍內(nèi)的屬性,以便它們可以和 JSF 和 Oracle ADF Faces 標(biāo)記一起使用:
    <c:set var="pageTitle" scope="request" value="${pageScope.title}"/>
    
    您還可以將屬性的值存儲(chǔ)在由 JSF 管理的 Bean 內(nèi)。假定您有一個(gè)名稱為 WizardBean 的類,該類在 faces-config.xml 中被配置為受管 Bean:
    <faces-config>
        ...
    <managed-bean>
    <managed-bean-name>wizard</managed-bean-name>
    <managed-bean-class>webreuse.WizardBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
        ...
    </faces-config>
    
    示例 Bean 有一個(gè) currentStep 屬性,您可以在該屬性中存儲(chǔ) step 屬性的值。該操作可以利用 JSTL 的 <c:set> 標(biāo)記來(lái)完成,但您必須確保該 Bean 存在于會(huì)話范圍中(如 faces-config.xml 文件中所聲明的那樣)。只有在 JSF EL 表達(dá)式中首次引用受管 Bean 實(shí)例時(shí),JSF 才會(huì)創(chuàng)建該實(shí)例。如果在訪問(wèn)受管 Bean 的 JSF 或 Oracle ADF Faces 標(biāo)記之前執(zhí)行 JSTL 標(biāo)記,那么,您應(yīng)當(dāng)使用 <jsp:useBean>以確保該 Bean 實(shí)例存在于會(huì)話范圍中。如此,您就可以安全地使用 <c:set> 標(biāo)記了:
    <jsp:useBean class="webreuse.WizardBean" 
    id="wizard" scope="session"/>
    <c:set target="${wizard}" property="currentStep" 
    value="${pageScope.step}"/>
    
    以上代碼可以手動(dòng)輸入,或者可以使用 JDeveloper 的 Component Palette。選擇 JSP,然后單擊 UseBean,添加 <jsp:useBean> 標(biāo)記。JDeveloper 將打開(kāi)一個(gè)對(duì)話框,您必須在其中提供該標(biāo)記的屬性:

    圖 12

    最后,您可以在 pageTemplate.tag 文件中添加模板代碼:
    <f:view>
    <afh:html>
    <afh:head title="#{pageTitle}"/>
    <afh:body>
    <af:panelPage title="#{pageTitle}">
    <jsp:doBody/>
    </af:panelPage>
    </afh:body>
    </afh:html>
    </f:view>
    
    所有的 JSF 和 Oracle ADF Faces 組件都必須置于 <f:view> 內(nèi)部。<afh:html><afh:head><afh:body> 組件將生成具有相同名稱的 HTML 標(biāo)記。<af:panelPage> 組件顯示頁(yè)面標(biāo)題。然后,<jsp:doBody> 將調(diào)用您放在使用模板標(biāo)記的 JSP 頁(yè)面中的 <tags:pageTemplate></tags:pageTemplate> 之間的 JSP 內(nèi)容。這種 JSP 頁(yè)面將類似于:
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <tags:pageTemplate step="..." title="...">
    ... JSP content executed by doBody ...
    </tags:pageTemplate>
    
    當(dāng)執(zhí)行該頁(yè)面時(shí),標(biāo)記文件將生成 <html><head><body> 標(biāo)記以及頁(yè)面標(biāo)題和其他標(biāo)題標(biāo)記。然后,模板標(biāo)記文件將調(diào)用包在 <tags:pageTemplate></tags:pageTemplate> 之間的 JSP 內(nèi)容。在此之后,標(biāo)記文件可能會(huì)生成一個(gè)頁(yè)腳,并用 </body></html> 來(lái)完成頁(yè)面。下一部分將在基于 Web 的向?qū)У捻?yè)面中使用模板標(biāo)記。

    重用表單、菜單和其他 UI 組件

    利用 JSF 和 Oracle ADF Faces 組件構(gòu)建的 UI 面板可以使用 "subviews" 或 JSP 標(biāo)記文件在多個(gè)頁(yè)面中重用。前一種解決方案與舊的 JSP 1.2 版本兼容,但標(biāo)記文件更靈活。這一部分將介紹如何基于 JSF 和 Oracle ADF Faces 將一個(gè) Web 表單分成多個(gè)頁(yè)面和標(biāo)記文件。當(dāng)用戶第一次訪問(wèn)應(yīng)用程序時(shí),他將使用包含后退和前進(jìn)按鈕的向?qū)浇缑鎭?lái)逐步瀏覽這些頁(yè)面。在此以后,他可能想更新最初提供的信息。在這種情況下,用戶需要使用基于菜單的界面直接訪問(wèn)應(yīng)用程序的頁(yè)面。

    可以在上述的兩種情況下使用同一種 Web 表單。此外,所有的表單可以組合在一個(gè)確認(rèn)頁(yè)面中,該頁(yè)面可以讓用戶以只讀模式查看信息。當(dāng)用戶必須修改其中一個(gè)表單時(shí),可以編輯單個(gè)文件。每一個(gè)修改都將顯示在向?qū)эL(fēng)格的界面(用于從用戶那獲取信息)、確認(rèn)頁(yè)面(用于查看信息)和基于菜單的界面(由用戶用于更新信息)中。如果不重用表單,您將必須在三個(gè)不同的地方進(jìn)行相同的修改。

    開(kāi)發(fā) Backing Bean。您在前一部分中已經(jīng)發(fā)現(xiàn),示例應(yīng)用程序使用了一個(gè)名稱為 WizardBean 的 Backing Bean。pageTemplate.tag 文件設(shè)置了 currentStep 屬性,該屬性保存用戶在瀏覽器中看到的當(dāng)前表單的步驟 ID。示例應(yīng)用程序在確認(rèn)頁(yè)面(第四步)之前使用了三個(gè)表單,確認(rèn)頁(yè)面的 ID 由 MAX_STEP 常量來(lái)定義。將該常量公開(kāi)為名為 maxStep 的 bean 屬性,以便可以在 Web 頁(yè)面中使用 JSF EL 來(lái)訪問(wèn)它:
    package webreuse;
    
    public class WizardBean implements java.io.Serializable {
    public final static int MAX_STEP = 4;
    private int currentStep;
    private String connName, connType;
    private String userName, password, role;
    private String driver, hostName, sid;
    private int jdbcPort;
    
    public int getMaxStep() {
    return MAX_STEP;
        }
    
    public int getCurrentStep() {
    return currentStep;
        }
    
    public void setCurrentStep(int currentStep) {
    this.currentStep = currentStep;
        }
    
        ...
    }
    
    currentStepmaxStep 之外,WizardBean 類還有幾個(gè)其他的屬性可用于保存用戶提供的向?qū)?shù):connNameconnTypeuserNamepasswordroledriverhostNamesidjdbcPort。該示例應(yīng)用程序與用戶數(shù)據(jù)無(wú)關(guān),但在實(shí)際情況中,向?qū)⒂盟鼇?lái)配置數(shù)據(jù)庫(kù)連接。WizardBean 還實(shí)施了幾個(gè)在用戶單擊向?qū)У陌粹o時(shí)將執(zhí)行 JSF 操作。這些方法稍后將在本部分中進(jìn)行介紹。

    要?jiǎng)?chuàng)建您自己的 Bean,您可以在 File 菜單中選擇 New 來(lái)打開(kāi) New Gallery 窗口。然后,轉(zhuǎn)至 General 中的 Simple Files 類別,在右側(cè)面板中選擇 Java Class,并單擊 OK:

    圖 13

    提供類名和程序包名稱。然后單擊 OK,創(chuàng)建該類:

    圖 14

    在聲明一個(gè)字段之后(例如 private int currentStep),右鍵單擊其名稱并選擇 Generate Accessors。單擊 OK,生成 get 和 set 方法:

    圖 15

    創(chuàng)建可重用表單。將向?qū)У闹鞅韱尉帉?xiě)為可重用標(biāo)記文件。第一個(gè)表單 (form1.tag) 包含一個(gè)文本域和一個(gè)下拉列表:
    <!-- form1.tag -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:inputText id="connName" required="true" columns="40"
    label="Connection Name:" value="#{wizard.connName}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    <af:selectOneChoice id="connType" required="true"
    label="Connection Type:" value="#{wizard.connType}"
    readOnly="#{wizard.currentStep == wizard.maxStep}">
    <af:selectItem label="Oracle (JDBC)" value="Oracle_JDBC"/>
    </af:selectOneChoice>
    
    第二個(gè)表單 (form2.tag) 包含三個(gè)文本域:
    <!-- form2.tag -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:inputText id="userName" required="true" columns="40"
    label="User Name:" value="#{wizard.userName}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    <af:inputText id="password" required="true" columns="40"
    label="Password:" value="#{wizard.password}" secret="true"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    <af:inputText id="role" required="false" columns="40"
    label="Role:" value="#{wizard.role}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    第三個(gè)表單 (form3.tag) 與其他兩個(gè)表單類似:
    <!-- form3.tag -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:selectOneChoice id="driver" required="true"
    label="Driver:" value="#{wizard.driver}"
    readOnly="#{wizard.currentStep == wizard.maxStep}">
    <af:selectItem label="thin" value="thin"/>
    <af:selectItem label="oci8" value="oci8"/>
    </af:selectOneChoice>
    
    <af:inputText id="hostName" required="true" columns="40"
    label="Host Name:" value="#{wizard.hostName}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    <af:inputText id="sid" required="true" columns="40"
    label="SID:" value="#{wizard.sid}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    <af:inputText id="jdbcPort" required="true" columns="40"
    label="JDBC Port:" value="#{wizard.jdbcPort}"
    readOnly="#{wizard.currentStep == wizard.maxStep}"/>
    
    正如您可能已經(jīng)注意到的那樣,三個(gè)標(biāo)記文件中沒(méi)有一個(gè)包含了用于排列 Oracle ADF Faces 組件的標(biāo)記。不含任何布局標(biāo)記使得您可以獨(dú)立地使用表單標(biāo)記,或在確認(rèn)頁(yè)面中組合它們。Oracle ADF Faces 提供了一個(gè)名稱為 <af:panelForm> 的強(qiáng)大組件,它將自動(dòng)執(zhí)行布局。除了主要的組件之外,表單通常包含有其他的標(biāo)記,例如 <h:messages globalOnly="true"/><af:objectLegend name="required"/>。所有這些標(biāo)記都可以集中在一個(gè)名為 formTemplate.tag 的標(biāo)記文件中:
    <!-- formTemplate.tag -->
    
    <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <h:panelGrid columns="1" border="0" cellspacing="5">
    <h:messages globalOnly="true"/>
    <af:objectLegend name="required"/>
    <af:panelForm>
    <jsp:doBody/>
    </af:panelForm>
    </h:panelGrid>
    
    使用 pageTemplate.tag 和 formTemplate.tag 的 JSF 頁(yè)面將類似于:
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <tags:pageTemplate step="..." title="...">
    	<af:form id="...">
    		...
    		<tags:formTemplate>
    			<tags:form123/>
    		</tags:formTemplate>
    		...
    	</af:form>
    </tags:pageTemplate>
    
    在前面的代碼段中,<tags:form123/> 代表向?qū)У娜齻€(gè)主表單中的任意一個(gè)(&lt;tags:form1/><tags:form2/><tags:form3/>)。除了這些表單的組件之外,<af:form> 可能包含其他的 JSF 和 Oracle ADF Faces 組件(例如按鈕)。下一段介紹了使用 <tags:pageTemplate><tags:formTemplate><tags:form1><tags:form2><tags:form3> 的應(yīng)用程序頁(yè)面。這些具體的例子充分說(shuō)明了利用可重用標(biāo)記文件構(gòu)建 JSF 用戶界面的實(shí)際好處。

    向?qū)эL(fēng)格的界面。基于 Web 的向?qū)У捻?yè)面將包含標(biāo)記為 Back、Next 和 Finish 的按鈕。可以在一個(gè)名為 stepButtons.tag 的標(biāo)記文件中定義這些按鈕:
    <!-- stepButtons.tag -->
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:panelButtonBar>
    
    <af:singleStepButtonBar
    selectedStep="#{wizard.currentStep}"
    maxStep="#{wizard.maxStep}"
    previousAction="#{wizard.previousAction}"
    nextAction="#{wizard.nextAction}"/>
    
    <c:if test="${wizard.currentStep == wizard.maxStep}">
    <af:commandButton text="Finish"
    action="#{wizard.finishAction}"/>
    </c:if>
    
    </af:panelButtonBar>
    
    WizardBean 類包含當(dāng)用戶單擊按鈕時(shí)將執(zhí)行的操作方法:
    package webreuse;
    
    public class WizardBean implements java.io.Serializable {
        ...
    
    public String previousAction() {
    if (currentStep <= 1)
    return null;
    else {
    currentStep--;
    return "step" + currentStep;
            }
        }
    
    public String nextAction() {
    if (currentStep >= getMaxStep())
    return null;
    else {
    currentStep++;
    return "step" + currentStep;
            }
        }
    
    public String finishAction() {
    currentStep = 0;
    return "finished";
        }
    
        ...
    }
    
    操作方法返回的結(jié)果將在 faces-config.xml 文件的導(dǎo)航規(guī)則中使用:
    <faces-config>
        ...
    <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
    <from-outcome>step1</from-outcome>
    <to-view-id>/step1.jsp</to-view-id>
    </navigation-case>
    </navigation-rule>
        ...
    <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
    <from-outcome>step4</from-outcome>
    <to-view-id>/confirm.jsp</to-view-id>
    </navigation-case>
    </navigation-rule>
    
    <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
    <from-outcome>finished</from-outcome>
    <to-view-id>/index.jsp</to-view-id>
    </navigation-case>
    </navigation-rule>
        ...
    </faces-config>
    
    除了所有可見(jiàn)的組件之外,向?qū)ы?yè)面還將包含一個(gè)與 WizardBean 的 currentStep 屬性綁定的隱藏字段。您已經(jīng)看到了 pageTemplate.tag 將在每一次執(zhí)行頁(yè)面時(shí)設(shè)置該屬性。然而,用戶可能單擊瀏覽器的后退按鈕。作為該操作的結(jié)果,在瀏覽器中看到的當(dāng)前步驟將與 currentStep 屬性的值不符,因?yàn)闉g覽器將從其緩存中檢索到頁(yè)面,而不是請(qǐng)求執(zhí)行 JSF 頁(yè)面。

    如果每一次用戶單擊按鈕時(shí) currentStep 值都與表單數(shù)據(jù)一起提交,則不會(huì)導(dǎo)致任何問(wèn)題。hiddenData.tag 文件將 currentStep 作為一個(gè)隱藏字段包含在內(nèi)。此外,如果 currentStep 等于 maxStep(這意味著標(biāo)記在確認(rèn)頁(yè)面中使用),那么該標(biāo)記文件將為所有 Bean 屬性生成隱藏字段:
    <!-- hiddenData.tag -->
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
    
    <h:inputHidden id="currentStep" value="#{wizard.currentStep}"/>
    
    <c:if test="${wizard.currentStep == wizard.maxStep}">
    <h:inputHidden id="h_connName" value="#{wizard.connName}"/>
    <h:inputHidden id="h_connType" value="#{wizard.connType}"/>
    <h:inputHidden id="h_userName" value="#{wizard.userName}"/>
    <h:inputHidden id="h_password" value="#{wizard.password}"/>
    <h:inputHidden id="h_role" value="#{wizard.role}"/>
    <h:inputHidden id="h_driver" value="#{wizard.driver}"/>
    <h:inputHidden id="h_hostName" value="#{wizard.hostName}"/>
    <h:inputHidden id="h_sid" value="#{wizard.sid}"/>
    <h:inputHidden id="h_jdbcPort" value="#{wizard.jdbcPort}"/>
    </c:if>
    
    所有的向?qū)Р糠侄伎梢栽?JSF 頁(yè)面中組裝,如 step1.jsp:
    <!-- step1.jsp -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <tags:pageTemplate step="1" 
    title="Create Database Connection - Step 1">
    <af:form id="form1">
    <tags:formTemplate>
    <tags:form1/>
    </tags:formTemplate>
    <tags:stepButtons/>
    <tags:hiddenData/>
    </af:form>
    </tags:pageTemplate>
    
    step2.jsp 和 step3.jsp 頁(yè)面與 step1.jsp 非常類似。作為練習(xí),您可以嘗試為這些頁(yè)面構(gòu)建一個(gè)模板,從而將這些頁(yè)面都減少為四行代碼。confirm.jsp 頁(yè)面將一起顯示所有三個(gè)表單,但組件在只讀模式下工作,從而占用的屏幕空間更少并且無(wú)需用戶交互:
    <!-- confirm.jsp -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <tags:pageTemplate step="4" title="Confirm Connection Parameters">
    <af:form id="form4">
    <tags:formTemplate>
    <tags:form1/>
    <tags:form2/>
    <tags:form3/>
    </tags:formTemplate>
    <tags:stepButtons/>
    <tags:hiddenData/>
    </af:form>
    </tags:pageTemplate>
    
    基于菜單的界面。假定用戶逐步瀏覽向?qū)У捻?yè)面,提供所有需要的信息。如果用戶需要在以后修改某些地方,那么他應(yīng)當(dāng)不需要再次瀏覽所有的向?qū)ы?yè)面。相反,用戶界面將讓用戶直接轉(zhuǎn)至必須修改信息的表單。menuTabs.tag 文件使用相同名稱的 Oracle ADF Faces 組件來(lái)構(gòu)建菜單:
    <!-- menuTabs.tag -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:menuTabs>
    <af:commandMenuItem text="Name and Type" action="tab1"
    selected="#{wizard.currentStep == 1}"/>
    <af:commandMenuItem text="Authentication" action="tab2"
    selected="#{wizard.currentStep == 2}"/>
    <af:commandMenuItem text="Connection" action="tab3"
    selected="#{wizard.currentStep == 3}"/>
    </af:menuTabs>
    
    菜單的導(dǎo)航規(guī)則在 faces-config.xml 中定義:
    <faces-config>
        ...
    <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
    <from-outcome>tab1</from-outcome>
    <to-view-id>/tab1.jsp</to-view-id>
    </navigation-case>
    </navigation-rule>
        ...
    <navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
    <from-outcome>tab3</from-outcome>
    <to-view-id>/tab3.jsp</to-view-id>
    </navigation-case>
    </navigation-rule>
        ...
    </faces-config>
    
    當(dāng)用戶單擊菜單的標(biāo)簽時(shí),表單數(shù)據(jù)將被提交給 Web 服務(wù)器,在該服務(wù)器上 JSF 框架將更新 Backing Bean。如果用戶想更新表單而不改變當(dāng)前的標(biāo)簽,那么需要使用提交按鈕。submitButton.tag 文件提供了提交按鈕:
    <!-- submitButton.tag -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    
    <af:commandButton id="command" text="Submit" action="submitAction"/>
    
    tab1.jsp、tab2.jsp 和 tab3.jsp 文件將把菜單附加到向?qū)У谋韱紊稀O旅媸?tab1.jsp:
    <!-- tab1.jsp -->
    
    <%@ taglib prefix="af" uri="http://xmlns.oracle.com/adf/faces" %>
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <tags:pageTemplate step="1" title="Edit Database Connection">
    <af:form id="form1">
    <tags:menuTabs/>
    <tags:formTemplate>
    <tags:form1/>
    </tags:formTemplate>
    <tags:submitButton/>
    <tags:hiddenData/>
    </af:form>
    </tags:pageTemplate>
    
    使顯示邏輯可重用

    如果您必須使用 JSF 和 Oracle ADF Faces 從頭開(kāi)始構(gòu)建新的頁(yè)面,那么一切都沒(méi)什么問(wèn)題。但是,對(duì)于包含了以 Java 代碼形式存在的顯示邏輯的舊 JSP 頁(yè)面,該如何處理呢?維護(hù)這些頁(yè)面困難重重,并且,若不將顯示代碼從 JSP 頁(yè)面中分離出來(lái),則無(wú)法對(duì)其進(jìn)行重用。此外,Java 代碼和 HTML 標(biāo)記不應(yīng)混合在同一個(gè)頁(yè)面中,因?yàn)檫@將使 Java 開(kāi)發(fā)人員和 Web 設(shè)計(jì)人員無(wú)法輕松地展開(kāi)并行工作。

    JSF 和 Oracle ADF Faces 組件解決了多數(shù)情況下的此種問(wèn)題,因?yàn)?Web 頁(yè)面將使用這兩個(gè)框架提供的標(biāo)記來(lái)構(gòu)建,同時(shí)將 Java 代碼放到了 Backing Bean 中。JSTL 和其他的標(biāo)記庫(kù)也非常有用,但有時(shí)您必須只能使用 Java 代碼來(lái)動(dòng)態(tài)生成內(nèi)容。

    一種好的解決方案是使用 JSP 2.0 提供的 Simple Tags API 來(lái)構(gòu)建標(biāo)記庫(kù)。該 API 使您能夠開(kāi)發(fā)標(biāo)記處理器類,但您必須維護(hù)一個(gè)單獨(dú)的 XML 文件(稱為標(biāo)記庫(kù)描述符 (TLD)),該文件定義標(biāo)記名稱、它們的屬性等。如果這聽(tīng)起來(lái)太復(fù)雜,那么您可以簡(jiǎn)單地將 Java 代碼移到使用 JSP 語(yǔ)法的標(biāo)記文件中,讓?xiě)?yīng)用服務(wù)器生成標(biāo)記處理器類和 TLD 文件。讓我們看一下名為 oldCode.jsp 的 JSP 頁(yè)面,它混合了 Java 和 HTML。該頁(yè)面將讀取一個(gè)文本文件(其路徑將作為一個(gè)請(qǐng)求參數(shù)提供)并顯示文件的內(nèi)容(包括行號(hào))。當(dāng)您構(gòu)建演示應(yīng)用程序并想顯示代碼時(shí),這將非常有用。

    重要注意事項(xiàng)!請(qǐng)勿在生產(chǎn)環(huán)境中使用本部分的示例(oldCode.jsp 和 newCode.jsp),因?yàn)樗鼈兛赡軙?huì)泄漏應(yīng)用程序的源代碼。

    oldCode.jsp 頁(yè)面使用 java.io API 來(lái)讀取文本文件。它將在 JSP 頁(yè)面范圍中為每一行文本創(chuàng)建兩個(gè)名為 lineTextlineNo 的變量。行號(hào)將用 JSTL 的 <fmt:formatNumber> 標(biāo)記來(lái)進(jìn)行格式化,文本將通過(guò) <c:out> 標(biāo)記進(jìn)行顯示:
    <!-- oldCode.jsp -->
    
    <%@ page import="java.io.*" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    
    <HTML>
    <HEAD>
    <TITLE>${param.path}</TITLE>
    </HEAD>
    <BODY>
    
    <c:if test="${empty param.path}">
    <P>The <CODE>path</CODE> parameter wasn't specified.
    </c:if>
    
    <c:if test="${!empty param.path}">
    <P><B><CODE>${param.path}</CODE></B>
    <%
    String path = application.getRealPath(
    request.getParameter("path"));
    BufferedReader in = new BufferedReader(new FileReader(path));
    try {
    int lineNo = 0;
    String lineText;
    while ((lineText = in.readLine()) != null) {
    lineNo++;
    pageContext.setAttribute("lineText", lineText);
    pageContext.setAttribute("lineNo",
    new Integer(lineNo));
    %>
    <fmt:formatNumber var="fmtLineNo"
    value="${lineNo}" minIntegerDigits="3"/>
    <PRE>${fmtLineNo}  <c:out value="${lineText}"/></PRE>
    <%
            }
    } finally {
    in.close();
        }
    %>
    </c:if>
    
    </BODY>
    </HTML>
    
    來(lái)自前一個(gè)頁(yè)面示例的全部 Java 代碼都可以移到一個(gè)名為 readTextFile.tag 的標(biāo)記文件中。只需進(jìn)行少許修改:您必須使用 <%@tag%> 指令和 jspContext 隱式對(duì)象,而不是 <%@page%> 和 pageContext。您還必須使用 JSP 指令來(lái)聲明屬性和變量:
    <!-- readTextFile.tag -->
    
    <%@ tag import="java.io.*" %>
    <%@ attribute name="path" required="true" %>
    <%@ variable name-given="lineText" scope="NESTED" %>
    <%@ variable name-given="lineNo" scope="NESTED" %>
    <%
    String path = application.getRealPath(
    (String) jspContext.getAttribute("path"));
    BufferedReader in = new BufferedReader(new FileReader(path));
    try {
    int lineNo = 0;
    String lineText;
    while ((lineText = in.readLine()) != null) {
    lineNo++;
    jspContext.setAttribute("lineText", lineText);
    jspContext.setAttribute("lineNo",
    new Integer(lineNo));
    %>
    <jsp:doBody/>
    <%
            }
    } finally {
    in.close();
        }
    %>
    
    您可以在任何需要逐行處理文本文件的 JSP 頁(yè)面中使用 readTextFile.tag 文件。每一個(gè)頁(yè)面都可以對(duì)文本行執(zhí)行任何需要的操作,因?yàn)樵摌?biāo)記文件使用了 <jsp:doBody/>,從而允許 JSP 頁(yè)面將處理當(dāng)前行的代碼放到 <tags:readTextFile></tags:readTextFile> 之間。newCode.jsp 頁(yè)面的功能與舊樣式的示例相同,但它沒(méi)有混合 Java 和 HTML:
    <!-- newCode.jsp -->
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
    <%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
    
    <HTML>
    <HEAD>
    <TITLE>${param.path}</TITLE>
    </HEAD>
    <BODY>
    
    <c:if test="${empty param.path}">
    <P>The <CODE>path</CODE> parameter wasn't specified.
    </c:if>
    
    <c:if test="${!empty param.path}">
    <P><B><CODE>${param.path}</CODE></B>
    <tags:readTextFile path="${param.path}">
    <fmt:formatNumber var="fmtLineNo"
    value="${lineNo}" minIntegerDigits="3"/>
    <PRE>${fmtLineNo}  <c:out value="${lineText}"/></PRE>
    </tags:readTextFile>
    </c:if>
    
    </BODY>
    </HTML>
    
    正如您所見(jiàn),修改舊的 JSP 頁(yè)面以便可以重用代碼并不是很難。維護(hù)也變得更加容易。

    隨意重用

    重復(fù)的代碼或內(nèi)容是最令人頭疼的事情。有時(shí)它可能是一種容易的解決方案,但修改應(yīng)用程序變得更加困難,這意味著從長(zhǎng)遠(yuǎn)來(lái)看,您將不能適應(yīng)新的用戶需求或快速地修復(fù)問(wèn)題。在理想情況下,應(yīng)用程序不應(yīng)包含相同代碼的多個(gè)版本,Web 內(nèi)容不應(yīng)被復(fù)制和粘貼。
    posted on 2006-05-10 14:53 KingWell 閱讀(381) 評(píng)論(0)  編輯  收藏 所屬分類: Java Server Faces

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    歡迎訪問(wèn)我的網(wǎng)站
    JSF中國(guó)

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(1)

    隨筆檔案

    文章分類

    文章檔案

    收藏夾

    我的資源

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 免费无遮挡无码视频在线观看| 色播在线永久免费视频| 免费国产高清毛不卡片基地| 亚洲国产精品第一区二区| 免费A级毛片无码A| 免费无码黄十八禁网站在线观看| 国产午夜不卡AV免费| 九九免费久久这里有精品23| 亚洲人成网站999久久久综合| 亚洲伦另类中文字幕| 亚洲精品中文字幕乱码三区 | 亚洲高清资源在线观看| 日韩亚洲变态另类中文| 国产伦一区二区三区免费| 国产免费av片在线看| 1000部免费啪啪十八未年禁止观看 | 美女扒开屁股让男人桶爽免费 | 亚洲一级免费视频| 91视频精品全国免费观看| 免费无码一区二区| 国产亚洲精品第一综合| 狼人大香伊蕉国产WWW亚洲 | 国产精品深夜福利免费观看| 一本无码人妻在中文字幕免费| 亚洲黄色免费电影| 18禁美女裸体免费网站| 久久午夜夜伦鲁鲁片免费无码| 女同免费毛片在线播放| 国产性生大片免费观看性| 国产精品永久免费视频| CAOPORM国产精品视频免费| 男人和女人高潮免费网站| 老司机午夜精品视频在线观看免费| 亚洲爆乳成av人在线视菜奈实| 亚洲色偷偷色噜噜狠狠99| 亚洲色偷偷偷综合网| 亚洲av成人一区二区三区在线播放 | 国产成年无码久久久免费| 美女视频黄的免费视频网页| 国产精品白浆在线观看免费| 久久午夜羞羞影院免费观看|