Spring MVC Integration
Introduction
This chapter shows how to integrate Web Flow into a Spring MVC web application.
The booking-mvc sample application is a good reference for Spring MVC with Web Flow.
This application is a simplified travel site that allows users to search for and book hotel rooms.
Configuring web.xml
The first step to using Spring MVC is to configure the DispatcherServlet in web.xml.
You typically do this once per web application.
The example below maps all requests that begin with /spring/ to the DispatcherServlet.
An init-param is used to provide the contextConfigLocation.
This is the configuration file for the web application.
Spring MVC Dispatcher Servlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
/WEB-INF/web-application-config.xml
Spring MVC Dispatcher Servlet
/spring/*
]]>
Dispatching to flows
The DispatcherServlet maps requests for application resources to handlers.
A flow is one type of handler.
The first step to dispatching requests to flows is to enable flow handling within Spring MVC.
To this, install the FlowHandlerAdapter:
]]>
Once flow handling is enabled, the next step is to map specific application resources to your flows.
The simplest way to do this is to define a FlowIdHandlerMapping
]]>
Configuring this mapping allows the Dispatcher to map application resource paths to flows in a flow registry.
For example, accessing the resource path /hotels/booking would result in a registry query for the flow with id hotels/booking.
If a flow is found with that id, that flow will handle the request.
If no flow is found, the next handler mapping in the Dispatcher's ordered chain will be queried or a "noHandlerFound" response will be returned.
Implementing custom FlowHandlers
A FlowHandler manages the execution of a single flow definition in a servlet environment.
A FlowHandler is responsible for:
Providing the id of the flow definition to execute
Creating the input to pass new flow executions
Handling flow execution outcomes
Handling flow execution exceptions
These responsibilities are illustrated in the definition of the org.springframework.mvc.servlet.FlowHandler interface:
public interface FlowHandler {
public String getFlowId();
public MutableAttributeMap createExecutionInputMap(HttpServletRequest request);
public String handleExecutionOutcome(FlowExecutionOutcome outcome,
HttpServletRequest request, HttpServletResponse response);
public String handleException(FlowException e,
HttpServletRequest request, HttpServletResponse response);
}
To implement a FlowHandler, subclass AbstractFlowHandler. You only need to override the methods that you need.
Specifically:
Override getFlowId(HttpServletRequest) when the id of your flow cannot be derived from the URL.
By default, the flow id is derived from the last path element in the request URI, before any query parameters.
For example, http://localhost/hotels/booking?hotelId=1 results in a flow id of booking by default.
Override createExecutionInputMap(HttpServletRequest) when you need fine-grained control over extracting
flow input parameters from the HttpServletRequest. By default, all request parameters are treated as flow input parameters.
Override handleExecutionOutcome when you need to handle specific flow execution outcomes in a custom manner.
The default behavior sends a redirect to the ended flow's URL to restart a new execution of the flow.
Override handleException when you need fine-grained control over unhandled flow exceptions.
The default behavior attempts to restart the flow when a client attempts to access an ended or expired flow execution.
Any other exception is rethrown to the Spring MVC ExceptionResolver infrastructure by default.
Example FlowHandler
A common interaction pattern between Spring MVC And Web Flow is for a Flow to redirect to a Controller when it ends.
FlowHandlers allow this to be done without coupling the flow definition with a specific controller URL.
An example FlowHandler that redirects to a Spring MVC Controller is shown below:
Since this handler only needs to handle flow execution outcomes in a custom manner, nothing else is overridden.
The bookingConfirmed outcome will result in a redirect to show the new booking.
Any other outcome will redirect back to the hotels index page.
To use your FlowHandler, first deploy an instance to Spring so it can be mapped to a URL:
]]>
With this configuration, accessing the URL /hotels/booking will launch the hotels/booking flow.
When the booking flow ends, the FlowHandler will process the flow execution outcome and redirect to the appropriate controller.
FlowHandler Redirects
A FlowHandler handling a FlowExecutionOutcome or FlowException returns a String to indicate the resource to redirect to after handling.
In the previous example, the BookingFlowHandler redirects to the booking/show resource URI for bookingConfirmed outcomes,
and the hotels/index resource URI for all other outcomes.
By default, returned resource locations are relative to the current servlet mapping.
This allows for a flow handler to redirect to other Controllers in the application using relative paths.
In addition, explicit redirect prefixes are supported for cases where more control is needed.
The explicit redirect prefixes supported are:
servletRelative: - redirect to a resource relative to the current servlet
contextRelative: - redirect to a resource relative to the current web application context path
serverRelative: - redirect to a resource relative to the server root
http:// or https:// - redirect to a fully-qualified resource URI
These same redirect prefixes are also supported within a flow definition when using the externalRedirect: directive in
conjunction with a view-state or end-state; for example, view="externalRedirect:http://springframework.org"
View Resolution
Web Flow 2 maps selected view identifiers to files located within the flow's working directory unless otherwise specified.
For existing Spring MVC + Web Flow applications, an external ViewResolver is likely already handling this mapping for you.
Therefore, to continue using that resolver and to avoid having to change how your existing flow views are packaged, configure Web Flow as follows:
]]>