From 54ba149619f63f1ff392cfe4c175a73b5885492f Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 8 Apr 2008 21:54:45 +0000 Subject: [PATCH] Spring Faces docs --- spring-webflow-reference/src/spring-faces.xml | 399 ++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 spring-webflow-reference/src/spring-faces.xml diff --git a/spring-webflow-reference/src/spring-faces.xml b/spring-webflow-reference/src/spring-faces.xml new file mode 100644 index 00000000..505a3922 --- /dev/null +++ b/spring-webflow-reference/src/spring-faces.xml @@ -0,0 +1,399 @@ + + + Using Spring Faces + + + Introduction + + 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. + + + 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. + + + + + Spring-centric Integration Approach + + 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. + + + Spring Faces provides a powerful supplement to a number of the standard JSF facilities, including: + + managed bean facility + scope management + event handling + navigation rules + easy modularization and packaging of views + cleaner URLs + model-level validation + client-side validation and UI enhancement + Ajax partial page updates and full navigation + progressive enhancement and graceful degradation + + 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 + Defining Flows + . + + + + Replacing the JSF Managed Bean Facility + + 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. + + + 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. + + + Using Flow Variables + + The easiest and most natural way to declare and manage the model is through the use of + flow variables + . You can declare these variables at the beginning of the flow: + + ]]> + + and then reference this variable in one of the flow's JSF view templates through EL: + ]]> + + + 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. + + + 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. + + + To define a view instance variable, you can use the + var + element inside a + view-state + definition: + + + +]]> + + + + Using Scoped Spring Beans + + 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: + + ]]> + + + 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. + + + + Manipulating The Model + + 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 + Actions + . Spring Faces provides some extra conveniences for converting the outcome of an action into a + JSF-specific data structure. For example: + + + +]]> + + + This will take the result of the + bookingService.findBookings + method an wrap it in a custom JSF DataModel so that the list can be used in a standard JSF DataTable + component: + + 0}"> + + Name + #{booking.hotel.name} + + + Confirmation number + #{booking.id} + + + Action + + +]]> + + + 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: + + + +]]> + + + + + Handling JSF Events With Spring Web Flow + + 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. + + + Handling JSF In-page Action Events + + 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 + transition + element. + + + 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 + view-state + definition to load and display the list would be: + + + + + +]]> + + + You construct a JSF DataTable that displays the current + hotels + list, and then place a "More Results" link below the table: + + ]]> + + + This commandLink signals a "next" event from its action attribute. You can then handle the event by + adding to the + view-state + definition: + + + + + + + + +]]> + + + Here you handle the "next" event by incrementing the page count on the searchCriteria instance. The + on-render + 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 + to + attribute on the + transition + element, and the changes in the model are reflected in the view. + + + + Handling JSF Action Events + + 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. + + + 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 + commandLink + component: + + ]]> + + + This raises the "select" event which you can then handle by adding another + transition + element to the existing + view-state + : + + + + + + + + + + + +]]> + + + 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" + view-state + . + + + + Performing Model Validation + + 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. + + + With Spring Faces, you can utilize the generic and low-level + MessageContext + in your business code and any messages added there will then be available to the + FacesContext + at render time. + + + 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 + transition + element: + + + + + +]]> + + + Here the "proceed" event is handled by invoking a model-level validation method on the booking instance, + passing the generic + MessageContext + instance so that messages may be recorded. The messages can then be displayed along with any other JSF + messages with the + h:messages + component, + + + + Handling Ajax Events + + Spring Faces provides some special + UICommand + 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. + + + Revisiting the earlier example with the paged table, you can change the "More Results" link to use an + Ajax request by replacing the standard + commandButton + 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): + + ]]> + + + This event is handled just as in the non-Ajax case with the + transition + element, but now you will add a special + render + action that specifies which portions of the component tree need to be re-rendered: + + + + + + + + + +]]> + + + The + fragments="hotels:searchResultsFragment" + 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 + fragments + 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 + render + action will be ignored and the full page will be rendered as normal. + + + In addition to the Spring Faces + commandLink + component, there is a corresponding + commandButton + component with the same functionality. There is also a special + ajaxEvent + 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. + + + +