Before JSF 2.0,
JSP (JavaServer Pages) technology produced page views.
In 2.0,
Facelets replaces JSP as the JSF view handler:
- Better error messages
- Mechanism for factoring out common page
parts: templates
- Easier mechanism for writing custom components
The capabilities of Facelets are demonstrated in the
Planets
Example available in the menu to the left.
The planets example shows a common page layout approach:
- Header
- Login page: "Welcome to the Planetarium"
- Other pages: "The Planetarium"
- Sidebar
- Login page: One message and image
- Other pages: Multiple images as links
- Content
- Login page: Login form
- Other pages: Varying content depending on planet
In addition, the page title varies:
- Login page: "Welcome to the Planetarium"
- Other pages: Planet names
masterLayout.xhtml is an ordinary XHTML file except for the
ui:insert tags:
- Each ui:insert tag corresponds to one of
four named page elements: windowTitle, header, sidebarLeft,
or content
- If the ui:insert tag has a body, it is used
as default content for the template
- Pages use this layout through
a ui:composition tag that defines what is to be inserted
using ui:define tags in its body
Use
ui:composition as in
login.xhtml below to make use of
a template:
- The ui:define tags in the composition
correspond to the ui:insert tags in the master layout template
- When the template is loaded, each ui:insert
tag is replaced with the contents of the corresponding ui:define
- Note use of ui:include to get content from
another file
Since
ui:composition uses a master layout
page that already has
html,
head,
title,
and
body tags, Facelets removes all tags
outside
the
ui:composition tag, explaining why the title is
IGNORED.
<!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:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head><title>IGNORED</title></head>
<body>
<ui:composition template="/templates/masterLayout.xhtml">
<ui:define name="windowTitle">
#{msgs.loginTitle}
</ui:define>
<ui:define name="heading">
<ui:include src="/sections/login/header.xhtml"/>
</ui:define>
<ui:define name="sidebarLeft">
<ui:include src="/sections/login/sidebarLeft.xhtml"/>
</ui:define>
<ui:define name="content">
<h:form>
<h:panelGrid columns="2">
#{msgs.namePrompt}
<h:inputText id="name" value="#{user.name}"/>
#{msgs.passwordPrompt}
<h:inputSecret id="password" value="#{user.password}"/>
</h:panelGrid>
<p>
<h:commandButton value="#{msgs.loginButtonText}"
action="planetarium"/>
</p>
</h:form>
</ui:define>
</ui:composition>
</body>
</html>
- The included content is wrapped in a ui:composition tag
so that the surrounding tags are stripped
- However, no template attribute is given
because it is already specified in the including file
<!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><title>IGNORED</title></head>
<body>
<ui:composition>
#{msgs.loginHeading}
</ui:composition>
</body>
</html>
- After the user logs in, the
same master layout is used for the rendered page planetarium.xhtml
- Note that the header and sidebarLeft
are not defined, so the defaults are used
<!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><title>IGNORED</title></head>
<body>
<ui:composition template="/templates/masterLayout.xhtml">
<ui:define name="windowTitle">
#{msgs.planetariumTitle}
</ui:define>
<ui:define name="content">
#{msgs.planetariumWelcome}
</ui:define>
</ui:composition>
</body>
</html>
- If the user has logged in and clicks on Saturn, the
same master layout is used again in saturn.xhtml
- Each of the planets uses the master layout in the
same way
- In a richer application, the content for
each planet would be in a separate file
<!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><title>IGNORED</title></head>
<body>
<ui:composition template="/templates/masterLayout.xhtml">
<ui:define name="windowTitle">
#{msgs.saturn}
</ui:define>
<ui:define name="content">
Saturn has rings made of ice and dust.
</ui:define>
</ui:composition>
</body>
</html>
To use a custom tag, it must be declared in a
tag library file
containing:
- The namespace that is mapped to prefixes in the
XHTML pages
- Each tag's name and the source file of its definition
Finally, the
web.xml configuration file must know about the tag
library location by including a
context-param element.
corejsf.taglib.xml | web.xml |
<?xml version="1.0"?>
<!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://corejsf.com/facelets</namespace>
<tag>
<tag-name>planet</tag-name>
<source>tags/corejsf/planet.xhtml</source>
</tag>
</facelet-taglib>
|
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/corejsf.taglib.xml</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/login.xhtml</welcome-file>
</welcome-file-list>
</web-app>
|
Two approaches to templating:
- Start with form and add content, as in
the Planets example
- Start with content and add form, as shown below
The markup on the left displays a login form which is the child of
a
ui:decorate tag with a
template attribute.
The template on the right surrounds the login form with
a default
heading and
sidebarLeft, making the login form
the page's
content
- The ui:insert tag without a name
attribute inserts the entire body of the ui:decorate
tag.
- The tags outside ui:decorate are not trimmed
Facelets simply considers
ui:decorate and
ui:composition
as complementary constructs:
ui:composition trims all surrounding
contents, whereas
ui:decorator does not.
Decorated Markup | masterDecorator.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:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head><title>#{msgs.loginTitle}</title></head>
<body>
<ui:decorate template="/templates/masterDecorator.xhtml">
<!-- Contents to be decorated -->
<h:form>
<h:panelGrid columns="2">
#{msgs.namePrompt}
<h:inputText id="name" value="#{user.name}"/>
#{msgs.passwordPrompt}
<h:inputSecret id="password" value="#{user.password}"/>
</h:panelGrid>
<p>
<h:commandButton value="#{msgs.loginButtonText}"
action="planetarium"/>
</p>
</h:form>
</ui:decorate>
</body>
</html>
|
Optional XHTML header
<ui:composition>
<h:outputStylesheet library="css" name="styles.css" target="body"/>
<div id="heading">
<ui:insert name="heading">Default header</ui:insert>
</div>
<div id="sidebarLeft">
<ui:insert name="sidebarLeft">Default sidebar</ui:insert>
</div>
<div id="content">
<ui:insert/>
</div>
</ui:composition>
Optional XHTML footer
|
When you place the
ui:debug tag in a Facelets page, a debug component is
added to the component tree for that page.
If the user types a hotkey, which by default is CTRL+SHIFT+d, JSF opens
a window and displays the state of the component tree and the
application’s scoped variables: