- 浏览: 122657 次
- 性别:
- 来自: 重庆
文章分类
最新评论
-
sunxiangfei91:
<div class="quote_title ...
Spring使用MimeMessageHelper -
lhb3015:
lz, Coder 这个类的代码呢??
Java RSA算法加密 -
b_lee:
顶顶顶 加两个字,再顶
Facelets是JSF更好的外衣 -
zhuqing08:
楼主 Coder 这个类的代码呢?
Java RSA算法加密 -
evajhhot:
貌似不行 有异常
BlazeDS 与Spring集成指南之一
是由 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");
}
}
通过上例可以看出:通过模型事件,我们能够设计一个更加优雅的复合组件。
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");
}
}
通过上例可以看出:通过模型事件,我们能够设计一个更加优雅的复合组件。
发表评论
-
Seam管理的事务
2010-01-28 15:22 1195EJB会话Bean有声明式事务 ... -
配置Seam组件之二
2010-01-16 20:30 942如果你有大量的组件需要在XML中进行配置,那么就很有必要将 c ... -
配置Seam组件之一
2010-01-16 20:29 975Seam所崇尚的哲学是XML配 ... -
Seam上下文
2009-12-25 15:23 1017Seam上下文是由框架创建 ... -
JSF和Spring的集成之二
2009-12-23 17:55 942使用框架 1 介绍 这个 ... -
JSF和Spring的集成之一
2009-12-19 20:45 766JSF和Spring集成的资料比较少,原理是获得彼此的上下文引 ... -
Seam配置和Seam应用程序打包之二
2009-11-28 09:15 1291将Seam与你的EJB容器集成 我们需要将 SeamInter ... -
Seam配置和Seam应用程序打包之一
2009-11-20 22:25 1137Seam基本配置 首先,让我们看看每当将Seam和JSF一起使 ... -
用Java Server Faces建立交互式WEB站点
2009-11-07 10:12 637步骤1:开发组件的Java ... -
集成JSF与BEEHIVE PAGE FLOW之二
2009-10-10 21:54 1033从后台bean访问当前页面 ... -
集成JSF与BEEHIVE PAGE FLOW之一
2009-10-07 23:13 995JSF对通过关联组件和事件来构建页面而说是非常棒的,但是,与所 ... -
借助Ajax自动保存JSF表单之二
2009-09-19 12:53 1212创建和发送 Ajax 请求 submitFormData() ... -
借助 Ajax 自动保存 JSF 表单之一
2009-09-13 11:00 1097在客户端获取表单数据 本节将给出一个 JSF 表单,其数据通 ... -
基于AJAX和JSF打造丰富的互联网组件之Weblets篇
2009-09-04 15:08 936为了在JSF开发中联合使用AJAX和Mozilla XUL技术 ... -
JSF 2.0的一个AJAX例子
2009-08-21 10:49 2418首先创建一个ManagedBean用来记录我们提交按钮的数量。 ... -
JSF2.0的页面模版化
2009-08-15 10:28 1731本篇介绍可以与Tapestry相媲美的页面模版化定义。 我 ... -
JSF2.0中自定义组件模型例子
2009-08-11 07:59 1332在本篇介绍中,我们开始接触JSF2.0纳为标准的最重要的特性之 ... -
Java Server Faces 2.0重要新功能以及相关改进简介
2009-08-01 10:00 1084JSF 2.0的最终规范也已经发布了有近一个月了,在近期试 ... -
JSF2: Ajax事件和错误
2009-07-09 09:13 1091JSF2的Ajax支持包含一个 ... -
JSF里自订验证器
2009-06-06 16:52 930您可以自订自己的验证器,所需要的是实作javax.faces. ...
相关推荐
Facelets使用XML语法,允许开发者更直观地创建和组织UI组件。它支持模板、导入、组合和重用组件,使得视图更加清晰和易于维护。Facelets还具有编译时的错误检查和性能优化。 3. **Ajax4jsf**:Ajax4jsf是一个开源...
它支持组件重用,便于组件化开发,并且与JSF的生命周期紧密集成,使得开发者可以更好地控制页面的渲染过程。 在JSF和Facelets结合的应用程序中,开发者通常会遵循以下步骤: 1. **定义组件**: 使用Facelets的XML...
项目可能包括源代码、配置文件以及相关的文档,可以帮助开发者更好地理解和实践Facelets、JSF、PrimeFaces、Spring集成以及JSTL的使用。通过深入研究这些文件,你可以学习到如何构建一个完整的、高效的Java Web应用...
6. **更好的可维护性**:Facelets支持命名空间和包含,可以方便地复用和组织UI片段,降低了代码复杂度。 **JSF Facelets 1.1.9的关键改进:** 1. **性能优化**:版本1.1.9对编译和渲染过程进行了优化,提升了应用的...
jsf_facelets 1.0.10版本
jsf-facelets.jar 下载 希望对您有用
Facelets 非常适合 专为 JSF 设计的视图技术
jsf-facelets.jar 1.1.15.B1
本教程将深入探讨Facelets的基础以及高级特性,旨在帮助初学者和有经验的开发者更好地理解和应用Facelets。 一、Facelets基础 Facelets作为JSF的默认视图描述语言,取代了原来的JSP(JavaServer Pages)。它提供了...
不同于早期 JSF 使用的 JSP(Java Server Pages),Facelets 提供了更为强大的模板处理能力,以及对组件树结构的直观管理,这使得开发者能够以更高效、更整洁的方式构建用户界面。 #### 二、Facelets 的核心优势:...
在 JavaServer Faces (JSF) 2.0 中,Facelets 取代 JavaServer Pages (JSP) 成为默认的视图声明语言 (VDL)。有了 Facelets,您不需要像以前在 JSF 1.2 中那样配置视图处理器。Facelets 是一种以 JSF 为中心的视图...
《Facelets Essentials》一书由...通过学习本书,开发者不仅能够提高开发JSF应用的效率,还能确保应用具有更好的性能和更高的代码质量。无论你是JSF的新手还是有经验的开发者,这本书都将为你提供宝贵的指导和灵感。
Facelets是一种用于构建JavaServer Faces (JSF)应用程序的视图技术,它是JSF 2.0及更高版本的标准视图层表示。Facelets提供了一种声明式的方式来创建动态和交互式的用户界面,允许开发者使用XML或者XHTML语法来定义...
Facelets 是一种用于构建用户界面的视图技术,主要在JavaServer Faces (JSF) 应用程序中使用。它提供了声明式的方式去定义页面结构和逻辑,使得开发者能够更高效地创建和维护Web应用程序的前端。在这个"facelets_...
Facelets 是一种用于构建 JavaServer Faces (JSF) 应用程序视图的框架,它提供了更高效和灵活的方式来创建用户界面。以下是 Facelets 的详细知识点: 1. **下载与依赖**:首先,你需要下载 Facelets 的库文件,并...
JSF 1.2能够很好地与其他Java EE技术(如EJB、JPA、CDI等)集成,构建完整的企业级应用。 ### 11. 性能优化 JSF 1.2引入了一些性能优化措施,比如延迟组件初始化、减少不必要的请求处理等,以提高整体性能。 ### ...
2. **视图(View)**: 视图是用户看到和交互的部分,通常是由JSF组件组成的JSP或Facelets页面。 3. **模型(Model)**: 模型包含了业务逻辑和数据。JSF通过 Managed Beans 来处理模型对象,它们可以是普通的Java类...
**JSF(JavaServer Faces)教程** JSF是一种基于组件的服务器端用户界面(UI)框架,用于构建和实现Web应用程序。...通过深入学习这个教程,开发者将能更好地理解和掌握JSF框架,从而高效地开发高质量的Web应用。