- 浏览: 119347 次
- 性别:
- 来自: 重庆
文章分类
最新评论
-
sunxiangfei91:
引用[*][url][/url]
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 1167EJB会话Bean有声明式事务 ... -
配置Seam组件之二
2010-01-16 20:30 912如果你有大量的组件需要在XML中进行配置,那么就很有必要将 c ... -
配置Seam组件之一
2010-01-16 20:29 941Seam所崇尚的哲学是XML配 ... -
Seam上下文
2009-12-25 15:23 989Seam上下文是由框架创建 ... -
JSF和Spring的集成之二
2009-12-23 17:55 917使用框架 1 介绍 这个 ... -
JSF和Spring的集成之一
2009-12-19 20:45 731JSF和Spring集成的资料比较少,原理是获得彼此的上下文引 ... -
Seam配置和Seam应用程序打包之二
2009-11-28 09:15 1255将Seam与你的EJB容器集成 我们需要将 SeamInter ... -
Seam配置和Seam应用程序打包之一
2009-11-20 22:25 1092Seam基本配置 首先,让我们看看每当将Seam和JSF一起使 ... -
用Java Server Faces建立交互式WEB站点
2009-11-07 10:12 599步骤1:开发组件的Java ... -
集成JSF与BEEHIVE PAGE FLOW之二
2009-10-10 21:54 1000从后台bean访问当前页面 ... -
集成JSF与BEEHIVE PAGE FLOW之一
2009-10-07 23:13 963JSF对通过关联组件和事件来构建页面而说是非常棒的,但是,与所 ... -
借助Ajax自动保存JSF表单之二
2009-09-19 12:53 1176创建和发送 Ajax 请求 submitFormData() ... -
借助 Ajax 自动保存 JSF 表单之一
2009-09-13 11:00 1055在客户端获取表单数据 本节将给出一个 JSF 表单,其数据通 ... -
基于AJAX和JSF打造丰富的互联网组件之Weblets篇
2009-09-04 15:08 903为了在JSF开发中联合使用AJAX和Mozilla XUL技术 ... -
JSF 2.0的一个AJAX例子
2009-08-21 10:49 2388首先创建一个ManagedBean用来记录我们提交按钮的数量。 ... -
JSF2.0的页面模版化
2009-08-15 10:28 1692本篇介绍可以与Tapestry相媲美的页面模版化定义。 我 ... -
JSF2.0中自定义组件模型例子
2009-08-11 07:59 1302在本篇介绍中,我们开始接触JSF2.0纳为标准的最重要的特性之 ... -
Java Server Faces 2.0重要新功能以及相关改进简介
2009-08-01 10:00 1058JSF 2.0的最终规范也已经发布了有近一个月了,在近期试 ... -
JSF2: Ajax事件和错误
2009-07-09 09:13 1064JSF2的Ajax支持包含一个 ... -
JSF里自订验证器
2009-06-06 16:52 901您可以自订自己的验证器,所需要的是实作javax.faces. ...
相关推荐
jsf+facelets+ajax4jsf的全部jar包
jsf_facelets 1.0.10版本
JSF+Facelets相结合的应用程序例子。
JSF/Facelets/xhtml学习
jsf-facelets.jar 下载 希望对您有用
Facelets 非常适合 专为 JSF 设计的视图技术
jsf-facelets.jar 1.1.15.B1
小面 jsf、primefaces、facelets、spring 集成、jstl、
在 JavaServer Faces (JSF) 2.0 中,Facelets 取代 JavaServer Pages (JSP) 成为默认的视图声明语言 (VDL)。有了 Facelets,您不需要像以前在 JSF 1.2 中那样配置视图处理器。Facelets 是一种以 JSF 为中心的视图...
jsf-facelets1.1.9 目前最高版本 时间:2012年9月
JavaEE5学习笔记13-JSF集成Facelets使用经验总结.
[TipTec Development] JSF & Facelets & JBoss Seam 核心技术 (英文版) [TipTec Development] Essential JSF, Facelets & JBoss Seam (E-Book) ☆ 出版信息:☆ [作者信息] Kent Ka Iok Tong [出版机构] TipTec ...
这是一个使用jsf框架实现简易登录功能的小例子,对于初学者可以参考一下。
jsf-facelets-1.1.15.B1.jar
Facelets ,very good
JSF框架的jar和JSF的教程帮助你学习的JSF框架
试图把 JSF 和 JSP 结合起来就像试图要把脚硬塞进手套一样:可能做得到,但是只是更好的解决办法出现之前的一个权宜之计。在这篇文章中,JSF 的热心支持者 Rick Hightower 介绍了关于 Facelets 他最喜欢的内容:容易...
facelets中文初级+高级教程,另有facelets标签
jsf 1.2 myfaces1.2.7 richfaces3.3.1 facelets1.2 所有的最新包 让你一步到位,所有包测试过。可以兼容
使用Facelets视图声明语言、托管bean和JSF表达式语言(EL)。按照JSF导航模型声明一个页面,包括新的“隐式导航”功能。使用用户界面组件模型和JSF事件模型,包括支持可添加书签的页面以及POST、REDIRECT、GET模式。...