读书人

JSF 二 简介第 2 部分: 模板及复合组

发布时间: 2012-10-31 14:37:31 作者: rapoo

JSF 2 简介,第 2 部分: 模板及复合组件

(转自: http://www.ibm.com/developerworks/cn/java/j-jsf2fu2/)

?

2009 年 6 月 25 日

模板和复合组件是 Java?Server Faces (JSF) 2 的两个功能强大的特性,借助这两个特性,您就可以实现易于修改和扩展的用户界面。在本文 — 共三部分的JSF 二 简介,第 2 部分: 模板及复合组件Facelets 和 JSF 2

在标准化开源 Facelets 实现的同时,JSF 2 专家组还对底层的 Facelets API 进行了更改,但保留了与标记库的后向兼容性。这意味着用开源 Facelets 所实现的现有视图均应适用于 JSF 2。

在 Rick Hightower 的这两篇文章 “Facelets 非常适合 JSF技巧 1:遵守 DRY 原则

在我作为软件开发人员从事的第一项工作中,我的任务是为基于 UNIX? 的计算机辅助设计和计算机辅助制造(CAD/CAM)系统实现一个 GUI。

最初,一切进行顺利,但是一段时间后,我的代码开始问题不断。待到代码发布的时候,系统已经相当脆弱,我甚至都害怕修复 bug,而这次的代码发布自然也伴随着一连串的 bug 报告。

如果我在这个项目中遵循了 DRY 原则 — 不重复自己—on't Repeat Yourself),我本可以让自己不至于这么悲惨。DRY 原则最初由 Dave Thomas 和 Andy Huntprinciple 提出(参见JSF 2 模板

JSF 2 在很多方面都支持 DRY 原则,其中之一就是通过模板。模板能够封装在应用程序视图中十分常见的功能,因此该功能只需被指定一次。在 JSF 2 应用程序中,一个模板可供多个组装(compositions)用于创建视图。

我在JSF 二 简介,第 2 部分: 模板及复合组件JSF 二 简介,第 2 部分: 模板及复合组件

与很多 Web 应用程序一样,这个 places 应用程序包含多个具有相同布局的视图。JSF 模板功能让您能够在一个模板内封装该布局 — 及其他共享工件,比如 JavaScript 和 Cascading Style Sheets(CSS)。清单 1 是

ui:insert name="windowTitle">        #{msgs.placesWindowTitle}      </ui:insert>    </title>   </h:head>    <h:body>      <h:outputScript library="javascript" name="util.js" target="head"/>          <h:outputStylesheet library="css" name="styles.css" target="body"/>            <div style="font-size: 11px; font-weight: bold;">ui:insert name="heading">        #{msgs.placesHeading}      </ui:insert>         </div>           <div style="font-size: 11px; font-weight: bold;">ui:insert name="menuLeft"/>      </div>              <div style="display: #{places.showContent}">        <ui:insert name="content"/>      </div>           <div style="font-size: 11px; font-weight: bold;">ui:insert name="menuRight">          <ui:include src="/sections/shared/sourceViewer.xhtml"/>        </ui:insert>      </div>     </div>    </h:body> </html>

清单 1

template="/templates/masterLayout.xhtml">     <ui:define name="menuLeft">    <ui:include src="/sections/login/menuLeft.xhtml"/>  </ui:define>  <ui:define name="content">     <ui:include src="/sections/login/content.xhtml"/>             </ui:define>     </ui:composition>

这个 login 视图为窗口的标题、头和右菜单使用了模板的默认内容。它只定义了特定于此 login 视图的功能:内容部分和左菜单。

通过为窗口标题、头或右菜单提供

template="/templates/masterLayout.xhtml">  <ui:define name="content">    <ui:include src="/sections/showSource/content.xhtml"/>  </ui:define>  <ui:define name="menuLeft">    <ui:include src="/sections/showSource/menuLeft.xhtml"/>        </ui:define>       <ui:define name="menuRight">    <ui:include src="/sections/showSource/menuRight.xhtml"/>        </ui:define></ui:composition>    

source-viewer 视图定义了内容部分以及右菜单的内容。它还覆盖了由

template="/templates/masterLayout.xhtml">   <ui:define name="menuLeft">    <ui:include src="/sections/places/menuLeft.xhtml"/>   </ui:define>  <ui:define name="content">    <ui:include src="/sections/places/content.xhtml"/>  </ui:define></ui:composition>    

JSF 二 简介,第 2 部分: 模板及复合组件JSF 2 模板功能

模板功能背后的概念十分简单。定义一个模板来封装在多个视图中常见的功能。每个视图由一个组装和一个模板组成。

当 JSF 创建视图时,它加载组装的模板,然后将由组装所定义的内容插入模板。

请注意清单
JSF 二 简介,第 2 部分: 模板及复合组件
JSF 二 简介,第 2 部分: 模板及复合组件
回页首

技巧 2:使用组合的方式

在我的 CAD/CAM GUI 发布后不久,我花了几个月的时间与另一位开发人员 Bob 致力于一个新的项目。我们以 Bob 的代码为基础,而且不可思议地是,我们还能轻松进行更改并修复 bug。

我很快意识到 Bob 的代码和我的代码之间的最大区别是他编写了

清单 5 显示了定义该菜单内容的文件:


清单 5. login 视图左菜单的实现

清单 5

places 视图的左菜单的实现如清单 6 所示:


清单 6. places 视图的左菜单的实现

清单 6

addressForm.xhtml">    <ui:include src="logoutIcon.xhtml">  </div>    </ui:composition>

清单 9 显示了 addressForm.xhtml:


清单 9. addressForm.xhtml

清单 10 显示了 logoutIcon.xhtml:


清单 10. logoutIcon.xhtml

JSF 二 简介,第 2 部分: 模板及复合组件
JSF 二 简介,第 2 部分: 模板及复合组件
回页首

技巧 3:牢记 LEGO 拼装玩具的理念

在我还是一个男孩的时候,我有两个最喜欢的玩具:一个是化学组合(chemistry set),一个是 LEGO 拼装玩具。这两种玩具让我能够通过组合基本的构建块来创建东西,而这也成为了我一生的爱好,只不过现在是打着软件开发的幌子。

JSF 的优势一直都在于其组件模型,但这种优势直到现在才完全实现,因为用 JSF 1 很难实现定制组件。您必须要编写 Java 代码、指定 XML 配置,并对 JSF 的生命周期有深刻的理解。有了 JSF 2,您就能够轻松实现定制组件:

    无需配置、XML 或其他。无需 Java 代码。开发人员可以向其附加功能。修改后执行热部署。

    在本文的剩余部分,我将向您介绍如何为 places 应用程序实现三个定制组件:一个图标、一个 login 面板和一个显示了地址地图和天气信息的面板。但是首先,让我先来概括介绍一下 JSF 2 复合组件。

    实现定制组件

    JSF 2 综合了

    要使用复合组件,需要声明一个名称空间并使用标记。此名称空间通常为

    /component/util">  ...  <util:login.../>  ...<html>

    而要使用

    /components/util">  ...  <util:icon.../>  ...<html>

    最后,若要使用 place 组件,则可按如下所示的这样做:

    /components/places">  ...  <places:place.../>  ...<html>

    icon

    每个图标都是一个链接。当用户单击

    actionMethod="#{sourceViewer.showSource}"                       image="#{resource['images:disk-icon.jpg']}"/>  ...</html>

    清单 12 给出了如何使用

    actionMethod="#{places.logout}"                       image="#{resource['images:back-arrow.jpg']}"/>  ...</html>

    清单 13 给出了

    composite:interface>    <composite:attribute name="image"/>    <composite:attribute name="actionMethod"              method-signature="java.lang.String action()"/>          </composite:interface>  <!-- IMPLEMENTATION -->              <composite:implementation>    <h:form>        <h:commandLink action="#{cc.attrs.actionMethod}" immediate="true">      <h:graphicImage value="#{cc.attrs.image}"                styleClass="icon"/>      </h:commandLink>    </h:form>  </composite:implementation></html>

    与其他复合组件类似,清单 13

    name="styleClass" default="icon" required="false"/>      ...    </composite:interface>    <composite:implementation>      ...      <h:graphicImage value="#{cc.attrs.image}"                 stylestyle="font-size: 11px; font-weight: bold;">#{cc.attrs.styleClass}"/>      ...    </composite:implementation></html>


    如果不能指定login

    清单 15 显示了这个 places 应用程序是如何使用

    component/util">  <util:login loginPrompt="#{msgs.loginPrompt}"                namePrompt="#{msgs.namePrompt}"            passwordPrompt="#{msgs.passwordPrompt}"               loginAction="#{user.login}"           loginButtonText="#{msgs.loginButtonText}"               managedBean="#{user}">                     <f:actionListener for="loginButton"                         type="com.clarity.LoginActionListener"/>                              </util:login>  ...</html>

    清单 15

    <composite:actionSource name="loginButton" targets="form:loginButton"/>    <composite:attribute name="loginButtonText" default="Log In" required="true"/>    <composite:attribute name="loginPrompt"/>    <composite:attribute name="namePrompt"/>    <composite:attribute name="passwordPrompt"/>    <composite:attribute name="loginAction"       method-signature="java.lang.String action()"/>    <composite:attribute name="managedBean"/>  </composite:interface>      <!-- IMPLEMENTATION -->  <composite:implementation>   <h:form id="form" prependId="false">     <div value="#{cc.attrs.managedBean.name}"/>       #{cc.attrs.passwordPrompt}        <h:inputSecret id="password" value="#{cc.attrs.managedBean.password}" />     </panelGrid>     <p>       <h:commandButton id="loginButton"                     value="#{cc.attrs.loginButtonText}"                     action="#{cc.attrs.logi 

读书人网 >JavaScript

热点推荐