首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Facelets 非常适合 JSF(3)

Facelets 非常适合 JSF(3)

使用 Facelets 模板为了调用模板,要使用 ui:composition 标记。为了把参数传递给模板,要使用 ui:define 标记,它是 ui:composition 标记的子元素。在清单 2 中,我调用了在线 CD 商店示例的布局页面:
清单 2. 调用布局页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
<ui:composition template="/WEB-INF/layout/layout.xhtml">
  <ui:define name="title">CD form</ui:define>
  <ui:define name="content">
    <!-- use the form tag to set up this form -->
    <h:form id="cdForm">
        ...
        ...
...
    </h:form>
  </ui:define>
</ui:composition>
</html>




请注意在上面的调用中包含了以下命名空间:
  • xmlns:h="http://java.sun.com/jsf/html"
  • xmlns:f="http://java.sun.com/jsf/core"
有了 Facelets,就不必依赖 JSF 标记库,所以要使用核心和 HTML JSF 组件,必须通过以上命名空间导入它们。
html 标记的使用看起来可能有些奇怪。毕竟,清单 2 所示的布局页面要调用的模板已经有了一个 html 标记;所以这是不是意味着会得到两个 html 标记?如果真的这样,那么在 ui:composition 标记之外的内容全部被忽略,所以 html 标记所做的只是让 HTML 编辑器能够看到 HTML 片段。它不会影响运行时行为。
位置是一切当页面调用布局模板时,只需指定模板的位置,如下所示:
1
<ui:composition template="/WEB-INF/layout/layout.xhtml">




这个标记调用清单 1 所示的模板,所以我要做的全部工作就是把参数传递给模板。然后,在复合标记内部,可以传递像标题这样的简单文本:
1
<ui:define name="title">CD form</ui:define>




或者传递整个组件树:
1
2
3
4
5
6
7
8
  <ui:define name="content">
    <!-- use the form tag to setup this form -->
    <h:form id="cdForm">
        ...
        ...
...
    </h:form>
  </ui:define>




请注意,在我定义和传递的许多逻辑区域中,cdForm.xhtml 只传递两个:内容和标题。
Tiles 与 Facelets这篇文章带了三个示例:第一个使用 Tiles,第二个使用 Facelets,第三个使用复合组件。之所以包含 Tiles 示例是为了可以比较和对比两个框架中不同的模板化技术。请看看它,并看看自己有什么想法!

复合组件如果只用 Facelets 定义和使用模板,那么可能会有点失败。虽然 Facelets 的模板化特性完整而且丰富,但是它没有 Tiles 之类的框架那么多的特性,后者还擅长定义默认值、相关模板的层次结构以及类似的东西。
但模板化不是 Facelets 真正出色的地方:Facelets 把它的精华放在复合组件上。(有趣的是,复合组件也给 Facelets 模板化带来了一些好处;例如,在 Facelets 中可以舍弃 f:verbatim 标记和各种 hutputText 标记,因为所有的东西都被当成组件树中的组件。关于这方面的更多内容稍后介绍。)
对于这篇文章余下的部分,我将重点放在创建和使用复合组件的步骤上。但在开始之前,先要确保能够清楚地理解是什么让这些方便的小代码段这么棒。
破坏 DRY 原则您是否曾经编写过像清单 3 所示的代码片段?
清单 3. 复合组件之前的生活
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<h:dataTable id="items" value="#{CDManagerBean.cds}" var="cd"
    rowClasses="oddRow, evenRow" headerClass="tableHeader">
<!--  Title -->
<h:column>
    <f:facet name="header">
        <h:panelGroup>
            <hutputText value="Title" />
                 
                 <f:verbatim>[</f:verbatim>
            <h:commandLink styleClass="smallLink"
                              action="#{CDManagerBean.sort}">
                <hutputText id="ascTitle" value="asc" />
                <f:param name="by" value="title"/>
                <f:param name="order" value="asc"/>
            </h:commandLink>
            <hutputText value="," />
            <!-- Sort descending -->
            <h:commandLink styleClass="smallLink"
                         action="#{CDManagerBean.sort}">
                <hutputText id="decTitle" value="dec" />
                <f:param name="by" value="title"/>
                <f:param name="order" value="dec"/>
            </h:commandLink>
                 <f:verbatim>]</f:verbatim>
        </h:panelGroup>
    </f:facet>
    <hutputText value="#{cd.title}" />
</h:column>
<!--  Artist -->
<h:column>
    <f:facet name="header">
        <h:panelGroup>
            <hutputText value="Artist" />
               <f:verbatim>[</f:verbatim>
              <h:commandLink styleClass="smallLink"
                           action="#{CDManagerBean.sort}">
                 <hutputText id="ascArtist" value="asc" />
                <f:param name="by" value="artist"/>
                <f:param name="order" value="asc"/>
               </h:commandLink>
            <hutputText value="," />
                    <!-- Sort descending -->
            <h:commandLink styleClass="smallLink"
                           action="#{CDManagerBean.sort}">
                <hutputText id="decArtist" value="dec" />
                <f:param name="by" value="artist"/>
                <f:param name="order" value="dec"/>
            </h:commandLink>
                 <f:verbatim>]</f:verbatim>
        </h:panelGroup>
    </f:facet>
    <h:outputText value="#{cd.artist}" />
</h:column>




这段来自 listing.xhtml 的代码为示例应用程序的清单页面生成列标题和升序/降序排列链接。请注意,必须在多个地方重复代码,才能输出多列。(在上面的示例中您还会注意到,我在 ${..} 和 #{..} 之间切换;这可能让人迷惑,但它们做的是同样的事!)
所有这些渲染标题列和艺术家列的重复代码都破坏了 DRY 原则 —— 即,不要重复自己。那么您说,这里错在哪儿呢?假设在清单中平均有 5 列,应用程序中有 20 个不同的清单。使用清单 3 的方法,就不得不重复这 35 行代码 100 次,合计 3,500 行代码!维护所有这些代码会是种痛苦,但是如果决定修改清单的表示或添加一种通用的清单过滤方式,会怎么样?需要更多、更多的工作。
现在拿清单 3 和这个代码比较:
清单 4. 创建字段的新方式
1
2
3
4
5
<h:dataTable id="items" value="#{CDManagerBean.cds}" var="cd"
        rowClasses="oddRow, evenRow" headerClass="tableHeader">
            
<a:column entity="${cd}" fieldName="title" backingBean="${CDManagerBean}"/>
<a:column entity="${cd}" fieldName="artist" backingBean="${CDManagerBean}"/>




看起来好像我只用 4 行代码就替代了 70 行或更多行代码!可以猜出,a:column 是个复合组件。在 Facelets 中,可以容易地定义这样的组件,如清单 5 所示:
清单 5. column.xhtml 渲染带有排序链接的列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:z="http://www.qualcomm.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fn="http://java.sun.com/jsp/jstl/functions">
THIS TEXT WILL BE REMOVED
<ui:composition>
    <!--  The label attribute is optional. Generate it if it is missing. -->
    <c:if test="${empty label}">
        <c:set var="label" value="${fieldName}" />
    </c:if>
    <!--  The sort attribute is optional. Set it to true if it is missing. -->
    <c:if test="${empty sort}">
        <c:set var="sort" value="${true}" />
    </c:if>
    <h:column>
      <f:facet name="header">
        <h:panelGroup>
          ${label}
          <c:if test="${sort}">
              [
            <h:commandLink styleClass="smallLink"
          action="#{backingBean.sort}">
              <h:outputText value="asc" />
              <f:param name="by"
              value="${fieldName}"/>
              <f:param name="order" value="asc"/>
            </h:commandLink>
                    ,
            <!-- Sort descending -->
            <h:commandLink styleClass="smallLink"
              action="#{backingBean.sort}">  
              <h:outputText value="asc" />
              <f:param name="by"               
              value="${fieldName}"/>
              <f:param name="order" value="dec"/>
            </h:commandLink>
                    ]
          </c:if>         
        </h:panelGroup>
      </f:facet>
      <!--  Display the field name -->
      <h:outputText value="${entity[fieldName]}"/>
        </h:column>
</ui:composition>
THIS TEXT WILL BE REMOVED AS WELL
</html>

返回列表