Spring Faces docs
This commit is contained in:
399
spring-webflow-reference/src/spring-faces.xml
Normal file
399
spring-webflow-reference/src/spring-faces.xml
Normal file
@@ -0,0 +1,399 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="spring-faces">
|
||||
<title>Using Spring Faces</title>
|
||||
|
||||
<sect1 id="spring-faces-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Spring Faces is Spring's JSF integration module that ships with the Spring Web Flow 2.0 distribution and
|
||||
aims to simplify the programming model for using JSF with Spring. It provides support for using JSF in a
|
||||
Spring-centric environment using Spring MVC and Spring Web Flow for control flow and event handling.
|
||||
</para>
|
||||
<para>
|
||||
It includes a lightweight Facelets component library that focuses on providing rich client-side behavior and
|
||||
Ajax support through the use of progressive enhancement. The client-side functionality of the component
|
||||
library is provided by Spring JavaScript, an integration layer that aims to be agnostic to the underlying
|
||||
client-side JavaScript toolkit. Spring Faces also aims to ensure that other JSF component libraries
|
||||
integrate smoothly with Spring Web Flow, for the cases where a more desktop-like UI is desired as opposed to
|
||||
the lightweight approach of the Spring Faces components.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="spring-faces-integration">
|
||||
<title>Spring-centric Integration Approach</title>
|
||||
<para>
|
||||
Spring Faces aims to emphasize the strengths of JSF (i.e, its component model and EL binding) while
|
||||
providing an alternative controller model that addresses many of its traditional weaknesses. Spring Faces
|
||||
requests are routed through the Spring MVC DispatcherServlet instead of the FacesServlet, and the JSF
|
||||
lifecycle is executed within the context of the current flow execution. Whereas pure JSF requests are
|
||||
essentially driven by the current JSF view in a pull-oriented fashion, routing through the Spring
|
||||
infrastructure allows for more flexible request processing with many well-defined extension points for
|
||||
initialization and manipulation of the model and event-handling mechanisms that enable a reduced dependence
|
||||
on the JSF API.
|
||||
</para>
|
||||
<para>
|
||||
Spring Faces provides a powerful supplement to a number of the standard JSF facilities, including:
|
||||
<orderedlist>
|
||||
<listitem>managed bean facility</listitem>
|
||||
<listitem>scope management</listitem>
|
||||
<listitem>event handling</listitem>
|
||||
<listitem>navigation rules</listitem>
|
||||
<listitem>easy modularization and packaging of views</listitem>
|
||||
<listitem>cleaner URLs</listitem>
|
||||
<listitem>model-level validation</listitem>
|
||||
<listitem>client-side validation and UI enhancement</listitem>
|
||||
<listitem>Ajax partial page updates and full navigation</listitem>
|
||||
<listitem>progressive enhancement and graceful degradation</listitem>
|
||||
</orderedlist>
|
||||
Using these features will significantly reduce the amount of configuration required in faces-config.xml
|
||||
while providing a cleaner separation between the view and controller layer and better modularization of your
|
||||
application's functional responsibilities. These use of these features are outlined in the sections to
|
||||
follow. As the majority of these features build on the flow definition language of Spring Web Flow, it is
|
||||
assumed that you have an understanding of the foundations presented in
|
||||
<link linkend="defining-flows">Defining Flows</link>
|
||||
.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="spring-faces-managed-beans">
|
||||
<title>Replacing the JSF Managed Bean Facility</title>
|
||||
<para>
|
||||
Spring Faces allows you to completely replace the JSF managed bean facility with a combination of
|
||||
flow-managed variables and Spring managed beans. It gives you a good deal more control over the lifecycle of
|
||||
your managed objects with well-defined hooks for initialization and execution of your domain model.
|
||||
Additionally, since you are presumably already using Spring for your business layer, it reduces the
|
||||
conceptual overhead of having to maintain two different managed bean models.
|
||||
</para>
|
||||
<para>
|
||||
In doing pure JSF development, you will quickly find that request scope is not long-lived enough for storing
|
||||
conversational model objects that drive complex event-driven views. The only available option is to begin
|
||||
putting things into session scope, with the extra burden of needing to clean the objects up before
|
||||
progressing to another view or functional area of the application. What is really needed is a managed scope
|
||||
that is somewhere between request and session scope. Fortunately web flow provides such extended facilities.
|
||||
</para>
|
||||
<sect2 id="spring-faces-flow-variables">
|
||||
<title>Using Flow Variables</title>
|
||||
<para>
|
||||
The easiest and most natural way to declare and manage the model is through the use of
|
||||
<link linkend="flow-variables">flow variables</link>
|
||||
. You can declare these variables at the beginning of the flow:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>]]>
|
||||
</programlisting>
|
||||
<para>and then reference this variable in one of the flow's JSF view templates through EL:</para>
|
||||
<programlisting language="xhtml"><![CDATA[
|
||||
<h:inputText id="searchString" value="#{searchCriteria.searchString}"/>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
Note that you do not need to prefix the variable with its scope when referencing it from the template
|
||||
(though you can do so if you need to be more specific). As with standard JSF beans, all available scopes
|
||||
will be searched for a matching variable, so you could change the scope of the variable in your flow
|
||||
definition without having to modify the EL expressions that reference it.
|
||||
</para>
|
||||
<para>
|
||||
You can also define view instance variables that are scoped to the current view and get cleaned up
|
||||
automatically upon transitioning to another view. This is quite useful with JSF as views are often
|
||||
constructed to handle multiple in-page events across many requests before transitioning to another view.
|
||||
</para>
|
||||
<para>
|
||||
To define a view instance variable, you can use the
|
||||
<code>var</code>
|
||||
element inside a
|
||||
<code>view-state</code>
|
||||
definition:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<view-state id="enterSearchCriteria">
|
||||
<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
<sect2 id="spring-faces-spring-beans">
|
||||
<title>Using Scoped Spring Beans</title>
|
||||
<para>
|
||||
Though defining autowired flow instance variables provides nice modularization and readability,
|
||||
occasions may arise where you want to utilize the other capabilities of the Spring container such as
|
||||
AOP. In these cases, you can define a bean in your Spring ApplicationContext and give it a specific web
|
||||
flow scope:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<bean id="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria" scope="flow"/>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
The major difference with this approach is that the bean will not be fully initialized until it is first
|
||||
accessed via an EL expression. This sort of lazy instantiation via EL is quite similar to how JSF
|
||||
managed beans are typically allocated.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Manipulating The Model</title>
|
||||
<para>
|
||||
The need to initialize the model before view rendering (such as by loading persistent entities from a
|
||||
database) is quite common, but JSF by itself does not provide any convenient hooks for such
|
||||
initialization. The flow definition language provides a natural facility for this through its
|
||||
<link linkend="flow-actions">Actions</link>
|
||||
. Spring Faces provides some extra conveniences for converting the outcome of an action into a
|
||||
JSF-specific data structure. For example:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findBookings(currentUser.name)"
|
||||
result="viewScope.bookings" result-type="dataModel" />
|
||||
</on-render>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
This will take the result of the
|
||||
<code>bookingService.findBookings</code>
|
||||
method an wrap it in a custom JSF DataModel so that the list can be used in a standard JSF DataTable
|
||||
component:
|
||||
</para>
|
||||
<programlisting language="xhtml"><![CDATA[
|
||||
<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking" rendered="#{bookings.rowCount > 0}">
|
||||
<h:column>
|
||||
<f:facet name="header">Name</f:facet>
|
||||
#{booking.hotel.name}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">Confirmation number</f:facet>
|
||||
#{booking.id}
|
||||
</h:column>
|
||||
<h:column>
|
||||
<f:facet name="header">Action</f:facet>
|
||||
<h:commandLink id="cancel" value="Cancel" action="cancelBooking" />
|
||||
</h:column>
|
||||
</h:dataTable>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
The custom DataModel provides some extra conveniences such as being serializable for storage beyond
|
||||
request scope and access to the currently selected row in EL expressions. For example, on postback from
|
||||
a view where the action event was fired by a component within a DataTable, you can take action on the
|
||||
selected row's model instance:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<transition on="cancelBooking">
|
||||
<evaluate expression="bookingService.cancelBooking(bookings.selectedRow)" />
|
||||
</transition>]]>
|
||||
</programlisting>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="spring-faces-event-handling">
|
||||
<title>Handling JSF Events With Spring Web Flow</title>
|
||||
<para>
|
||||
Spring Web Flow allows you to handle JSF action events in a decoupled way, requiring no direct dependencies
|
||||
in your Java code on JSF API's. In fact, these events can often be handled completely in the flow definiton
|
||||
language without requiring any custom Java action code at all. This allows for a more agile development
|
||||
process since the artifacts being manipulated in wiring up events (JSF view templates and SWF flow
|
||||
definitions) are instantly refreshable without requiring a build and re-deploy of the whole application.
|
||||
</para>
|
||||
<sect2 id="spring-faces-in-page-events">
|
||||
<title>Handling JSF In-page Action Events</title>
|
||||
<para>
|
||||
A simple but common case in JSF is the need to signal an event that causes manipulation of the model in
|
||||
some way and then redisplays the same view to reflect the changed state of the model. The flow
|
||||
definition language has special support for this in the
|
||||
<code>transition</code>
|
||||
element.
|
||||
</para>
|
||||
<para>
|
||||
A good example of this is a table of paged list results. Suppose you want to be able to load and display
|
||||
only a portion of a large result list, and allow the user to page through the results. The initial
|
||||
<code>view-state</code>
|
||||
definition to load and display the list would be:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<view-state id="reviewHotels">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)"
|
||||
result="viewScope.hotels" result-type="dataModel" />
|
||||
</on-render>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
You construct a JSF DataTable that displays the current
|
||||
<code>hotels</code>
|
||||
list, and then place a "More Results" link below the table:
|
||||
</para>
|
||||
<programlisting language="xhtml"><![CDATA[
|
||||
<h:commandLink id="nextPageLink" value="More Results" action="next"/>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
This commandLink signals a "next" event from its action attribute. You can then handle the event by
|
||||
adding to the
|
||||
<code>view-state</code>
|
||||
definition:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<view-state id="reviewHotels">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)"
|
||||
result="viewScope.hotels" result-type="dataModel" />
|
||||
</on-render>
|
||||
<transition on="next">
|
||||
<evaluate expression="searchCriteria.nextPage()" />
|
||||
</transition>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
Here you handle the "next" event by incrementing the page count on the searchCriteria instance. The
|
||||
<code>on-render</code>
|
||||
action is then called again with the updated criteria, which causes the next page of results to be
|
||||
loaded into the DataModel. The same view is re-rendered since there was no
|
||||
<code>to</code>
|
||||
attribute on the
|
||||
<code>transition</code>
|
||||
element, and the changes in the model are reflected in the view.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="spring-faces-action-events">
|
||||
<title>Handling JSF Action Events</title>
|
||||
<para>
|
||||
The next logical level beyond in-page events are events that require navigation to another view, with
|
||||
some manipulation of the model along the way. Achieving this with pure JSF would require adding a
|
||||
navigation rule to faces-config.xml and likely some intermediary Java code in a JSF managed bean (both
|
||||
tasks requiring a re-deploy). With the flow defintion language, you can handle such a case concisely in
|
||||
one place in a quite similar way to how in-page events are handled.
|
||||
</para>
|
||||
<para>
|
||||
Continuing on with our use case of manipulating a paged list of results, suppose we want each row in the
|
||||
displayed DataTable to contain a link to a detail page for that row instance. You can add a column to
|
||||
the table containing the following
|
||||
<code>commandLink</code>
|
||||
component:
|
||||
</para>
|
||||
<programlisting language="xhtml"><![CDATA[
|
||||
<h:commandLink id="viewHotelLink" value="View Hotel" action="select"/>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
This raises the "select" event which you can then handle by adding another
|
||||
<code>transition</code>
|
||||
element to the existing
|
||||
<code>view-state</code>
|
||||
:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<view-state id="reviewHotels">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)"
|
||||
result="viewScope.hotels" result-type="dataModel" />
|
||||
</on-render>
|
||||
<transition on="next">
|
||||
<evaluate expression="searchCriteria.nextPage()" />
|
||||
</transition>
|
||||
<transition on="select" to="reviewHotel">
|
||||
<set name="flowScope.hotel" value="hotels.selectedRow" />
|
||||
</transition>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
Here the "select" event is handled by pushing the currently selected hotel instance from the DataTable
|
||||
into flow scope, so that it may be referenced by the "reviewHotel"
|
||||
<code>view-state</code>
|
||||
.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="spring-faces-model-validation">
|
||||
<title>Performing Model Validation</title>
|
||||
<para>
|
||||
JSF provides useful facilities for validating input at field-level before changes are applied to the
|
||||
model, but when you need to then perform more complex validation at the model-level after the updates
|
||||
have been applied, you are generally left with having to add more custom code to your JSF action methods
|
||||
in the managed bean. Validation of this sort is something that is generally a responsibility of the
|
||||
domain model itself, but it is difficult to get any error messages propagated back to the view without
|
||||
introducing an undesirable dependency on the JSF API in your domain layer.
|
||||
</para>
|
||||
<para>
|
||||
With Spring Faces, you can utilize the generic and low-level
|
||||
<code>MessageContext</code>
|
||||
in your business code and any messages added there will then be available to the
|
||||
<code>FacesContext</code>
|
||||
at render time.
|
||||
</para>
|
||||
<para>
|
||||
For example, suppose you have a view where the user enters the necessary details to complete a hotel
|
||||
booking, and you need to ensure the Check In and Check Out dates adhere to a given set of business
|
||||
rules. You can invoke such model-level validation from a
|
||||
<code>transition</code>
|
||||
element:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<view-state id="enterBookingDetails">
|
||||
<transition on="proceed" to="reviewBooking">
|
||||
<evaluate expression="booking.validateEnterBookingDetails(messageContext)" />
|
||||
</transition>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
Here the "proceed" event is handled by invoking a model-level validation method on the booking instance,
|
||||
passing the generic
|
||||
<code>MessageContext</code>
|
||||
instance so that messages may be recorded. The messages can then be displayed along with any other JSF
|
||||
messages with the
|
||||
<code>h:messages</code>
|
||||
component,
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="spring-faces-ajax-events">
|
||||
<title>Handling Ajax Events</title>
|
||||
<para>
|
||||
Spring Faces provides some special
|
||||
<code>UICommand</code>
|
||||
components that go beyond the standard JSF components by adding the ability to do Ajax-based partial
|
||||
view updates. These components degrade gracefully so that the flow will still be fully functional by
|
||||
falling back to full page refreshes if a user with a less capable browser views the page.
|
||||
</para>
|
||||
<para>
|
||||
Revisiting the earlier example with the paged table, you can change the "More Results" link to use an
|
||||
Ajax request by replacing the standard
|
||||
<code>commandButton</code>
|
||||
with the Spring Faces version (note that the Spring Faces command components use Ajax by default, but
|
||||
they can alternately be forced to use a normal form submit by setting ajaxEnabled="false" on the
|
||||
component):
|
||||
</para>
|
||||
<programlisting language="xhtml"><![CDATA[
|
||||
<sf:commandLink id="nextPageLink" value="More Results" action="next" />]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
This event is handled just as in the non-Ajax case with the
|
||||
<code>transition</code>
|
||||
element, but now you will add a special
|
||||
<code>render</code>
|
||||
action that specifies which portions of the component tree need to be re-rendered:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
<view-state id="reviewHotels">
|
||||
<on-render>
|
||||
<evaluate expression="bookingService.findHotels(searchCriteria)"
|
||||
result="viewScope.hotels" result-type="dataModel" />
|
||||
</on-render>
|
||||
<transition on="next">
|
||||
<evaluate expression="searchCriteria.nextPage()" />
|
||||
<render fragments="hotels:searchResultsFragment" />
|
||||
</transition>
|
||||
</view-state>]]>
|
||||
</programlisting>
|
||||
<para>
|
||||
The
|
||||
<code>fragments="hotels:searchResultsFragment"</code>
|
||||
is an instruction that will be interpreted at render time, such that only the component with the JSF
|
||||
clientId "hotels:searchResultsFragment" will be rendered and returned to the client. This fragment will
|
||||
then be automatically replaced in the page. The
|
||||
<code>fragments</code>
|
||||
attribute can be a comma-delimited list of ids, with each id representing the root node of a subtree
|
||||
(meaning the root node and all of its children) to be rendered. If the "next" event is fired in a
|
||||
non-Ajax request (i.e., if JavaScript is disabled on the client), the
|
||||
<code>render</code>
|
||||
action will be ignored and the full page will be rendered as normal.
|
||||
</para>
|
||||
<para>
|
||||
In addition to the Spring Faces
|
||||
<code>commandLink</code>
|
||||
component, there is a corresponding
|
||||
<code>commandButton</code>
|
||||
component with the same functionality. There is also a special
|
||||
<code>ajaxEvent</code>
|
||||
component that will raise a JSF action even in response to any client-side DOM event. See the Spring
|
||||
Faces tag library docs for full details.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
Reference in New Issue
Block a user