`
yingfang05
  • 浏览: 122903 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

Facelets是JSF更好的外衣

    博客分类:
  • jsf
阅读更多
是由 Sun 公司在 dev.java.net 上的一个开源项目,其主页为:facelets.dev.java.net。为什么说 Facelets 更适合JSF?笔者认为,主要是基于以下特性:
Facelets基于xml,它是组件树更自然的一种描述方式(xml天生就是一种树形结构描述语言)。

Facelets的模版技术,使它更适合网页开发

Facelets支持复合组件,并且,组件的定义方式更简单

Facelets的 jsfc 技术对 html 设计器更友好

与JSP相比,Facelets无需运行前编译,并且,Facelets 还适合对生成的组件树做cache,从而使运行期更轻量,效率更高

以下对Facelets的模版及复合组件技术做一个简单介绍。

首先,我们举一个场景:假设我们现在要做一个向导,该向导包含两个页面,分别是录入用户的姓名和其它信息.

暂且不考虑 Facelets,这两个页面的代码分别如下:

dialog1.xhtml:

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html">
  <w:page title="Dialog" style="font-family: Verdana; font-size: 10pt; margin: 0px; padding: 0px">
    <w:form>
    <layout:panelGrid columns="2" width="100%" style="padding-left: 20px">
      <layout:cell colspan="1" rowspan="1" width="99%">
        <div style="font-size: 11pt; font-weight: bold;">Input Name</div>
      </layout:cell>
      <layout:cell colspan="1" rowspan="2" style="align: right">
        <img src="images/wizard.gif" />
      </layout:cell>
      <layout:cell colspan="1" rowspan="2">
        <div style="font-size: 10pt; font-weight: normal;">Please input your name</div>
      </layout:cell>
    </layout:panelGrid>
    <w:separator />
    <layout:panelGrid columns="2" style="height: 250px">
      <layout:cell style="vertical-align: top">
        <h:outputLabel value="Name:"/>
      </layout:cell>
      <layout:cell style="vertical-align: top">
        <w:textField id="name" width="250"/>
      </layout:cell>
    </layout:panelGrid>
    <w:separator />
    <layout:panelGrid columns="5" style="align: right" width="100%">
      <layout:cell style="width: 90%"> </layout:cell>
      <w:button value="Back"/>
      <w:button value="Next"/>
      <w:button value="Finished"/>
      <w:button value="Cancel"/>
    </layout:panelGrid>
    </w:form>
  </w:page>
</f:view>
dialog2.xhtml

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html">
  <w:page title="Dialog" style="font-family: Verdana; font-size: 10pt; margin: 0px; padding: 0px">
    <w:form>
    <layout:panelGrid columns="2" width="100%" style="padding-left: 20px">
      <layout:cell colspan="1" rowspan="1" width="99%">
        <div style="font-size: 11pt; font-weight: bold;">Input Others</div>
      </layout:cell>
      <layout:cell colspan="1" rowspan="2" style="align: right">
        <img src="images/wizard.gif" />
      </layout:cell>
      <layout:cell colspan="1" rowspan="2">
        <div style="font-size: 10pt; font-weight: normal;">Please input your others information</div>
      </layout:cell>
    </layout:panelGrid>
    <w:separator />
    <layout:panelGrid columns="2" style="height: 250px">
      <layout:cell style="vertical-align: top">
        <h:outputLabel value="Others:"/>
      </layout:cell>
     <layout:cell style="vertical-align: top">
       <w:combo id="others" width="250"/>
     </layout:cell>
    </layout:panelGrid>
  <w:separator />
  <layout:panelGrid columns="5" style="align: right" width="100%">
    <layout:cell style="width: 90%"> </layout:cell>
      <w:button value="Back"/>
      <w:button value="Next"/>
      <w:button value="Finished"/>
      <w:button value="Cancel"/>
    </layout:panelGrid>
    </w:form>
  </w:page>
</f:view>
首先非常抱歉的是,笔者对HTML/CSS并不是很懂,因此,上述的代码示例有许多可以改进的地方。但无庸置疑的是: 上述两个页面有太多的重复性代码。如果我们用纯粹的JSP/Servlet技术来开发此应用,可以用 Tiles 来消除这种重复;如果用 AOM 来开发,则可以通过 Facelets 来达到同样的目的。

模版技术
针对上述示例,我们首先定义一个模版文件dialog_template.xhtml。

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  renderKitId="AJAX" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
  <w:page title="Dialog" style="font-family: Verdana; font-size: 10pt; margin: 0px; padding: 0px"> 
    <layout:panelGrid columns="2" width="100%" style="padding-left: 20px">
      <layout:cell colspan="1" rowspan="1" width="99%">
        <div style="font-size: 11pt; font-weight: bold;">         
            <ui:insert name="title">default title</ui:insert>
        </div>
      </layout:cell>
      <layout:cell colspan="1" rowspan="2" style="align: right">
        <img src="images/wizard.gif" />
      </layout:cell>
      <layout:cell colspan="1" rowspan="2">
        <div style="font-size: 10pt; font-weight: normal;">
            <ui:insert name="description">default description</ui:insert>
        </div>
      </layout:cell>
    </layout:panelGrid>
    <w:separator />
<ui:insert name="content">empty content</ui:insert>
    <w:separator />
    <layout:panelGrid columns="5" style="align: right" width="100%">
      <layout:cell style="width: 90%"></layout:cell>
      <w:button value="Back" />
      <w:button value="Next" />
      <w:button value="Finished" />
      <w:button value="Cancel" />
    </layout:panelGrid>
  </w:page>
</f:view>
请注意,我们在上述模版文件中,分别插入三个<ui:insert/>标记,每个标记都有一个name属性,其值分别是:title、description、content。 这三个标记,本质上就相当于定义了三个“锚点”,至于具体的内容,随时可以替换。

现在,我们再来看看 dialog1 应该怎么使用这个模版。

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  xmlns:h="http://java.sun.com/jsf/html"  xmlns:ui="http://java.sun.com/jsf/facelets">
   This text should be skiped.
<ui:composition template="/dialog_template.xhtml">
   This text should be skiped too.
<ui:define name="title">Input Name</ui:define>
<ui:define name="description">Please input your name</ui:define>

<ui:define name="content">
      <layout:panelGrid columns="2" style="height: 250px">
        <layout:cell style="vertical-align: top">
          <h:outputLabel value="Name:" />
        </layout:cell>
        <layout:cell style="vertical-align: top">
          <w:textField id="name" width="250" />
        </layout:cell>
      </layout:panelGrid>
    </ui:define>
  </ui:composition>
</html>
我们可以观察:首先,<ui:composition>指定使用哪个模版文件,然后通过<ui:define>对模版文件中每个可供插入的“<ui:insert>锚点”进行定义。在 上述的dialog1.xhtml文件中,我们针对模版文件(dialog_template.xhtml)的三个锚点,分别定义了相应的具体内容。在运行期,这些具体的内容, 将会被插入到模版文件中定义的锚点位置。 这里需要提醒注意的是:<ui:composition>标记和<ui:define>标记以外的所有内容都会被忽略,并且,最外面的<html>标记, 只是为了定义一个根元素,以便在这个根元素中声明命名空间,至于你是用<html>还是<f:view>,甚至是其它的乱七八糟的 标记,如<abcde>等等,其实都无所谓。笔者建议各位同学使用<html>作为根元素,一是因为<html>所属的命名空间已经被声明过了(xmlns="http://www.w3.org/1999/xhtml"), 二是因为它对设计器更友好(哪个网页设计器不认识<html/>标记呢?)。

Facelets的相关知识毕竟不是本文的重点,读者可以参考其它更加专业的文档,但为了方便对模版技术的理解,最后再把修订后的 dialog2.xhtml 页面源码附上:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  xmlns:h="http://java.sun.com/jsf/html"  xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="/dialog_template.xhtml">
    <ui:define name="title">Input Others</ui:define>
    <ui:define name="description">Please input your others information</ui:define>
    <ui:define name="content">
      <layout:panelGrid columns="2" style="height: 250px">
        <layout:cell style="vertical-align: top">
          <h:outputLabel value="Others:" />
        </layout:cell>
        <layout:cell style="vertical-align: top">
          <w:combo id="others" width="250" />
        </layout:cell>
      </layout:panelGrid>
    </ui:define>
  </ui:composition>
</html>
复合组件
事实上,笔者认为:复合组件才是 Facelets 的精华所在,而复合组件加上AOM的模型事件,则更是完美的搭配。

回顾Dialog的例子,我们发觉:back、next、finish、cancel这四个按钮,其实经常组合在一起,在许多的场景下都可以重复使用。 那么,我们希望把它组装成一个自定义的“复合组件”,以达到代码重用的目的。

首先,我们准备一个buttons.xhtml作为该复合组件的模版:

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
  <w:page>
    This text above will not be displayed.
    It's purpose is for design tools.
    <ui:composition>
      <layout:panelGrid columns="5" style="align: right" width="100%">
        <layout:cell style="width: 90%" />
        <w:button value="Back" action="#{onBack}" />
        <w:button value="Next" action="#{onNext}" />
        <w:button value="Finish" action="#{onFinish}" />
        <w:button value="Cancel" action="#{onCancel}" />
      </layout:panelGrid>
    </ui:composition>
  </w:page>
</f:view>
同样需要注意的是:上述文件中真正有用的东西是<ui:composition>标记之内的内容,至于外面的<f:view>、<w:page>等标记, 纯粹是为了让设计器更好的工作而准备的。

在buttons.xhtml中,我们定义了四个按钮,并且,分别指定它们的 action为 #{onBack}、#{onNext}、#{onFinished}、#{onCancel}。然后我们再为这个组件准备一个描述文件:buttons.taglib.xml。

<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<facelet-taglib>
  <namespace>http://www.mycompany.com/aom</namespace>
  <tag>
    <tag-name>buttons</tag-name>
    <source>buttons.xhtml</source>
  </tag>
</facelet-taglib>
在上面这个文件中,我们声明了一个新的tag,其名称为"buttons",它所属于的命名空间是:"http://www.mycompany.com/aom",并且,这个自定义组件的内容来源自 source属性指定的模版文件buttons.xhtml。

怎么告诉Facelets我们新做了一个复合组件呢?在 web.xml 中增加以下配置:

<context-param>
  <param-name>facelets.LIBRARIES</param-name>
  <param-value>/buttons.taglib.xml</param-value>
</context-param>
如果你有多个复合组件的描述文件,就以分号隔开。至此,一个复合组件就准备完毕了,我们来看如何使用这个复合组件。我们准备一个 test_buttons.xhtml来调用新做的这个复合组件,如下所示:

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  xmlns:my="http://www.mycompany.com/aom" renderKitId="AJAX"
  xmlns:ui="http://java.sun.com/jsf/facelets">
  <w:page title="Test buttons component">
    <w:form>
      <h2>Test the buttons component.</h2>
      <p/>
      <my:buttons onBack="#{.onBack}" onNext="#{TestButtonsBean.onNext}"
         onFinish="#{TestButtonsBean.onFinish}" onCancel="#{TestButtonsBean.onCancel}"/>
    </w:form>   
  </w:page>
</f:view>
其中,TestButtonsBean如下所示:

@ManagedBean(name="TestButtonsBean", scope=ManagedBeanScope.SESSION)
public class TestButtonsBean {

  public String onBack() {
    System.out.println("onBack");
    return null;
  }

  public String onNext() {
    System.out.println("onNext");
    return null;
  }

  public String onFinish() {
    System.out.println("onFinish");
    return null;
  }

  public String onCancel() {
    System.out.println("onCancel");
    return null;
  }
}
通过上例可以看出:在 Facelets 下完成一个复合组件是比较简单的一件事情,

但有的同学要问了:这种在 <my:buttons onBack="#{testButtonsBean.onBack}"> 中直接引入 EL 表达式的风格,好像不是那么 IoVC ,有没有更好的解决方案?

答案是:“有。通过模型事件,则是一个更加优雅的解决方案。”

我们将模版文件buttons.xhtml修订如下:

<f:view xmlns="http://www.w3.org/1999/xhtml"  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget"  xmlns:layout="http://www.apusic.com/jsf/layout" renderKitId="AJAX"
  xmlns:h="http://java.sun.com/jsf/html"  xmlns:ui="http://java.sun.com/jsf/facelets">
  <w:page>
    This text above will not be displayed.
    It's purpose is for design tools.
    <ui:composition>
      <layout:panelGrid columns="5" style="align: right" width="100%">
        <layout:cell style="width: 90%" />
        <w:button value="Back" action="#{buttonsBean.onBack}" />
        <w:button value="Next" action="#{buttonsBean.onNext}" />
        <w:button value="Finish" action="#{buttonsBean.onFinish}" />
        <w:button value="Cancel" action="#{buttonsBean.onCancel}" />
      </layout:panelGrid>
    </ui:composition>
  </w:page>
</f:view>
请注意,我们在模版文件中,直接将上述 Button 的 action 绑定在了一个 “buttonsBean” 上,由于这个 “buttonsBean” 是无状态的,所以,它的生命周期声明为none,以下是示例代码:

@ManagedBean(name = "buttonsBean", scope = ManagedBeanScope.NONE)
public class ButtonsBean {

  private EventBroadcaster event = EventBroadcaster.getInstance();
 
  public Object onBack() {
    event.broadcast(this, "com.mycompany.buttons.onBack");
    return null;
  }

  public Object onNext() {
    event.broadcast(this, "com.mycompany.buttons.onNext");
    return null;
  }

  public Object onFinish() {
    event.broadcast(this, "com.mycompany.buttons.onFinish");
    return null;
  }

  public Object onCancel() {
    event.broadcast(this, "com.mycompany.buttons.onCancel");
    return null;
  }
}
换言之,当点击不同的按钮时,buttonsBean 会发送不同的模型事件,事件类型以不同的字符串区分。

然后,我们再修订一下test_buttons.xhtml,看上述这个复合组件,是如何使用的:

<f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
  xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
  xmlns:my="http://www.mycompany.com/aom" renderKitId="AJAX"
  xmlns:ui="http://java.sun.com/jsf/facelets">
  <w:page title="Test buttons component">
    <w:form>
      <h2>Test the buttons component.</h2>
      <p/>
      <my:buttons/>
    </w:form>   
  </w:page>
</f:view>
可以看到,此处,我们只是声明一个<my:buttons/>,并没有将其绑定任何EL表达式。那么,如果我要响应 onBack 按钮点击事件该怎么办呢?很简单,只要有一个 EventListener,监听 "com.mycompany.buttons.onBack"事件即可。以下是 TestButtonsBean 的示例代码:

@ManagedBean(name="TestButtonsBean", scope=ManagedBeanScope.SESSION)
public class TestButtons {

  @EventListener("com.mycompany.buttons.onBack")
  public void onBack() {
    System.out.println("onBack event");
  }
}
通过上例可以看出:通过模型事件,我们能够设计一个更加优雅的复合组件。
分享到:
评论
1 楼 b_lee 2011-03-02  
顶顶顶   加两个字,再顶

相关推荐

    jsf+facelets+ajax4jsf的全部jar包

    Facelets使用XML语法,允许开发者更直观地创建和组织UI组件。它支持模板、导入、组合和重用组件,使得视图更加清晰和易于维护。Facelets还具有编译时的错误检查和性能优化。 3. **Ajax4jsf**:Ajax4jsf是一个开源...

    JSF与Facelets应用程序

    它支持组件重用,便于组件化开发,并且与JSF的生命周期紧密集成,使得开发者可以更好地控制页面的渲染过程。 在JSF和Facelets结合的应用程序中,开发者通常会遵循以下步骤: 1. **定义组件**: 使用Facelets的XML...

    Facelets:jsf、primefaces、facelets、spring 集成、jstl、

    项目可能包括源代码、配置文件以及相关的文档,可以帮助开发者更好地理解和实践Facelets、JSF、PrimeFaces、Spring集成以及JSTL的使用。通过深入研究这些文件,你可以学习到如何构建一个完整的、高效的Java Web应用...

    jsf-facelets1.1.9

    6. **更好的可维护性**:Facelets支持命名空间和包含,可以方便地复用和组织UI片段,降低了代码复杂度。 **JSF Facelets 1.1.9的关键改进:** 1. **性能优化**:版本1.1.9对编译和渲染过程进行了优化,提升了应用的...

    jsf_facelets,jar

    jsf_facelets 1.0.10版本

    jsf-facelets.jar 下载

    jsf-facelets.jar 下载 希望对您有用

    jsf-facelets-1.1.9

    Facelets 非常适合 专为 JSF 设计的视图技术

    jsf-facelets.jar 1.1.15.B1

    jsf-facelets.jar 1.1.15.B1

    facelets中文教程(初级+高级)

    本教程将深入探讨Facelets的基础以及高级特性,旨在帮助初学者和有经验的开发者更好地理解和应用Facelets。 一、Facelets基础 Facelets作为JSF的默认视图描述语言,取代了原来的JSP(JavaServer Pages)。它提供了...

    facelets 教程

    不同于早期 JSF 使用的 JSP(Java Server Pages),Facelets 提供了更为强大的模板处理能力,以及对组件树结构的直观管理,这使得开发者能够以更高效、更整洁的方式构建用户界面。 #### 二、Facelets 的核心优势:...

    facelets模板

    在 JavaServer Faces (JSF) 2.0 中,Facelets 取代 JavaServer Pages (JSP) 成为默认的视图声明语言 (VDL)。有了 Facelets,您不需要像以前在 JSF 1.2 中那样配置视图处理器。Facelets 是一种以 JSF 为中心的视图...

    Facelets Essentials - APRESS

    《Facelets Essentials》一书由...通过学习本书,开发者不仅能够提高开发JSF应用的效率,还能确保应用具有更好的性能和更高的代码质量。无论你是JSF的新手还是有经验的开发者,这本书都将为你提供宝贵的指导和灵感。

    facelets源码包

    Facelets是一种用于构建JavaServer Faces (JSF)应用程序的视图技术,它是JSF 2.0及更高版本的标准视图层表示。Facelets提供了一种声明式的方式来创建动态和交互式的用户界面,允许开发者使用XML或者XHTML语法来定义...

    facelets_demo

    Facelets 是一种用于构建用户界面的视图技术,主要在JavaServer Faces (JSF) 应用程序中使用。它提供了声明式的方式去定义页面结构和逻辑,使得开发者能够更高效地创建和维护Web应用程序的前端。在这个"facelets_...

    Facelets

    Facelets 是一种用于构建 JavaServer Faces (JSF) 应用程序视图的框架,它提供了更高效和灵活的方式来创建用户界面。以下是 Facelets 的详细知识点: 1. **下载与依赖**:首先,你需要下载 Facelets 的库文件,并...

    core jsf 1.2 jsf 核心

    JSF 1.2能够很好地与其他Java EE技术(如EJB、JPA、CDI等)集成,构建完整的企业级应用。 ### 11. 性能优化 JSF 1.2引入了一些性能优化措施,比如延迟组件初始化、减少不必要的请求处理等,以提高整体性能。 ### ...

    JSF框架入门教程和JSF的jar包

    2. **视图(View)**: 视图是用户看到和交互的部分,通常是由JSF组件组成的JSP或Facelets页面。 3. **模型(Model)**: 模型包含了业务逻辑和数据。JSF通过 Managed Beans 来处理模型对象,它们可以是普通的Java类...

    JSF教程(有关jsf实例的操作步骤)

    **JSF(JavaServer Faces)教程** JSF是一种基于组件的服务器端用户界面(UI)框架,用于构建和实现Web应用程序。...通过深入学习这个教程,开发者将能更好地理解和掌握JSF框架,从而高效地开发高质量的Web应用。

Global site tag (gtag.js) - Google Analytics