For any view technology to succeed, it must have some aspect of templating and re-use that's both easy to use and understand. Facelets technology solves this issue in a way that is ideal for JavaServer Faces while keeping that sense of familiarity to traditional, tag-based user interfaces. This article covers the possible ways to increase re-use and simplify maintenance on your JavaServer Faces project.
When people first start creating web pages, they often find themselves repeating content across multiple files. As a developer, this can be frustrating when your object-oriented tendencies kick in. Wouldn't it be nice to simply maintain that content in one spot?
The first approach to templating and re-use is creating a template. A web page is often composed of some basic parts: header, body, and footer. With Facelets, you can pull those common elements into a single page, creating a template with editable areas, as shown in the following sample template:
- <!-- template.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">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
- <title>Sample Template</title>
- </head>
- <body>
- <h1>#{title}</h1>
- <div><ui:insert name="menu"/></div>
- <p><ui:insert name="body"/></p>
- </body>
- </html>
The ui:insert tag for menu
and body
mark areas that change on a per-page basis. You can create other pages that will use this template and provide content for both your menu and body.
xml 代码
- <!-- template-client.xhtml -->
- <!-- content above will be trimmed -->
- <ui:composition template="template.xhtml">
- <ui:param name="title" value="Here's my Title"/>
- <ui:define name="menu">Here's My Menu</ui:define>
- <ui:define name="body">Here's My Body</ui:define>
- </ui:composition>
- <!-- content below will be trimmed -->
This example page introduces another tag: <ui:composition/>
. This tag provides a couple features. It trims any content around it. This means you can have a normal HTML page and Facelets will only use or render the content within the ui:composition
tag. With this tag, you also have the option of providing a template
attribute, which will define how and where its content is layed out.
To pair content within this page and the template, the ui:define
tags are used with names that match the ui:insert
tags from the template above. For simply passing variables or text, you can use the ui:param
tag, which exposes the value as a variable within the template.
When Facelets render the page above with the specified template, you will get the following output:
- <!-- template.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">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
- <title>Sample Template</title>
- </head>
- <body>
- <h1>Here's my Title</h1>
- <div>Here's My Menu</div>
- <p>Here's My Body</p>
- </body>
- </html>
The previous example can be simplified even more if there's only one area that can be changed
within a template:
- <!-- simple-template.xhtml -->
- ...
- <body>
- <h1>Title</h1>
- <!-- editable body -->
- <p><ui:insert/></p>
- </body>
- ...
The page that wants to use the above template can now be as simple as this:
- <!-- simple-template-client.xhtml -->
- <ui:composition template="simple-template.xhtml">
- Here's My Simple Body
- </ui:composition>
The idea of compositions in pages is pretty powerful for defining re-usable content in your web pages. The examples so far have shown how to use compositions with a template for rendering. But what if you want to include that composition in another page? Maybe there's a series of form controls or a complex menu that you would rather separate out into a different document that can be reused or managed separately without cluttering up your page layout.
Facelets provides two ways of including compositions or other pages in general. The first option is with the ui:include
tag. This tag should be pretty familiar to web developers:
When Facelets processes the include.xhtml, siteNav.xhtml will have all of its content within the ui:composition
included into include.xhtml:
- <!-- include.xhtml -->
- ...
- <span id="leftNav">
- <!-- myfaces tomahawk components -->
- <t:tree2 value="#{backingBean.options}" var="opt">
- ...
- </t:tree2>
- </span>
- ...
If you would like to pass variables to siteNav.xhtml, to be used with the tree component, then you can use the ui:param
tag:
- <!-- include.xhtml -->
- ...
- <span id="leftNav">
- <ui:include src="/WEB-INF/siteNav.xhtml">
- <ui:param name="menuBean" value="#{backingBean.options}"/>
- </ui:include>
- </span>
- ...
- <!-- siteNav.xhtml -->
- ...
- <ui:composition>
- <!-- myfaces tomahawk components -->
- <t:tree2 value="#{menuBean}" var="opt">
- ...
- </t:tree2>
- </ui:composition>
- ...
You can see that now the siteNav.xhtml can just reference the variable menuBean
and assume that it will be passed within the ui:include
tag. This allows for some flexibility with re-using common components and content.
Facelets provides an even cleaner solution to ui:include
and ui:param
by supporting custom tags. Don't worry, you don't have to write any Java code. To make siteNav.xhtml a reusable tag, you must create a simple XML taglib file:
- <facelet-taglib>
- <namespace>">http://www.mycompany.com/jsf</namespace>
- <tag>
- <tag-name>siteNav.xhtml</tag-name>
- <source>/WEB-INF/tags/siteNav.xhtml</source>
- </tag>
- </facelet-taglib>
Aside from pointing Facelets at your new taglib XML file, that's it. You may add as many tags as you want to your new taglib. By specifying the http://www.mycompany.com/jsf
namespace within your pages, you can now write:
- <!-- include-tag.xhtml -->
- ...
- <span id="leftNav">
- <my:siteNav menuBean="#{backingBean.options}"/>
- </span>
- ...
The include-tag.xhtml example is equivalent to the include.xhtml example above. The attribute menuBean
will be made available as an attribute within siteNav.xhtml, just as <ui:param/>
provided.
Your project may include a whole library of custom tags that are packaged with your JAR files or simply placed within a folder in your web application. Many more tags are covered in the Facelets Developer Documentation.