|
In this chapter, we will cover JavaServer Faces (JSF), the standard component
framework of the Java EE platform. JSF applications consist of a number of JSPs for
the user interface (other view technologies are supported, but JSP is the default), a
series of managed beans that can serve to hold data entered in the JSPs and can also
serve as controllers, and a con_ guration _ le declaring all the managed beans and
page navigation for the application.
Developing Our First JSF Application
To illustrate basic JSF concepts, we will develop a simple application consisting of
two JSPs and a single managed bean.
As we mentioned in this chapter's introduction, the default view technology for JSF
is JSP. A "JSF-enabled" JSP is nothing but a standard JSP using a number of
JSF-speci_ c tags. The following example shows what a typical JSF JSP looks like:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css"> .leftAlign { text-align: left;} .rightAlign { text-align: right;} </style> <title>Enter Customer Data</title> </head> <body> <f:view> <h:form> <h:messages></h:messages> <h:panelGrid columns="2" columnClasses="rightAlign,leftAlign"> <h:outputText value="First Name:"> </h:outputText> <h:inputText label="First Name" value="#{Customer.firstName}" required="true"> <f:validateLength minimum="2" maximum="30"></f:validateLength> </h:inputText> <h:outputText value="Last Name:"></h:outputText> <h:inputText label="Last Name" value="#{Customer.lastName}" required="true"> <f:validateLength minimum="2" maximum="30"></f:validateLength> </h:inputText> <h:outputText value="Email:"> </h:outputText> <h:inputText label="Email" value="#{Customer.email}"> <f:validateLength minimum="3" maximum="30"></f:validateLength> </h:inputText> <h:panelGroup></h:panelGroup> <h:commandButton action="save" value="Save"></h:commandButton> </h:panelGrid> </h:form> </f:view> </body> </html>
The following screenshot illustrates how this JSP renders in the browser.
The above screenshot, of course, was taken after entering some data in every text
_ eld; originally, each text _ eld was blank
Pretty much any JSF-enabled JSP will include the two tag libraries illustrated in the
example. The _ rst tag library (<%@ taglib uri="http://java.sun.com/jsf/core"
prefix="f"%>) is the core JSF tag library, by convention, the pre_ x "f" (for "faces") is
used when using this tag library.
The second tag library (<%@ taglib uri="http://java.sun.com/jsf/html"
prefix="h"%>) is for tags that render HTML components; by convention, the pre_ x
"h" (for "HTML") is used when using this tag library
The example opposite contains some of the most frequently used JSF tags. The _ rst
tag we see in the example is the <f:view> tag, which tells the container that JSF is
used to manage the components inside of it. Any JSF tags (core, HTML, or custom)
must be placed inside the <f:view> tag.
The next tag we see is the <h:form> tag. This tag generates an HTML form when the
JSP is rendered. As can be seen in the example, there is no need to specify an action
or a method attribute for this tag; as a matter of fact, there is no action attribute nor
method attribute for this tag. The action attribute for the rendered HTML form will
be generated automatically, and the method attribute will always be "post".
The next tag we see is the <h:messages> tag. As its name implies, this tag is used
to display any messages. As we will see shortly, JSF can automatically generate
validation messages; these will be displayed inside this tag. Additionally, arbitrary
messages can be added programmatically via the addMessage() method de_ ned in
javax.faces.context.FacesContext.
The next JSF tag we see is <h:panelGrid>. This tag is roughly equivalent to an
HTML table, but it works a bit differently. Instead of declaring rows and columns,
the <h:panelGrid> tag has a columns attribute; the value of this attribute indicates
the number of columns in the table rendered by this tag. As we place components
inside this tag, they will be placed in a row until the number of columns de_ ned in
the columns attribute is reached, and then the next component will be placed in the
next row. In the example, the value of the columns attribute is two, therefore the _ rst
two tags will be placed in the _ rst row, the next two will be placed in the second
row, and so forth.
Another interesting attribute of <h:panelGrid> is the columnClasses attribute. This
attribute assigns a CSS class to each column in the rendered table. In the example,
two CSS classes (separated by a comma) are used as the value for this attribute. This
has the effect of assigning the _ rst CSS class to the _ rst column, and the second one
to the second column. Had there been three or more columns, the third one would
have gotten the _ rst CSS class, the fourth one the second one, and so on, alternating
between the _ rst one and the second one. To clarify how this works, the next code
snippet illustrates a portion of the source of the HTML markup generated by our
sample JSP.
<table>
<tbody>
<tr>
<td class="rightAlign">
First Name:
</td>
<td class="leftAlign">
<input type="text" name="j_id_id18:j_id_id27" /></td>
</tr>
<tr>
<td class="rightAlign">
Last Name:
</td>
<td class="leftAlign">
<input type="text"
name="j_id_id18:j_id_id34" />
</td>
</tr>
<tr>
<td class="rightAlign">Email:</td>
<td class="leftAlign">
<input type="text" name="j_id_id18:j_id_id42" />
</td>
</tr>
<tr>
Notice how each <td> tag has an alternating CSS tag of "rightAlign" or
"leftAlign"; we achieved this by assigning the value "rightAlign,leftAlign" to
the columnClasses attribute of <h:panelGrid>.
At this point in the example, we start adding components inside <h:panelGrid>.
These components will be rendered inside the table rendered by <h:panelGrid>.
As we mentioned before, the number of columns in the rendered table is defi ned by
the columns attribute of <h:panelGrid>. Therefore, we don't need to worry about
columns (or rows); we just start adding components and they will be placed in the
right place.
The next tag we see is the <h:outputText> tag. This tag is similar to the core
JSTL <c:out> tag. It outputs the text or expression in its value attribute to the
rendered page.
Next, we see the <h:inputText> tag. This tag generates a text field in the rendered
page; its label attribute is used for any validation messages. It lets the user know
what field the message refers to.
Of particular interest is the tag's value attribute. What we see as the value for
this attribute is a value binding expression. What this means is that this value is
tied to a property of one of the application's managed beans. In the example, this
particular text fi eld is tied to a property called firstName in a managed bean called
Customer. When a user enters a value for this text fi eld and submits the form, the
corresponding property in the managed bean is updated with this value. The tag's
required attribute is optional and valid values for it are true and false. If this
attribute is set to true, the container will not let the user submit the form until the
user enters some data for the text field.
If the user attempts to submit the form without entering a required value, the
page will be reloaded and an error message will be displayed inside the
<h:messages> tag.
The above screenshot illustrates the default error message shown when the user
attempts to save the form in the example without entering a value for the customer's
_ rst name. The _ rst part of the message ("First Name") is taken from the value of
the label attribute of the corresponding <h:inputTextField> tag. The text of the
message can be customized, as well as its style (font, color, etc.). We will cover how
to do this later in this chapter.
Each <h:inputField> tag in our example has a nested <f:validateLength> tag.
As its name implies, this tag validates that the entered value for the text fi eld is
between a minimum and maximum length. Minimum and maximum values are
defi ned by the tag's minimum and maximum attributes. <f:validateLength> is one
of the standard validators included with JSF. Just as with the required attribute of
<h:inputText>, JSF will automatically display a default error message when a user
attempts to submit a form with a value that does not validate.
Again, the default message and style can be overridden; we will cover how to do this
in the next section.
In addition to <f:validateLength> JSF includes two other standard validators: <f:
validateDoubleRange> validates that the value is a valid Double value between
the two values specifi ed by the tag's minimum and maximum attributes, inclusive. <f:
validateLongRange> validates that the value is a valid Long value between the
values specifi ed by the tag's minimum and maximum attributes.
<h:panelGroup> is the next new tag in the example. Typically, <h:panelGroup>
is used to group several components together so that they occupy a single cell in
an <h:panelGrid>. This can be accomplished by adding components inside <h:
panelGroup> and adding <h:panelGroup> to <h:panelGrid>. As can be seen in the
example, this particular instance of <h:panelGroup> has no child components. In
this particular case, the purpose of <h:panelGroup> is to have an "empty" cell and
have the next component, <h:commandButton>, align with all other input fields in
the form.
<h:commandButton> renders an HTML input fi eld in the browser, just as with
standard HTML and JSPs; its purpose is to submit the form. Its value attribute
simply sets the button's label. This tag's action attribute is used for navigation; the
next JSP to show is based on the value of this attribute. The action attribute can
have a String constant or Unifi ed Expression Language as its value; additionally
it can have a method binding expression, mea ning that it can point to a method
in a managed bean that returns a String. We will see an example of a <h:
commandButton> tag whose action attribute is a method-binding expression later in
this chapter.
Navigation rules and managed beans are defi ned in a confi guration fi le called
faces-config.xml. This fi le must be placed in the WEB-INF folder of the
application's WAR fi le. The faces-config.xml fi le for our example application
looks like this:
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http:// java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2"> <managed-bean> <managed-bean-name>Customer</managed-bean-name> <managed-bean-class> net.ensode.glassfishbook.jsf.Customer </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <navigation-rule> <from-view-id>/customer_data_entry.jsp</from-view-id> <navigation-case> <from-outcome>save</from-outcome> <to-view-id>/confirmation.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>
The <managed-bean> element defi nes a managed bean that can be used for
value-binding and method binding expressions. Its nested <managed-bean-name>
element defi nes a logical name for this managed bean. The <managed-bean-class>
element must contain the fully qualifi ed name of the managed bean's class. The
<managed-bean-scope> element indicates the scope of the bean. Valid values for
this element include request, session, application, and none. The managed bean
will be attached as an attribute of the specifi ed scope. Several managed beans can be
declared in this manner. In our example application, there is only one managed bean.
Its source code is shown in the following code listing:
package net.ensode.glassfishbook.jsf; public class Customer {
private String firstName; private String lastName; private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Notice that there is nothing special about this bean. It is a standard JavaBean with
private properties and corresponding getter and setter methods.
The next tag we see in faces-config.xml is the <navigation-rule> tag. This tag
defi nes where a page will navigate after a certain outcome. In this example, this
navigation rule ties to the <h:commandButton> tag that had a value for its action
attribute of "save". When the form is submitted, the container will look for an action
of "save", as defi ned in the <from-outcome> element in the above faces-config.
xml, and navigate to the JSP defi ned in the <to-view-id> element (/confirmation.
jsp in this case). Each <navigation-rule> element must have only one <fromview-
id> child element, but it can have several <navigation-case> elements, one
for each outcome.
As can be seen in faces-config.xml, when the user clicks on the "save" button
from the customer_data_entry.jsp, our application will navigate to a JSP called
confirmation.jsp. The source for this JSP looks like this:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Customer Data Entered</title> </head> <body> <p>The following data was entered:</p> <f:view> <h:panelGrid columns="2"> <h:outputText value="First Name:"></h:outputText> <h:outputText value="#{Customer.firstName}"></h:outputText> <h:outputText value="Last Name:"></h:outputText> <h:outputText value="#{Customer.lastName}"></h:outputText> <h:outputText value="Email:"></h:outputText> <h:outputText value="#{Customer.email}"></h:outputText> </h:panelGrid> </f:view> </body> </html>
There are no tags we haven't seen before in this JSP. One thing to notice about it is
that it is using value-binding expressions as the value for all of its <h:outputText>
tags. As these value-binding expressions are the same expressions used in the
previous page for the <h:inputText> tags, their values will correspond to the data
the user entered.
The last piece of the puzzle is the application's web.xml file.
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http:// java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name>Archetype Created Web Application</display-name> <servlet> <display-name>FacesServlet</display-name> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> </web-app>
A JSF application is a standard web application; therefore a standard web.xml file
is needed. As can be seen in the example, a single servlet is added to the web.xml
confi guration fi le; this servlet is included in the JSF libraries.It is customary to use a suffi x mapping of .jsf or a prefi x mapping of /faces/ to
access the FacesServlet. This example declares both mappings.
|