使用Facelets创建JSF组合控件
项目过程经常需要自定义组件,以提高代码复用和减少代码量等,使用JSF创建自定义组件需要做大量的工作,还需要手动编写烦人的html编码和解码等工作。而将Facelets和JSF结合使用,创建自定义组件则方便很多。当然Facelets的好处还不仅如此。下面的内容翻译自《Facelets Essentials: Guide to JavaServer™ Faces View Definition Framework 》,仅供学习交流使用,详细内容请看原著.
创建一个h:outputLabel 和 h:inputText 组合的组件,命名为inputTextLabeled, 在JSF 页面中用下面的方式使用这个组件, 将在JSF 组件树中增加一个UIComponent 实例:
<custom:inputTextLabeled label="Name" value="#{bird.name}" />
创建一个名为InputTextLabeled.xhtml 的标签源文件, 放在 /WEB-INF/facelets/components 目录下:
$PROJECT
+- /WEB-INF
+- /web.xml
+- /faces-config
+- /facelets
+- /mycustom.taglib.xml
+- /components
+- /InputTextLabeled.xhtml
+- [other tag files]
+- /[xhtml documents]
源文件的代码如下:
<!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">
<ui:component>
<h:outputLabel value="#{label}: ">
<h:inputText value="#{value}"/>
</h:outputLabel>
</ui:component>
</html>
先创建一个名为mycustom.taglib.xml 的标签库文件,位于/WEB-INF/facelets 文件夹下。
mycustom.taglib.xml 如下:
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD
Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/
facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://myfaces.apress.com/custom </namespace>
<tag>
<tag-name>inputTextLabelled</tag-name>
<source>components/InputTextLabeled.xhtml </source>
</tag>
</facelet-taglib>
为了使用这个标签库,需要将mycustom.taglib.xml 的路径告知Facelets 。在web.xml 增加以下内容:
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value> /WEB-INF/facelets/mycustom.taglib.xml</param-value>
</context-param>
就此标签inputTextLabeled 的创建完毕。
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:custom="http://myfaces.apress.com/custom">
<body>
<f:view>
<h:form>
<h:panelGrid columns="1">
<custom:inputTextLabeled label="Name" value="#{bird.name}"/>
<custom:inputTextLabeled label="Order" value="#{bird.order}"/>
<custom:inputTextLabeled label="Family" value="#{bird.family}"/>
</h:panelGrid>
</h:form>
</f:view>
</body>
</html>
和例子一相似,不同的是例子一使用的<ui:component> 会在JSF 组件树中创建一个UIComponent 实例,而例子二使用的<ui:composition> 不会在组件树上创建节点。
EditableColumn.xhtml 文件内容如下:
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:custom="http://myfaces.apress.com/custom">
<ui:composition>
<h:column>
<f:facet name="header">
<h:outputText value="#{headerText}"/>
</f:facet>
<h:outputText value="#{cellText}" rendered="#{!editMode}"/>
<h:panelGroup rendered="#{editMode}">
<custom:inputTextLabeled label="#{headerText}" value="#{cellText}"/>
</h:panelGroup>
</h:column>
</ui:composition>
</html>
在上文的 mycustom.taglib.xml 中增加以下内容:
<tag>
<tag-name>editableColumn</tag-name>
<source>components/EditableColumn.xhtml</source>
</tag>
editablecolumn-example.xhtml
<!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:custom="http://myfaces.apress.com/custom">
<head>
<title>custom:simpleColumn</title>
</head>
<body>
<h:form>
<h:dataTable var="item" value="#{birdDirectory.allBirds}">
<custom:editableColumn headerText="Name" cellText="#{item.name}"
editMode="#{userBean.editMode}"/>
<custom:editableColumn headerText="Order" cellText="#{item.order}"
editMode="#{userBean.editMode}"/>
<custom:editableColumn headerText="Family" cellText="#{item.family}"
editMode="#{userBean.editMode}"/>
</h:dataTable>
<h:commandButton value="Edit Mode"
actionListener="#{userBean.switchToEditMode}"
rendered="#{!userBean.editMode}"/>
<h:commandButton value="Normal Mode"
actionListener="#{userBean.switchToNormalMode}"
rendered="#{userBean.editMode}"/>
</h:form>
</body>
</html>