您的位置:首页 > Web前端

Web Tier to Go With Java EE 5: Summary of New Features in JavaServer Faces 1.2 Technology

2006-06-12 22:00 831 查看
By Jennifer Ball and Ed Burns, February 2006

Articles Index

The first article of the "Web Tier to Go With Java EE 5" series summarizes new features in JavaServer Pages (JSP) 2.1 technology. As that article describes, the biggest contribution of JSP technology is better alignment with JavaServer Faces technology, which was accomplished by unifying the two expression languages (ELs). Alignment with the JSP framework is also one of the more important achievements of JavaServer Faces 1.2 technology, developed through JSR 252. In addition to these changes, JavaServer Faces technology contributes a host of other significant ease-of-use features. This article briefly describes the more substantial ones, which include the following:

Alignment with JSP technology

Ease-of-use improvements in support for custom messages

Improved state-saving behavior

Ability to turn off generation of component client IDs

New
setPropertyActionListener
Tag


The Preface section of the JavaServer Faces specification provides a complete list of new features.

Alignment With JSP Technology


At the center of the incompatibilities between the JSP and JavaServer Faces technologies was the difference between the page life cycles that they support. As the previous article explains, the JSP specification supports a single render-and-response life cycle during which the elements in the page are executed in the order they appear, and the page is rendered immediately. The JavaServer Faces technology life cycle, on the other hand is divided into several phases, during which a component tree is created, the components' data is processed, and the components are rendered to the page. Therefore, a JavaServer Faces page is not necessarily rendered immediately after it is executed. As a result, the use of JavaServer Faces components in JSP pages sometimes caused content to be rendered in the wrong order, component state to be lost, or other problems to occur.

The article summarizing new features in JSP 2.1 technology touched on some of these issues. This article gives you more detail on what has changed in JavaServer Faces technology to foster alignment between the two technologies:

First-class support of JSTL's
forEach
tag with JavaServer Faces components

Improvements in tree creation and content interweaving

Deprecation of the JavaServer Faces technology EL in favor of the unified EL

First-Class Support of JSTL's
forEach
Tag With JavaServerFaces Components


As described in the article describing new features in JSP technology, one benefit of unifying the EL in the entire Java EE web tier is that iterating tags such as JSTL's
forEach
tag can now be used with JavaServer Faces components in an intuitive way. For example, to render a simple table with input components, you could have the following code:

<table>
<tr><th>Item Name</th> <th>Item Price</th> <th>Item Quantity</th></tr>
<c:forEach var="item" items="#{shoppingCart.items}">
<tr>
<td><h:outputText value="#{item.name}" /></td>
<td><h:outputText value="#{item.price}" /></td>
<td><h:inputText value="#{item.quantity}" /></td>
</tr>
</c:forEach>
<h:commandButton value="update quantities" action="update" />
</table>

Without the unified EL, this coordination would not be possible.

Improvements in Tree Creation and Content Interweaving

As documented by Hans Bergsten in his article about the use of JavaServer Faces technology with JSP pages, mixing JSP code with JavaServer Faces tags sometimes yielded unexpected results. For example, in the following code, the value of the JavaServer Faces output text component
Hi.
should be displayed before the JSP template text
What's your name?


<h:panelGroup>
<h:outputText value="Hi. "/>
What's your name?
</h:panelGroup>

However, these two lines are reversed in the code's output. What caused this problem? The JavaServer Faces implementation depended on the JSP rendering engine to render the component tree. Because JSP technology immediately executes and adds static text to the response, whereas the children of the
panelGroup
tag are not rendered until after the end-tag of
panelGroup
is reached, the text
What's your name?
would be rendered before the text
Hi.


Problems such as this and others mentioned in Hans Bergsten's article have been fixed in JavaServer Faces 1.2 technology. The solution involved changing how the component tree is created and how various kinds of content are processed and rendered. The most important changes are the following:

The creation and rendering of the component tree is now split into two steps to prevent the JSP technology engine from rendering content prematurely.

The
rendersChildren
properties of all standard renderers are now set to
true
so that the body content of the associated components is not rendered separately from the components themselves.

The static content in the body of tags whose renderers have
rendersChildren
set to
true
is captured and stored in a transient
UIOutput
component and added to the tree.

State-management tasks have been moved from
ViewTag
to
ViewHandler
to prevent
writeState
from being called before the state is actually saved.

The upcoming article in the "Web Tier to Go With Java EE 5" series provides a more detailed discussion of the improvements in tree creation and content interweaving, which now make it possible to mix JavaServer Faces component tags with other JSP code.

Deprecation of the JavaServer Faces EL in Favor of the Unified EL

As the previous article in this series explains, the ELs of both the JSP and JavaServer Faces technologies are consolidated into the unified EL. This means that the JavaServer Faces EL is now deprecated. Those of you who had built JavaServer Faces applications prior to the introduction of the unified EL can be assured that your applications are completely backward-compatible.

However, in order to take advantage of the unified EL's features, you will need to change your custom components and custom tags. Migrating to the unified EL primarily involves changing
ValueBinding
to
ValueExpression
and changing
MethodBinding
to
MethodExpression
. These changes are fairly easy to make. Furthermore, the new way of doing things is also easier. For example, because all standard tag attributes are enabled to accept value expressions, your tag handler does not need to check whether an attribute is enabled to accept value expressions.

To get more details on migrating to the unified EL, please see the article "Unified Expression Language."

Ease-of-Use Improvements in Support for Custom Messages


The most-improved feature of JavaServer Faces 1.2 technology is the ability to add custom messages to a JavaServer Faces application. The improvements in this area include the following:

A new set of standard converter messages

New
requiredMessage
,
converterMessage
, and
validatorMessage
attributes for input components

A new
label
attribute for input components, allowing the name of the component to be included in an error message

A new
resource-bundle
element for registering resource bundles with an application

Set of Standard Converter Messages

Prior versions of JavaServer Faces technology included a set of standard error messages to accompany the standard validators. Version 1.2 also includes a set of messages for the standard converters. To see the entire list of messages, refer to section 2.5.2.4 of the specification.

New
requiredMessage
,
converterMessage
, and
validatorMessage
Attributes


In most cases, a standard error message meets your needs. When it does not, you can override it with your own custom messages by using the
requiredMessage
,
converterMessage
, or
validatorMessage
attributes of your input component.

This new feature allows you to override a message when you want to. For example, let's say you are using the length validator on the
userid
and
password
fields. You want to have one message that says
Userid must be 9 characters
and another that says
Password must be 9 characters
, but you want to use the same validator for each. With the
validatorMessage
attribute, you can set these separate messages on the appropriate components rather than associating one message with every instance of a particular validator.

These attributes accept literal values as well as value expressions, as do most JavaServer Faces tag attributes. Therefore, you can use a value expression to reference a message contained in a resource bundle, as this example shows:

<h:inputText value="#{customer.userID}"
validatorMessage="#{customMessages.userIdMessage}" >
<f:validateLongRange minimum="9" maximum="9"/>
</h:inputText>

As you might have guessed, the value of an input component's
requiredMessage
attribute overrides the default message for the required validation failure. The value of an input component's
converterMessage
attribute overrides the default message of the converter registered on the input component. Likewise, the value of an input component's
validatorMessage
attribute overrides the default message of the validator registered on the input component.

Because of this feature, page authors can now provide error messages that are more tailored to the component using it. Thus, the user can more easily determine the source of the error.

A New
label
Attribute for Input Components


Another feature that helps users decipher error messages is the new
label
attribute for input components. Most standard error messages include substitution parameters that take the name of the component that produced the error. The value of an input component's
label
attribute is substituted at the start of the appropriate default message. For example, the following message is associated with the
DATE_ID
message identifier of
DateTimeConverter
:

{2}: "{0}" could not be understood as a date.

Say that you have a
DateTimeConverter
instance registered on a text-field component, and you set the input component's
label
attribute to
Birth Date
. If the user enters
older than the hills
into the text field, the conversion will fail. When the page is rendered again, the user will see the following error message:

Birth Date: "older than the hills" could not be understood as a date.

The
label
component accepts both literal and value expressions. So, as with most other JavaServer Faces tag attributes, you can use an expression to reference the name of the component from a resource bundle.

New
resource-bundle
Configuration Element


Prior to version 1.2 of JavaServer Faces technology, page authors used the
loadBundle
tag to load a resource bundle into a page in order to reference localized data from a page. Page authors can still load resource bundles into a page using this method in version 1.2.

A new, more efficient way of loading resource bundles involves registering a resource bundle with the entire application by using a
resource-bundle
element in the application's configuration file. The following
resource-bundle
element registers a
ResourceBundle
class named
CustomMessages
, which is in the
resources
package.

<resource-bundle>
<var>customMessages</var>
<base-name>resources.CustomMessages</base-name>
</resource-bundle>

The
var
child element defines the name that page authors will use in expressions that reference the resource bundle, as shown here:

<h:outputText value="#{customMessages.myText}" />

In this example,
myText
is the key that maps to the message in the resource bundle.

With the new
resource-bundle
element, you can load any number of resource bundles into the entire application. Not only does this new element eliminate the need to add a
loadBundle
tag to multiple pages, but it also has significant performance benefits because loading a resource bundle is an expensive operation.

Improved State-Saving Behavior


Version 1.2 of JavaServer Faces technology contains two major changes to the state-management facility. One change involves rectifying problems with application state becoming disoriented when an application uses multiple frames or windows. The other change is providing the option to secure state on the client.

The cause of the disoriented application state in multiframe or multiwindow applications was that these multiple logical views within the root view often would have duplicate IDs and would therefore confuse the state-management facility. Several changes to the state-management API in version 1.2 solve this problem.

First, each window or frame within a view now has a unique ID, which is a combination of the view root's ID and a random number that is saved into a hidden field in the form associated with the window or frame. The
writeState
method of
ViewHandler
has been modified to generate the unique ID and write it out to the client during the life cycle's render response phase. Additionally, the
encodeEnd
method
UIForm
has been modified to call
writeState
before writing out the markup for the closing tag of the form so that state for multiple forms can be saved.

Also during the life cycle's render response
 phase, the newly modified 
saveSerializedView
method of
StateManager
uses the unique ID to store the serialized view in the session. For example, if the server crashes, the saved state can be replicated to another server. Therefore, the state-saving mechanism now supports high availability. Finally, the
restoreView
method of
ViewHandler
now uses the unique ID to identify the view to restore during the life cycle's restore view
 phase.

The other major improvement to state saving allows you to encrypt client-side state before including it in the rendered markup that is sent to the client. You can choose to encrypt client-side state by using the
ClientStateSavingPassword
environment entry, as shown here:

<env-entry>
<env-entry-name>
com.sun.faces.ClientStateSavingPassword
</env-entry-name>
<env-entry-value>somePassword</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>

The password that you provide is used to generate keys and cyphers for encryption. If this environment entry is not present in your configuration file, no encryption will occur.

Ability to Turn Off Generation of Component Client IDs


JavaServer Faces technology uses an algorithm to generate client IDs for components included in a form. In prior versions, these components' client IDs looked like this:

[form ID]:[clientID]

Page authors had the option of specifying a client ID for a form component and for any of the other components included in the form. If the page author did not specify a form's client ID or a component's client ID, the implementation would generate them automatically.

Earlier versions of JavaServer Faces technology did not specify this algorithm well enough for developers to understand how it worked. Furthermore, a custom component or renderer class had no easy way to determine whether the page author had set a component's client ID or the implementation had automatically generated it. Finally, an author of custom renderers might not be able to change the name of the form for one reason or another but might still need to reference its components with JavaScript technology.

This release of JavaServer Faces technology includes a more explicit explanation of the algorithm that generates the client ID. You can find it primarily in the API documentation for
UIComponent
. The algorithm has also changed with the addition of the
prependId
attribute on the
UIForm
component. Page authors can now change the value of this attribute from the default of
true
to
false
to indicate that the form ID should not be a prefix of the component ID. Table 1 shows the different possibilities for generated client IDs in the most common scenarios.

Table 1: Client ID Generation Scenarios

Scenario
prependId==true
prependID==false
Page author sets no client IDs.
_id0:_id1

_id1

Page author sets the form client ID only.
myForm:_id0

_id0

Page author sets the component client ID only.
_id0:myComponent

myComponent

Page author sets client IDs of both the form and the component.
myForm:myComponent

myComponent

New
setPropertyActionListener
Tag



In addition to the
actionListener
tag that allows you register a custom action listener onto a component, the core tag library now includes the
setPropertyActionListener
tag. You use this tag to register a special action listener onto the
ActionSource
instance associated with a component. When the component is activated, the listener will store the object referenced by the tag's
value
attribute into the object referenced by the tag's
target
attribute.

To illustrate this tag's usefulness, let's suppose you have a
forEach
tag that includes a
commandButton
tag and iterates over a list of books, as shown here:

<c:forEach items="#{bookDBAO.books}" var="book" varStatus="stat">
<c:set var="book" scope="request" value="${book}"/>
...
<h:commandButton id="add" action="#{catalog.add}"
value="#{bundle.CartAdd}">
<f:setPropertyActionListener
target="#{requestScope.book}"
value="#{book}"/>
</h:commandButton>
<c:remove var="book" scope="request"/>
</c:forEach>

When the user clicks the button represented by the
commandButton
tag, the current book is added to the shopping cart, and the next page of the application displays.

If you are familiar with JSTL, you know that the
var
attribute of the
forEach
tag is always in
page
scope. However, the book data must be in
request
scope so that the page that displays after the user has clicked the button has access to the book data. Therefore, the
setPropertyActionListener
tag is used to set the current book object into
request
scope when the user activates the button.

In this case, the
setPropertyActionListener
tag's
value
attribute references the book object. The
setPropertyActionListener
tag's
target
attribute references the value expression
requestScope.book
, which is where the book object referenced by the attribute is stored when the user clicks the button associated with the
commandButton
component.

Conclusion


This article demonstrates that JavaServer Faces 1.2 technology offers plenty of valuable new features and includes solutions to many long-standing problems. We encourage you to give version 1.2 a try. If you have any questions or comments, please write or join us at the forum or in our public IRC chat room. In the meantime, watch for the next article in the series, which will describe resource injection on the web tier.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐