Spring Webflow Reference
Spring Webflow Reference
Keith Donald
Erwin Vervaet
Jeremy Grelle
Scott Andrews
Rossen Stoyanchev
Version 2.0.9
Published
Copies of this document may be made for your own use and for distribution to others, provided that you do not
charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether
distributed in print or electronically.
Table of Contents
Preface ................................................................................................................................. vii
1. Introduction ....................................................................................................................... 1
1.1. What this guide covers ........................................................................................... 1
1.2. What Web Flow requires to run ............................................................................. 1
1.3. Where to get support .............................................................................................. 1
1.4. Where to follow development ................................................................................ 1
1.5. How to access Web Flow artifacts from Maven Central ....................................... 1
1.6. How to access Web Flow artifacts from the SpringSource Bundle Repository .... 2
1.7. How to access nightly builds ................................................................................. 4
2. Defining Flows .................................................................................................................. 7
2.1. Introduction ............................................................................................................ 7
2.2. What is a flow? ...................................................................................................... 7
2.3. What is the makeup of a typical flow? ................................................................... 8
2.4. How are flows authored? ....................................................................................... 8
2.5. Essential language elements .................................................................................. 9
2.6. Actions ................................................................................................................. 10
2.7. Input/Output Mapping ......................................................................................... 12
2.8. Variables .............................................................................................................. 14
2.9. Calling subflows .................................................................................................. 14
3. Expression Language (EL) ............................................................................................. 17
3.1. Introduction .......................................................................................................... 17
3.2. Supported EL implementations ............................................................................ 17
3.3. EL portability ....................................................................................................... 17
3.4. EL usage ............................................................................................................... 17
3.5. Special EL variables ............................................................................................ 19
3.6. Scope searching algorithm ................................................................................... 21
4. Rendering views .............................................................................................................. 23
4.1. Introduction .......................................................................................................... 23
4.2. Defining view states ............................................................................................. 23
4.3. Specifying view identifiers .................................................................................. 23
4.4. View scope ........................................................................................................... 24
4.5. Executing render actions ...................................................................................... 25
4.6. Binding to a model ............................................................................................... 25
4.7. Performing type conversion ................................................................................. 26
4.8. Suppressing binding ............................................................................................. 27
4.9. Specifying bindings explicitly ............................................................................. 27
4.10. Validating a model ............................................................................................. 28
4.11. Suppressing validation ....................................................................................... 30
4.12. Executing view transitions ................................................................................. 31
4.13. Working with messages ..................................................................................... 32
4.14. Displaying popups ............................................................................................. 34
4.15. View backtracking ............................................................................................. 34
5. Executing actions ............................................................................................................ 35
5.1. Introduction .......................................................................................................... 35
Version 2.0.9 v
vi Spring Web Flow
Preface vii
Preface
Many web applications require the same sequence of steps to execute in different contexts. Often
these sequences are merely components of a larger task the user is trying to accomplish. Such a
reusable sequence is called a flow.
Consider a typical shopping cart application. User registration, login, and cart checkout are all
examples of flows that can be invoked from several places in this type of application.
Spring Web Flow is the module of Spring for implementing flows. The Web Flow engine plugs
into the Spring Web MVC platform and provides declarative flow definition language. This
reference guide shows you how to use and extend Spring Web Flow.
viii Preface
Introduction 1
1. Introduction
Report bugs and influence the Web Flow project roadmap using the Spring Issue Tracker.
Subscribe to the Spring Community Portal for the latest Spring news and announcements.
Visit the Web Flow Project Home for more resources on the project.
To access Web Flow jars from Maven Central, declare the following dependencies in your pom:
Version 2.0.9 1
2 Spring Web Flow
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-binding</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-js</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-faces</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<repository>
<id>com.springsource.repository.bundles.release</id>
<name>SpringSource Enterprise Bundle Repository - SpringSource Releases</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
<repository>
<id>com.springsource.repository.bundles.external</id>
<name>SpringSource Enterprise Bundle Repository - External Releases</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.binding</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
2 Introduction
Introduction 3
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.js</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.webflow</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.faces</artifactId>
<version>2.0.9.RELEASE</version>
</dependency>
Note the Web Flow artifacts in the SpringSource Bundle Repository are indexed under different
ids because their transitive dependencies are different than the Maven Central artifacts. The
difference is the transitive jars such as commons-logging have been patched by SpringSource to
add the metadata required to make them OSGi-compatible.
<url name="com.springsource.repository.bundles.release">
<ivy pattern="http://repository.springsource.com/ivy/bundles/release/
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/release/
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<url name="com.springsource.repository.bundles.external">
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/external/
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
Version 2.0.9 3
4 Spring Web Flow
A dm Server library for Web Flow is also available if you are deploying to a dm Server
environment. Import this library in your MANIFEST.mf to automatically import all Web Flow
bundles. To access the library, add the following repository:
<repository>
<id>com.springsource.repository.libraries.release</id>
<name>SpringSource Enterprise Bundle Repository - SpringSource Library Releases</name>
<url>http://repository.springsource.com/maven/libraries/release</url>
</repository>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.webflow-library</artifactId>
<type>libd</type>
<version>2.0.9.RELEASE</version>
</dependency>
If using Maven, you may obtain snapshots from either the SpringSource-managed Maven
Central-compatible repository or the SpringSource Enterprise Bundle Repository. Use the Maven
Central-compatible snapshot repository when your project obtains its other open source
dependencies from Maven Central. Use the Spring Source Enterprise Bundle Snapshot
Repository when you wish to run Web Flow in an OSGi environment.
<repository>
<id>org.springsource.maven.snapshot</id>
<name>SpringSource Maven Central-compatible Snapshot Repository</name>
<url>http://maven.springframework.org/snapshot</url>
</repository>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-binding</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
4 Introduction
Introduction 5
<artifactId>spring-js</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>spring-faces</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<repository>
<id>com.springsource.repository.bundles.snapshot</id>
<name>SpringSource Enterprise Bundle Snapshot Repository</name>
<url>http://repository.springsource.com/maven/bundles/snapshot</url>
</repository>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.binding</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.js</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.webflow</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.webflow</groupId>
<artifactId>org.springframework.faces</artifactId>
<version>x.y.z.BUILD-SNAPSHOT</version>
</dependency>
Version 2.0.9 5
6 Spring Web Flow
download area.
6 Introduction
Defining Flows 7
2. Defining Flows
2.1. Introduction
This chapter begins the Users Section. It shows how to implement flows using the flow
definition language. By the end of this chapter you should have a good understanding of
language constructs, and be capable of authoring a flow definition.
Version 2.0.9 7
8 Spring Web Flow
The example below shows the structure of the book hotel flow referenced in the previous
diagram:
Flow diagram
8 Defining Flows
Defining Flows 9
flow
Every flow begins with the following root element:
All states of the flow are defined within this element. The first state defined becomes the flow's
starting point.
view-state
Use the view-state element to define a step of the flow that renders a view:
By convention, a view-state maps its id to a view template in the directory where the flow is
located. For example, the state above might render
/WEB-INF/hotels/booking/enterBookingDetails.xhtml if the flow itself was
located in the /WEB-INF/hotels/booking directory.
transition
Use the transition element to handle events that occur within a state:
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
end-state
Use the end-state element to define a flow outcome:
Version 2.0.9 9
10 Spring Web Flow
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
<view-state id="reviewBooking">
<transition on="confirm" to="bookingConfirmed" />
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
<end-state id="bookingConfirmed" />
<end-state id="bookingCancelled" />
</flow>
2.6. Actions
Most flows need to express more than just view navigation logic. Typically they also need to
invoke business services of the application or other actions.
Within a flow, there are several points where you can execute actions. These points are:
• On flow start
• On state entry
• On view render
• On transition execution
• On state exit
• On flow end
Actions are defined using a concise expression language. Spring Web Flow uses the Unified EL
by default. The next few sections will cover the essential language elements for defining actions.
evaluate
10 Defining Flows
Defining Flows 11
The action element you will use most often is the evaluate element. Use the evaluate
element to evaluate an expression at a point within your flow. With this single tag you can
invoke methods on Spring beans or any other flow variable. For example:
If the expression returns a value, that value can be saved in the flow's data model called
flowScope:
If the expression returns a value that may need to be converted, specify the desired type using the
result-type attribute:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<input name="hotelId" />
<on-start>
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
result="flowScope.booking" />
</on-start>
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
<view-state id="reviewBooking">
<transition on="confirm" to="bookingConfirmed" />
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
<end-state id="bookingConfirmed" />
<end-state id="bookingCancelled" />
</flow>
This flow now creates a Booking object in flow scope when it starts. The id of the hotel to book
is obtained from a flow input attribute.
Version 2.0.9 11
12 Spring Web Flow
input
Use the input element to declare a flow input attribute:
Input values are saved in flow scope under the name of the attribute. For example, the input
above would be saved under the name hotelId.
If an input value does not match the declared type, a type conversion will be attempted.
Use the value attribute to specify an expression to assign the input value to:
If the expression's value type can be determined, that metadata will be used for type coersion if
no type attribute is specified.
12 Defining Flows
Defining Flows 13
Use the required attribute to enforce the input is not null or empty:
output
Use the output element to declare a flow output attribute. Output attributes are declared within
end-states that represent specific flow outcomes.
<end-state id="bookingConfirmed">
<output name="bookingId" />
</end-state>
Output values are obtained from flow scope under the name of the attribute. For example, the
output above would be assigned the value of the bookingId variable.
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<input name="hotelId" />
<on-start>
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
result="flowScope.booking" />
</on-start>
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
<view-state id="reviewBooking">
<transition on="confirm" to="bookingConfirmed" />
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
<end-state id="bookingConfirmed" >
<output name="bookingId" value="booking.id"/>
</end-state>
<end-state id="bookingCancelled" />
</flow>
The flow now accepts a hotelId input attribute and returns a bookingId output attribute
Version 2.0.9 13
14 Spring Web Flow
2.8. Variables
A flow may declare one or more instance variables. These variables are allocated when the flow
starts. Any @Autowired transient references the variable holds are also rewired when the flow
resumes.
var
Use the var element to declare a flow variable:
Make sure your variable's class implements java.io.Serializable, as the instance state
is saved between flow requests.
subflow-state
Use the subflow-state element to call another flow as a subflow:
The above example calls the createGuest flow, then waits for it to return. When the flow
returns with a guestCreated outcome, the new guest is added to the booking's guest list.
14 Defining Flows
Defining Flows 15
Simply refer to a subflow output attribute by its name within a outcome transition:
In the above example, guest is the name of an output attribute returned by the
guestCreated outcome.
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<input name="hotelId" />
<on-start>
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
result="flowScope.booking" />
</on-start>
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
<view-state id="reviewBooking">
<transition on="addGuest" to="addGuest" />
<transition on="confirm" to="bookingConfirmed" />
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
<subflow-state id="addGuest" subflow="createGuest">
<transition on="guestCreated" to="reviewBooking">
<evaluate expression="booking.guests.add(currentEvent.attributes.guest)" />
</transition>
<transition on="creationCancelled" to="reviewBooking" />
</subflow-state>
<end-state id="bookingConfirmed" >
<output name="bookingId" value="booking.id" />
</end-state>
<end-state id="bookingCancelled" />
</flow>
The flow now calls a createGuest subflow to add a new guest to the guest list.
Version 2.0.9 15
16 Spring Web Flow
16 Defining Flows
Expression Language (EL) 17
3.1. Introduction
Web Flow uses EL to access its data model and invoke actions. This chapter will familiarize you
with the EL syntax, and special EL variables you can reference from your flow definition.
Unified EL
Web Flow attempts to use the Unified EL by default. jboss-el is currently the default EL
implementation. When found in your classpath along with the el-api, it will be used
automatically. You can find the JBoss EL jar in the SpringSource Bundle Repository.
Note
The el-api dependency is typically provided by your web container. Tomcat 6
includes it, for example.
OGNL
OGNL is the other EL supported by Web Flow 2. OGNL is the EL most familiar to Web Flow
version 1.0 users. To use ognl, simply include ognl in your classpath instead of jboss-el.
Please refer to the OGNL language guide for specifics on its EL syntax.
3.3. EL portability
In general, you will find the Unified EL and OGNL have a very similar syntax. For basic
variable resolution, property access, and method invocation the syntax is identical. We
recommend adhering to Unified EL syntax whenever possible, and only relying on proprietary
EL features when needed.
3.4. EL usage
EL is used for many things within a flow, including:
1. Accessing data provided by the client, such as flow input attributes and request parameters.
Version 2.0.9 17
18 Spring Web Flow
4. Resolving constructs such as state transition criteria, subflow ids, and view names.
Views rendered by flows typically access flow data structures using EL as well.
Expression types
There are basically two types of expressions in Web Flow.
The first, and most common, type of expression, is the standard eval expression. Such
expressions are dynamically evaluated by the EL and should not be enclosed in delimiters like
${} or #{}. For example:
The expression above is a standard expression that invokes the nextPage method on the
searchCriteria variable when evaluated. Attempting to enclose this expression in special
eval delimiters like ${} or #{} will result in an IllegalArgumentException.
Note
We view use of special eval delimiters as redundant in this context, as the only
acceptable value for the expression attribute is a single eval expression string.
Template expressions
The second type of expression is a "template" expression. Such expressions allow a mixing of
literal text with one or more eval blocks. Each eval block is explictly delimited with the ${}
delimiters. For example:
The expression above is a template expression. The result of evaluation will be a string that
concatenates the literal text error- with the result of evaluating
externalContext.locale. As you can see, explicit delimiters are necessary here to
demarcate eval blocks within the template.
See the Web Flow XML schema for a complete listing of the XML attributes that accept
standard expressions and template expressions.
flowScope
Use flowScope to assign a flow variable. Flow scope gets allocated when a flow starts and
destroyed when the flow ends. With the default implementation, any objects stored in flow scope
need to be Serializable.
viewScope
Use viewScope to assign a view variable. View scope gets allocated when a view-state
enters and destroyed when the state exits. View scope is only referenceable from within a
view-state. With the default implementation, any objects stored in view scope need to be
Serializable.
<on-render>
<evaluate expression="searchService.findHotels(searchCriteria)" result="viewScope.hotels"
result-type="dataModel" />
</on-render>
requestScope
Use requestScope to assign a request variable. Request scope gets allocated when a flow is
called and destroyed when the flow returns.
flashScope
Use flashScope to assign a flash variable. Flash scope gets allocated when a flow starts,
cleared after every view render, and destroyed when the flow ends. With the default
implementation, any objects stored in flash scope need to be Serializable.
conversationScope
Version 2.0.9 19
20 Spring Web Flow
requestParameters
Use requestParameters to access a client request parameter:
currentEvent
Use currentEvent to access attributes of the current Event:
currentUser
Use currentUser to access the authenticated Principal:
messageContext
Use messageContext to access a context for retrieving and creating flow execution
messages, including error and success messages. See the MessageContext Javadocs for more
information.
resourceBundle
Use resourceBundle to access a message resource.
flowRequestContext
Use flowRequestContext to access the RequestContext API, which is a representation
of the current flow request. See the API Javadocs for more information.
flowExecutionContext
Use flowExecutionContext to access the FlowExecutionContext API, which is a
representation of the current flow state. See the API Javadocs for more information.
flowExecutionUrl
Use flowExecutionUrl to access the context-relative URI for the current flow execution
view-state.
externalContext
Use externalContext to access the client environment, including user session attributes.
See the ExternalContext API JavaDocs for more information.
<evaluate expression="searchService.suggestHotels(externalContext.sessionMap.userProfile)"
result="viewScope.hotels" />
When simply accessing a variable in one of the scopes, referencing the scope is optional. For
example:
If no scope is specified, like in the use of booking above, a scope searching algorithm will be
employed. The algorithm will look in request, flash, view, flow, and conversation scope for the
variable. If no such variable is found, an EvaluationException will be thrown.
Version 2.0.9 21
22 Spring Web Flow
4. Rendering views
4.1. Introduction
This chapter shows you how to use the view-state element to render views within a flow.
<view-state id="enterBookingDetails">
<transition on="submit" to="reviewBooking" />
</view-state>
By convention, a view-state maps its id to a view template in the directory where the flow is
located. For example, the state above might render
/WEB-INF/hotels/booking/enterBookingDetails.xhtml if the flow itself was
located in the /WEB-INF/hotels/booking directory.
Below is a sample directory structure showing views and other resources like message bundles
co-located with their flow definition:
Flow Packaging
Version 2.0.9 23
24 Spring Web Flow
Use the view attribute to specify the id of the view to render explicitly.
See the Spring MVC integration section for more information on how to integrate with the MVC
ViewResolver infrastructure.
24 Rendering views
Rendering views 25
Use the on-render tag to assign a variable from an action result before the view renders:
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels" />
</on-render>
<view-state id="searchResults">
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)"
result="viewScope.hotels" />
</on-render>
<transition on="next">
<evaluate expression="searchCriteria.nextPage()" />
<render fragments="searchResultsFragment" />
</transition>
<transition on="previous">
<evaluate expression="searchCriteria.previousPage()" />
<render fragments="searchResultsFragment" />
</transition>
</view-state>
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels" />
</on-render>
Version 2.0.9 25
26 Spring Web Flow
The model may be an object in any accessible scope, such as flowScope or viewScope.
Specifying a model triggers the following behavior when a view event occurs:
1. View-to-model binding. On view postback, user input values are bound to model object
properties for you.
2. Model validation. After binding, if the model object requires validation that validation logic
will be invoked.
For a flow event to be generated that can drive a view state transition, model binding must
complete successfully. If model binding fails, the view is re-rendered to allow the user to revise
their edits.
Implementing a Converter
To implement your own Converter, implement the
org.springframework.binding.convert.converters.TwoWayConverter
interface. A convenient StringToObject base class has been provided to simplify the
implementation of this interface for converters that convert from a user input String to a
user-defined Object and back. Simply extend from this class and override these two methods:
toObject(String, Class) should convert from the input string to your object's type, and
toString(Object) should do the reverse.
The following example shows a Converter that converts from String to a MonetaryAmount for
working with currency values:
26 Rendering views
Rendering views 27
Registering a Converter
To install your own Converter or override any of the default Converters, extend from
org.springframework.binding.convert.service.DefaultConversionService
and override the addDefaultConverters() method. Use the
addConverter(Converter) method to register the primary Converter to use to convert
between two types, such as a String and a MonetaryAmount. Optionally use the
addConverter(String, Converter) method to register alternate converters for the
same type pair; for example, to support formatting a java.util.Date as a String in several
different ways.
Each alternate Converter is indexed by a unique converterId that can be referenced when
configuring a model binding. When no converter id is referenced explicitly by a binding, the
primary Converter between the two types is always used.
The ConversionService is the object Web Flow consults at runtime to lookup conversion
executors to convert from one type to another. There is generally one ConversionService per
application. See the System Setup section for documentation on how to configure an extended
ConversionService implementation that registers custom Converters to apply application-wide.
Also consult the Convert API documentation for more information.
Version 2.0.9 27
28 Spring Web Flow
<binder>
<binding property="creditCard" />
<binding property="creditCardName" />
<binding property="creditCardExpiryMonth" />
<binding property="creditCardExpiryYear" />
</binder>
<transition on="proceed" to="reviewBooking" />
<transition on="cancel" to="cancel" bind="false" />
</view-state>
If the binder element is not specified, all public properties of the model are eligible for binding
by the view. With the binder element specified, only the explicitly configured bindings are
allowed.
Each binding may also apply a converter to format the model property value for display in a
custom manner. If no converter is specified, the default converter for the model property's type
will be used.
In the example above, the shortDate converter is bound to the checkinDate and
checkoutDate properties. Custom converters may be registered with the application's
ConversionService.
Each binding may also apply a required check that will generate a validation error if the user
provided value is null on form postback:
In the example above, all of the bindings are required. If one or more blank input values are
bound, validation errors will be generated and the view will re-render with those errors.
28 Rendering views
Rendering views 29
Programmatic validation
There are two ways to perform model validation programatically. The first is to implement
validation logic in your model object. The second is to implement an external Validator.
Both ways provide you with a ValidationContext to record error messages and access
information about the current user.
Defining validation logic in your model object is the simplest way to validate its state. Once such
logic is structured according to Web Flow conventions, Web Flow will automatically invoke that
logic during the view-state postback lifecycle. Web Flow conventions have you structure model
validation logic by view-state, allowing you to easily validate the subset of model properties that
are editable on that view. To do this, simply create a public method with the name
validate${state}, where ${state} is the id of your view-state where you want
validation to run. For example:
Any number of validation methods are defined. Generally, a flow edits a model over a series of
views. In that case, a validate method would be defined for each view-state where validation
needs to run.
Implementing a Validator
The second way is to define a separate object, called a Validator, which validates your model
object. To do this, first create a class whose name has the pattern ${model}Validator, where
Version 2.0.9 29
30 Spring Web Flow
${model} is the capitialized form of the model expression, such as booking. Then define a
public method with the name validate${state}, where ${state} is the id of your
view-state, such as enterBookingDetails. The class should then be deployed as a Spring
bean. Any number of validation methods can be defined. For example:
@Component
public class BookingValidator {
public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
MessageContext messages = context.getMessageContext();
if (booking.getCheckinDate().before(today())) {
messages.addMessage(new MessageBuilder().error().source("checkinDate").
defaultText("Check in date must be a future date").build());
} else if (!booking.getCheckinDate().before(booking.getCheckoutDate())) {
messages.addMessage(new MessageBuilder().error().source("checkoutDate").
defaultText("Check out date must be later than check in date").build());
}
}
}
A Validator can also accept a Spring MVC Errors object, which is required for invoking
existing Spring Validators.
ValidationContext
A ValidationContext allows you to obtain a MessageContext to record messages during
validation. It also exposes information about the current user, such as the signaled userEvent
and the current user's Principal identity. This information can be used to customize
validation logic based on what button or link was activated in the UI, or who is authenticated.
See the API Javadocs for ValidationContext for more information.
In this example, data binding will still occur on back but validation will be suppressed.
30 Rendering views
Rendering views 31
Transition actions
A view-state transition can execute one or more actions before executing. These actions may
return an error result to prevent the transition from exiting the current view-state. If an error
result occurs, the view will re-render and should display an appropriate message to the user.
If the transition action invokes a plain Java method, the invoked method may return false to
prevent the transition from executing. This technique can be used to handle exceptions thrown by
service-layer methods. The example below invokes an action that calls a service and handles an
exceptional situation:
Note
When there is more than one action defined on a transition, if one returns an error
result the remaining actions in the set will not be executed. If you need to ensure one
transition action's result cannot impact the execution of another, define a single
transition action that invokes a method that encapsulates all the action logic.
Global transitions
Use the flow's global-transitions element to create transitions that apply across all
views. Global-transitions are often used to handle global menu links that are part of the layout.
Version 2.0.9 31
32 Spring Web Flow
<global-transitions>
<transition on="login" to="login" />
<transition on="logout" to="logout" />
</global-transitions>
Event handlers
From a view-state, transitions without targets can also be defined. Such transitions are called
"event handlers":
<transition on="event">
<!-- Handle event -->
</transition>
These event handlers do not change the state of the flow. They simply execute their actions and
re-render the current view or one or more fragments of the current view.
Rendering fragments
Use the render element within a transition to request partial re-rendering of the current view
after handling the event:
<transition on="next">
<evaluate expression="searchCriteria.nextPage()" />
<render fragments="searchResultsFragment" />
</transition>
The fragments attribute should reference the id(s) of the view element(s) you wish to re-render.
Specify multiple elements to re-render by separating them with a comma delimiter.
Such partial rendering is often used with events signaled by Ajax to update a specific zone of the
view.
32 Rendering views
Rendering views 33
context.addMessage(builder.error().source("checkinDate")
.defaultText("Check in date must be a future date").build());
context.addMessage(builder.warn().source("smoking")
.defaultText("Smoking is bad for your health").build());
context.addMessage(builder.info()
.defaultText("We have processed your reservation - thank you and enjoy your stay").build());
#messages.properties
checkinDate=Check in date must be a future date
notHealthy={0} is bad for your health
reservationConfirmation=We have processed your reservation - thank you and enjoy your stay
From within a view or a flow, you may also access message resources using the
resourceBundle EL variable:
booking.checkinDate.typeMismatch
Version 2.0.9 33
34 Spring Web Flow
The first part of the key is the model class's short name. The second part of the key is the
property name. The third part is the error code. This allows for the lookup of a unique message to
display to the user when a binding fails on a model property. Such a message might say:
If no such resource key can be found of that form, a more generic key will be tried. This key is
simply the error code. The field name of the property is provided as a message argument.
When using Web Flow with the Spring Javascript, no client side code is necessary for the popup
to display. Web Flow will send a response to the client requesting a redirect to the view from a
popup, and the client will honor the request.
Discarding history
Set the history attribute to discard to prevent backtracking to a view:
Invalidating history
Set the history attribute to invalidate to prevent backtracking to a view as well all
previously displayed views:
34 Rendering views
Executing actions 35
5. Executing actions
5.1. Introduction
This chapter shows you how to use the action-state element to control the execution of an
action at a point within a flow. It will also show how to use the decision-state element to
make a flow routing decision. Finally, several examples of invoking actions from the various
points possible within a flow will be discussed.
<action-state id="moreAnswersNeeded">
<evaluate expression="interview.moreAnswersNeeded()" />
<transition on="yes" to="answerQuestions" />
<transition on="no" to="finish" />
</action-state>
The full example below illustrates a interview flow that uses the action-state above to determine
if more answers are needed to complete the interview:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<on-start>
<evaluate expression="interviewFactory.createInterview()" result="flowScope.interview" />
</on-start>
<view-state id="answerQuestions" model="questionSet">
<on-entry>
<evaluate expression="interview.getNextQuestionSet()" result="viewScope.questionSet" />
</on-entry>
<transition on="submitAnswers" to="moreAnswersNeeded">
<evaluate expression="interview.recordAnswers(questionSet)" />
</transition>
</view-state>
<action-state id="moreAnswersNeeded">
<evaluate expression="interview.moreAnswersNeeded()" />
<transition on="yes" to="answerQuestions" />
<transition on="no" to="finish" />
</action-state>
<end-state id="finish" />
</flow>
Version 2.0.9 35
36 Spring Web Flow
<decision-state id="moreAnswersNeeded">
<if test="interview.moreAnswersNeeded()" then="answerQuestions" else="finish" />
</decision-state>
This is illustrated in the example action state below, which invokes a method that returns a
boolean value:
<action-state id="moreAnswersNeeded">
<evaluate expression="interview.moreAnswersNeeded()" />
<transition on="yes" to="answerQuestions" />
<transition on="no" to="finish" />
</action-state>
36 Executing actions
Executing actions 37
Version 2.0.9 37
38 Spring Web Flow
on-start
The following example shows an action that creates a new Booking object by invoking a method
on a service:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<input name="hotelId" />
38 Executing actions
Executing actions 39
<on-start>
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
result="flowScope.booking" />
</on-start>
</flow>
on-entry
The following example shows a state entry action that sets the special fragments variable that
causes the view-state to render a partial fragment of its view:
on-exit
The following example shows a state exit action that releases a lock on a record being edited:
<view-state id="editOrder">
<on-entry>
<evaluate expression="orderService.selectForUpdate(orderId, currentUser)"
result="viewScope.order" />
</on-entry>
<transition on="save" to="finish">
<evaluate expression="orderService.update(order, currentUser)" />
</transition>
<on-exit>
<evaluate expression="orderService.releaseLock(order, currentUser)" />
</on-exit>
</view-state>
on-end
The following example shows the equivalent object locking behavior using flow start and end
actions:
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<input name="orderId" />
<on-start>
<evaluate expression="orderService.selectForUpdate(orderId, currentUser)"
result="flowScope.order" />
</on-start>
<view-state id="editOrder">
<transition on="save" to="finish">
<evaluate expression="orderService.update(order, currentUser)" />
</transition>
</view-state>
<on-end>
<evaluate expression="orderService.releaseLock(order, currentUser)" />
</on-end>
</flow>
Version 2.0.9 39
40 Spring Web Flow
on-render
The following example shows a render action that loads a list of hotels to display before the view
is rendered:
<view-state id="reviewHotels">
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)"
result="viewScope.hotels" result-type="dataModel" />
</on-render>
<transition on="select" to="reviewHotel">
<set name="flowScope.hotel" value="hotels.selectedRow" />
</transition>
</view-state>
on-transition
The following example shows a transition action adds a subflow outcome event attribute to a
collection:
Named actions
The following example shows how to execute a chain of actions in an action-state. The name of
each action becomes a qualifier for the action's result event.
<action-state id="doTwoThings">
<evaluate expression="service.thingOne()">
<attribute name="name" value="thingOne" />
</evaluate>
<evaluate expression="service.thingTwo()">
<attribute name="name" value="thingTwo" />
</evaluate>
<transition on="thingTwo.success" to="showResults" />
</action-state>
In this example, the flow will transition to showResults when thingTwo completes
successfully.
Streaming actions
Sometimes an Action needs to stream a custom response back to the client. An example might be
a flow that renders a PDF document when handling a print event. This can be achieved by having
the action stream the content then record "Response Complete" status on the ExternalContext.
The responseComplete flag tells the pausing view-state not to render the response because
another object has taken care of it.
40 Executing actions
Executing actions 41
<view-state id="reviewItinerary">
<transition on="print">
<evaluate expression="printBoardingPassAction" />
</transition>
</view-state>
In this example, when the print event is raised the flow will call the printBoardingPassAction.
The action will render the PDF then mark the response as complete.
package org.springframework.webflow.samples.booking;
import org.springframework.web.multipart.MultipartFile;
public class FileUploadHandler {
private transient MultipartFile file;
public void processFile() {
//Do something with the MultipartFile here
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
you can process the upload using a transition action as in the following example:
Version 2.0.9 41
42 Spring Web Flow
The MultipartFile will be bound to the FileUploadHandler bean as part of the normal
form binding process so that it will be available to process during the execution of the transition
action.
42 Executing actions
Flow Managed Persistence 43
6.1. Introduction
Most applications access data in some way. Many modify data shared by multiple users and
therefore require transactional data access properties. They often transform relational data sets
into domain objects to support application processing. Web Flow offers "flow managed
persistence" where a flow can create, commit, and close a object persistence context for you.
Web Flow integrates both Hibernate and JPA object persistence technologies.
Then configure the correct FlowExecutionListener to apply this pattern to your flow. If
using Hibernate, register the HibernateFlowExecutionListener. If using JPA, register
the JpaFlowExecutionListener.
Version 2.0.9 43
44 Spring Web Flow
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<bean id="jpaFlowExecutionListener"
class="org.springframework.webflow.persistence.JpaFlowExecutionListener">
<constructor-arg ref="entityManagerFactory" />
<constructor-arg ref="transactionManager" />
</bean>
To trigger a commit at the end, annotate your end-state with the commit attribute:
That is it. When your flow starts, the listener will handle allocating a new EntityManager in
flowScope. Reference this EntityManager at anytime from within your flow by using the
special persistenceContext variable. In addition, any data access that occurs using a
Spring managed data access object will use this EntityManager automatically. Such data access
operations should always execute non transactionally or in read-only transactions to maintain
isolation of intermediate edits.
7. Securing Flows
7.1. Introduction
Security is an important concept for any application. End users should not be able to access any
portion of a site simply by guessing the URL. Areas of a site that are sensitive must ensure that
only authorized requests are processed. Spring Security is a proven security platform that can
integrate with your application at multiple levels. This section will focus on securing flow
execution.
• Annotate the flow definition with the secured element to define the security rules
Each of these steps must be completed or else flow security rules will not be applied.
Three phases of flow execution can be secured: flows, states and transitions. In each case the
syntax for the secured element is identical. The secured element is located inside the element it is
securing. For example, to secure a state the secured element occurs directly inside that state:
<view-state id="secured-view">
<secured attributes="ROLE_USER" />
...
</view-state>
Security attributes
The attributes attribute is a comma separated list of Spring Security authorization
attributes. Often, these are specific security roles. The attributes are compared against the user's
granted attributes by a Spring Security access decision manager.
Version 2.0.9 45
46 Spring Web Flow
By default, a role based access decision manager is used to determine if the user is allowed
access. This will need to be overridden if your application is not using authorization roles.
Matching type
There are two types of matching available: any and all. Any, allows access if at least one of
the required security attributes is granted to the user. All, allows access only if each of the
required security attributes are granted to the user.
The match attribute will only be respected if the default access decision manager is used.
<bean id="securityFlowExecutionListener"
class="org.springframework.webflow.security.SecurityFlowExecutionListener">
<property name="accessDecisionManager" ref="myCustomAccessDecisionManager" />
46 Securing Flows
Securing Flows 47
</bean>
Both the booking-faces and booking-mvc sample applications are configured to use
Spring Security. Configuration is needed at both the Spring and web.xml levels.
Spring configuration
The Spring configuration defines http specifics (such as protected URLs and login/logout
mechanics) and the authentication-provider. For the sample applications, a local
authentication provider is configured.
<security:http auto-config="true">
<security:form-login login-page="/spring/login"
login-processing-url="/spring/loginProcess"
default-target-url="/spring/main"
authentication-failure-url="/spring/login?login_error=1" />
<security:logout logout-url="/spring/logout" logout-success-url="/spring/logout-success" />
</security:http>
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:user-service>
<security:user name="keith" password="417c7382b16c395bc25b5da1398cf076"
authorities="ROLE_USER,ROLE_SUPERVISOR" />
<security:user name="erwin" password="12430911a8af075c6f41c6976af22b09"
authorities="ROLE_USER,ROLE_SUPERVISOR" />
<security:user name="jeremy" password="57c6cbff0d421449be820763f03139eb"
authorities="ROLE_USER" />
<security:user name="scott" password="942f2339bf50796de535a384f0d1af3e"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
web.xml Configuration
In the web.xml file, a filter is defined to intercept all requests. This filter will listen for
login/logout requests and process them accordingly. It will also catch
AccesDeniedExceptions and redirect the user to the login page.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Version 2.0.9 47
48 Spring Web Flow
48 Securing Flows
Flow Inheritance 49
8. Flow Inheritance
8.1. Introduction
Flow inheritance allows one flow to inherit the configuration of another flow. Inheritance can
occur at both the flow and state levels. A common use case is for a parent flow to define global
transitions and exception handlers, then each child flow can inherit those settings.
In order for a parent flow to be found, it must be added to the flow-registry just like any
other flow.
A child flow cannot override an element from a parent flow. Similar elements between the parent
and child flows will be merged. Unique elements in the parent flow will be added to the child.
A child flow can inherit from multiple parent flows. Java inheritance is limited to a single class.
Unlike flow inheritance, only a single parent is allowed. Additionally, the identifier of the flow
state to inherit from must also be defined. The identifiers for the flow and the state within that
flow are separated by a #.
Version 2.0.9 49
50 Spring Web Flow
The parent and child states must be of the same type. For instance a view-state cannot inherit
from an end-state, only another view-state.
<flow abstract="true">
There are two types of elements: mergeable and non-mergeable. Mergeable elements will always
attempt to merge together if the elements are similar. Non-mergeable elements in a parent or
child flow will always be contained in the resulting flow intact. They will not be modified as part
of the merge process.
Note
Paths to external resources in the parent flow should be absolute. Relative paths will
break when the two flows are merged unless the parent and child flow are in the same
directory. Once merged, all relative paths in the parent flow will become relative to
the child flow.
Mergeable Elements
If the elements are of the same type and their keyed attribute are identical, the content of the
parent element will be merged with the child element. The merge algorithm will continue to
merge each sub-element of the merging parent and child. Otherwise the parent element is added
as a new element to the child.
In most cases, elements from a parent flow that are added will be added after elements in the
child flow. Exceptions to this rule include action elements (evaluate, render and set) which will
be added at the beginning. This allows for the results of parent actions to be used by child
actions.
50 Flow Inheritance
Flow Inheritance 51
• action-state: id
• attribute: name
• decision-state: id
• end-state: id
• if: test
• input: name
• output: name
• secured: attributes
• subflow-state: id
• view-state: id
Non-mergeable Elements
Non-mergeable elements are:
• bean-import
• evaluate
• exception-handler
• persistence-context
• render
Version 2.0.9 51
52 Spring Web Flow
• set
• var
52 Flow Inheritance
System Setup 53
9. System Setup
9.1. Introduction
This chapter shows you how to setup the Web Flow system for use in any web environment.
9.2. webflow-config.xsd
Web Flow provides a Spring schema that allows you to configure the system. To use this
schema, include it in one of your infrastructure-layer beans files:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
<!-- Setup Web Flow here -->
</beans>
FlowRegistry
Register your flows in a FlowRegistry:
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>
FlowExecutor
Deploy a FlowExecutor, the central service for executing flows:
See the Spring MVC and Spring Faces sections of this guide on how to integrate the Web Flow
Version 2.0.9 53
54 Spring Web Flow
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml">
<flow-definition-attributes>
<attribute name="caption" value="Books a hotel" />
</flow-definition-attributes>
</webflow:flow-location>
54 System Setup
System Setup 55
Use the base-path attribute to define a base location for all flows in the application. All flow
locations are then relative to the base path. The base path can be a resource path such as
'/WEB-INF' or a location on the classpath like
'classpath:org/springframework/webflow/samples'.
With a base path defined, the algorithm that assigns flow identifiers changes slightly. Flows will
now be assigned registry identifiers equal to the the path segment between their base path and
file name. For example, if a flow definition is located at
'/WEB-INF/hotels/booking/booking-flow.xml' and the base path is '/WEB-INF' the remaining
path to this flow is 'hotels/booking' which becomes the flow id.
If no base path is not specified or if the flow definition is directly on the base path, flow id
assignment from the filename (minus the extension) is used. For example, if a flow definition file
is 'booking.xml', the flow identifier is simply 'booking'.
Location patterns are particularly powerful when combined with a registry base path. Instead of
the flow identifiers becoming '*-flow', they will be based on the directory path. For example:
Version 2.0.9 55
56 Spring Web Flow
<webflow:flow-builder-services id="flowBuilderServices"
conversion-service="conversionService"
expression-parser="expressionParser"
view-factory-creator="viewFactoryCreator" />
<bean id="conversionService" class="..." />
<bean id="expressionParser" class="..." />
<bean id="viewFactoryCreator" class="..." />
conversion-service
expression-parser
view-factory-creator
The configurable settings are development. These settings are global configuration attributes
that can be applied during the flow construction process.
56 System Setup
System Setup 57
development
Set this to true to switch on flow development mode. Development mode switches on
hot-reloading of flow definition changes, including changes to dependent flow resources such as
message bundles.
<flow-execution-listeners>
<listener ref="securityListener"/>
<listener ref="persistenceListener"/>
</flow-execution-listeners>
max-executions
Tune the max-executions attribute to place a cap on the number of flow executions that can
be created per user session.
max-execution-snapshots
Version 2.0.9 57
58 Spring Web Flow
58 System Setup
Spring MVC Integration 59
10.1. 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.
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.
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-application-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>
Version 2.0.9 59
60 Spring Web Flow
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.
• HTTP request parameters are made available in the input map of all starting flow executions.
• When a flow execution ends without sending a final response, the default handler will attempt
to start a new execution in the same request.
Consult the API documentation for FlowHandlerAdapter for more information. You may
override these defaults by subclassing or by implementing your own FlowHandler, discussed in
the next section.
• Creating the input to pass new executions of that flow as they are started
• 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 itself with a specific controller URL. An example FlowHandler that redirects to a
Spring MVC Controller is shown below:
Version 2.0.9 61
62 Spring Web Flow
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.
With this configuration, accessing the resource /hotels/booking will launch the
hotels/booking flow using the custom BookingFlowHandler. 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.
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"
The MvcViewFactoryCreator is the factory that allows you to configure how the Spring MVC
view system is used inside Spring Web Flow. Use it to configure existing ViewResolvers, as
well as other services such as a custom MessageCodesResolver. You may also enable data
binding use Spring MVC's native BeanWrapper by setting the useSpringBinding flag to
true. This is an alternative to using OGNL or the Unified EL for view-to-model data binding. See
the JavaDoc API of this class for more information.
When a button is pressed Web Flow finds a request parameter name beginning with
_eventId_ and treats the remaining substring as the event id. So in this example, submitting
Version 2.0.9 63
64 Spring Web Flow
_eventId_proceed becomes proceed. This style should be considered when there are
several different events that can be signaled from the same form.
Here, Web Flow simply detects the special _eventId parameter and uses its value as the event
id. This style should only be considered when there is one event that can be signaled on the form.
<a href="${flowExecutionUrl}&_eventId=cancel">Cancel</a>
Firing an event results in a HTTP request being sent back to the server. On the server-side, the
flow handles decoding the event from within its current view-state. How this decoding process
works is specific to the view implementation. Recall a Spring MVC view implementation simply
looks for a request parameter named _eventId. If no _eventId parameter is found, the view
will look for a parameter that starts with _eventId_ and will use the remaining substring as
the event id. If neither cases exist, no flow event is triggered.
11.1. Introduction
Spring Javascript (spring-js) is a lightweight abstraction over common JavaScript toolkits such as
Dojo. It aims to provide a common client-side programming model for progressively enhancing a
web page with rich widget behavior and Ajax remoting.
Use of the Spring JS API is demonstrated in the the Spring MVC + Web Flow version of the
Spring Travel reference application. In addition, the JSF components provided as part of the
Spring Faces library build on Spring.js.
<!-- Serves static resource content from .jar files such as spring-js.jar -->
<servlet>
<servlet-name>Resource Servlet</servlet-name>
<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
</servlet>
<!-- Map all /resources requests to the Resource Servlet for handling -->
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
Using Spring Javascript in a page requires including the underlying toolkit as normal, the
Spring.js base interface file, and the Spring-(library implementation).js file
for the underlying toolkit. As an example, the following includes obtain the Dojo implementation
of Spring.js using the ResourceServlet:
When using the widget system of an underlying library, typically you must also include some
Version 2.0.9 65
66 Spring Web Flow
CSS resources to obtain the desired look and feel. For the booking-mvc reference application,
Dojo's tundra.css is included:
The following example illustrates enhancing a Spring MVC <form:input> tag with rich
suggestion behavior:
The ElementDecoration is used to apply rich widget behavior to an existing DOM node.
This decoration type does not aim to completely hide the underlying toolkit, so the toolkit's
native widget type and attributes are used directly. This approach allows you to use a common
decoration model to integrate any widget from the underlying toolkit in a consistent manner. See
the booking-mvc reference application for more examples of applying decorations to do
things from suggestions to client-side validation.
When using the ElementDecoration to apply widgets that have rich validation behavior, a
common need is to prevent the form from being submitted to the server until validation passes.
This can be done with the ValidateAllDecoration:
This decorates the "Proceed" button with a special onclick event handler that fires the client side
validators and does not allow the form to submit until they pass successfully.
</script>
This decorates the onclick event of the "Previous Results" link with an Ajax call, passing along a
special parameter that specifies the fragment to be re-rendered in the response. Note that this link
would still be fully functional if Javascript was unavailable in the client. (See the section on
Handling Ajax Requests for details on how this request is handled on the server.)
It is also possible to apply more than one decoration to an element. The following example
shows a button being decorated with Ajax and validate-all submit suppression:
It is also possible to apply a decoration to multiple elements in a single statement using Dojo's
query API. The following example decorates a set of checkbox elements as Dojo Checkbox
widgets:
<div id="amenities">
<form:checkbox path="amenities" value="OCEAN_VIEW" label="Ocean View" /></li>
<form:checkbox path="amenities" value="LATE_CHECKOUT" label="Late Checkout" /></li>
<form:checkbox path="amenities" value="MINIBAR" label="Minibar" /></li>
<script type="text/javascript">
dojo.query("#amenities input[type='checkbox']").forEach(function(element) {
Spring.addDecoration(new Spring.ElementDecoration({
elementId: element.id,
widgetType : "dijit.form.CheckBox",
widgetAttrs : { checked : element.checked }
}));
});
</script>
</div>
In order to be able to render partial fragments of a full response, the full response must be built
using a templating technology that allows the use of composition for constructing the response,
and for the member parts of the composition to be referenced and rendered individually. Spring
Javascript provides some simple Spring MVC extensions that make use of Tiles to achieve this.
The same technique could theoretically be used with any templating system supporting
composition.
Spring Javascript's Ajax remoting functionality is built upon the notion that the core handling
code for an Ajax request should not differ from a standard browser request, thus no special
knowledge of an Ajax request is needed directly in the code and the same hanlder can be used for
both styles of request.
Version 2.0.9 67
68 Spring Web Flow
Version 2.0.9 69
70 Spring Web Flow
12.1. Introduction
Spring Faces is Spring's JSF integration module that simplifies using JSF with Spring. It lets you
use the JSF UI Component Model with Spring MVC and Spring Web Flow controllers.
Spring Faces also includes a small Facelets component library that provides Ajax and client-side
validation capabilities. This component library builds on Spring Javascript, a Javascript
abstraction framework that integrates Dojo as the underlying UI toolkit.
Spring Faces provides a powerful supplement to a number of the standard JSF facilities,
including:
2. scope management
3. event handling
4. navigation rules
6. cleaner URLs
7. model-level validation
Version 2.0.9 71
72 Spring Web Flow
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-application-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>
In order for JSF to bootstrap correctly, the FacesServlet must be configured in web.xml as
it normally would even though you generally will not need to route requests through it at all
when using Spring Faces.
<!-- Just here so the JSF implementation can initialize, *not* used at runtime -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Just here so the JSF implementation can initialize -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
When using the Spring Faces components, you also need to configure the Spring JavaScript
ResourceServlet so that CSS and JavaScript resources may be output correctly by the
components. This servlet must be mapped to /resources/* in order for the URL's rendered by the
components to function correctly.
<!-- Serves static resource content from .jar files such as spring-faces.jar -->
<servlet>
<servlet-name>Resource Servlet</servlet-name>
<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- Map all /resources requests to the Resource Servlet for handling -->
<servlet-mapping>
<servlet-name>Resource Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
The Spring Faces components require the use of Facelets instead of JSP, so the typical Facelets
configuration must be added as well when using these components.
72 JSF Integration
JSF Integration 73
!-- Use JSF view templates saved as *.xhtml, for use with Facelets -->
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
For optimal page-loading performance, the Spring Faces component library includes a few
special components: includeStyles and includeScripts. These components will
eagerly load the neccessary CSS stylesheets and JavaScript files at the position they are placed in
your JSF view template. In accordance with the recommendations of the Yahoo Performance
Guildlines, these two tags should be placed in the head section of any page that uses the Spring
Faces components. For example:
This shows the opening of a typical Facelets XHTML layout template that uses these
components to force the loading of the needed CSS and JavaScript resources at the ideal
position.
The includeStyles component includes the necessary resources for the Dojo widget theme.
By default, it includes the resources for the "tundra" theme. An alternate theme may be selected
by setting the optional "theme" and "themePath" attributes on the includeStyles
component. For example:
will try to load a CSS stylesheet at "/styles/foobar/foobar.css" using the Spring JavaScript
ResourceServlet.
Version 2.0.9 73
74 Spring Web Flow
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
http://www.springframework.org/schema/faces
http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">
<!-- Executes flows: the central entry point into the Spring Web Flow system -->
<webflow:flow-executor id="flowExecutor" />
<!-- The registry of executable flow definitions -->
<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="/WEB-INF">
<webflow:flow-location-pattern value="**/*-flow.xml" />
</webflow:flow-registry>
<!-- Configures the Spring Web Flow JSF integration -->
<faces:flow-builder-services id="facesFlowBuilderServices" />
</beans>
See the swf-booking-faces reference application in the distribution for a complete working
example.
<faces-config>
<application>
<!-- Enables Facelets -->
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config>
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.
74 JSF Integration
JSF Integration 75
What is really needed is a managed scope that is somewhere between request and session scope.
Fortunately web flow provides such extended facilities.
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:
<view-state id="enterSearchCriteria">
<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>
</view-state>
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.
Version 2.0.9 75
76 Spring Web Flow
<on-render>
<evaluate expression="bookingService.findBookings(currentUser.name)"
result="viewScope.bookings" result-type="dataModel" />
</on-render>
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:
<transition on="cancelBooking">
<evaluate expression="bookingService.cancelBooking(bookings.selectedRow)" />
</transition>
76 JSF Integration
JSF Integration 77
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:
<view-state id="reviewHotels">
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)"
result="viewScope.hotels" result-type="dataModel" />
</on-render>
</view-state>
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:
<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>
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.
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:
Version 2.0.9 77
78 Spring Web Flow
This raises the "select" event which you can then handle by adding another transition
element to the existing view-state :
<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>
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 .
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:
<view-state id="enterBookingDetails">
<transition on="proceed" to="reviewBooking">
<evaluate expression="booking.validateEnterBookingDetails(messageContext)" />
</transition>
</view-state>
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,
78 JSF Integration
JSF Integration 79
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.
Note
Though the core JSF support in Spring Faces is JSF 1.1-compatible, the Spring Faces
Ajax components require JSF 1.2.
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:
<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>
An additional built-in feature when using the Spring Faces Ajax components is the ability to
have the response rendered inside a rich modal popup widget by setting popup="true" on a
view-state .
Version 2.0.9 79
80 Spring Web Flow
<sf:clientTextValidator required="true">
<h:inputText id="creditCardName" value="#{booking.creditCardName}" required="true"/>
</sf:clientTextValidator>
This will apply client-side required validation to the child inputText component, giving the
user a clear indicator if the field is left blank.
This will apply client-side validation to the child inputText component, giving the user a
clear indicator if the field is left blank, is not numeric, or does not match the given regular
expression.
80 JSF Integration
JSF Integration 81
This will apply client-side validation to the child inputText component, giving the user a
clear indicator if the field is left blank or is not a valid date.
<sf:validateAllOnClick>
<sf:commandButton id="proceed" action="proceed" processIds="*" value="Proceed"/> 
</sf:validateAllOnClick>
This will prevent the form from being submitted when the user clicks the "proceed" button if the
form is invalid. When the validations are executed, the user is given clear and immediate
indicators of the problems that need to be corrected.
<filter>
<display-name>RichFaces Filter</display-name>
Version 2.0.9 81
82 Spring Web Flow
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<servlet-name>Spring Web MVC Dispatcher Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
For deeper integration (including the ability to have a view with combined use of the Spring
Faces Ajax components and Rich Faces Ajax components), configure the RichFacesAjaxHandler
on your FlowController:
RichFaces Ajax components can be used in conjunction with the render tag to render partial
fragments on an Ajax request. Instead of embedding the ids of the components to be re-rendered
directly in the view template (as you traditionally do with Rich Faces), you can bind the
reRender attribute of a RichFaces Ajax component to a special flowRenderFragments
EL variable. For example, in your view template you can have a fragment that you would
potentially like to re-render in response to a particular event:
<h:form id="hotels">
<a4j:outputPanel id="searchResultsFragment">
<h:outputText id="noHotelsText" value="No Hotels Found" rendered="#{hotels.rowCount == 0}"/>
<h:dataTable id="hotels" styleClass="summary" value="#{hotels}" var="hotel" rendered="#{hotels.rowCount > 0}">
<h:column>
<f:facet name="header">Name</f:facet>
#{hotel.name}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
#{hotel.address}
</h:column>
</h:dataTable>
</a4j:outputPanel>
</h:form>
<transition on="next">
<evaluate expression="searchCriteria.nextPage()" />
<render fragments="hotels:searchResultsFragment" />
</transition>
82 JSF Integration
JSF Integration 83
The Apache MyFaces Trinidad library has been tested with the Spring Faces integration and
proven to fit in nicely. Deeper integration to allow the Trinidad components and Spring Faces
components to play well together has not yet been attempted, but Trinidad provides a pretty
thorough solution on its own when used in conjunction with the Spring Faces integration layer.
Typical Trinidad + Spring Faces configuration is as follows in web.xml (in addition to the
typical Spring Faces configuration):
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>
org.apache.myfaces.trinidad.CHANGE_PERSISTENCE
</param-name>
<param-value>session</param-value>
</context-param>
<context-param>
<param-name>
org.apache.myfaces.trinidad.ENABLE_QUIRKS_MODE
</param-name>
<param-value>false</param-value>
</context-param>
<filter>
<filter-name>Trinidad Filter</filter-name>
<filter-class>
org.apache.myfaces.trinidad.webapp.TrinidadFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>Trinidad Filter</filter-name>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>Trinidad Resource Servlet</servlet-name>
<servlet-class>
org.apache.myfaces.trinidad.webapp.ResourceServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resources</servlet-name>
<url-pattern>/adf/*</url-pattern>
</servlet-mapping>
Version 2.0.9 83
84 Spring Web Flow
84 JSF Integration
Portlet Integration 85
13.1. Introduction
This chapter shows how to use Web Flow in a Portlet environment. Web Flow has full support
for JSR-168 portlets. The booking-portlet-mvc sample application is a good reference for
using Web Flow within a portlet. This application is a simplified travel site that allows users to
search for and book hotel rooms.
In general, the configuration requires adding a servlet mapping in the web.xml file to dispatch
request to the portlet container.
<servlet>
<servlet-name>swf-booking-mvc</servlet-name>
<servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-name</param-name>
<param-value>swf-booking-mvc</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>swf-booking-mvc</servlet-name>
<url-pattern>/PlutoInvoker/swf-booking-mvc</url-pattern>
</servlet-mapping>
<portlet>
...
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/web-application-config.xml</value>
</init-param>
<init-param>
<name>viewRendererUrl</name>
<value>/WEB-INF/servlet/view</value>
</init-param>
<expiration-cache>0</expiration-cache>
...
</portlet>
Flow Handlers
The only supported mechanism for bridging a portlet request to Web Flow is a FlowHandler.
The PortletFlowController used in Web Flow 1.0 is no longer supported.
The flow handler, similar to the servlet flow handler, provides hooks that can:
• handle exceptions
In a portlet environment the targeted flow id can not be inferred from the URL and must be
defined explicitly in the handler.
Handler Mappings
Spring Portlet MVC provides a rich set of methods to map portlet requests. Complete
documentation is available in the Spring Reference Documentation.
<bean id="portletModeHandlerMapping"
class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<bean class="org.springframework.webflow.samples.booking.ViewFlowHandler" />
</entry>
</map>
</property>
</bean>
86 Portlet Integration
Portlet Integration 87
A FlowHandlerAdapter converts the handler mappings to the flow handlers. The flow
executor is required as a constructor argument.
<bean id="flowHandlerAdapter"
class="org.springframework.webflow.mvc.portlet.FlowHandlerAdapter">
<constructor-arg ref="flowExecutor" />
</bean>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
Window State
The Portlet API defined three window states: normal, minimized and maximized. The portlet
implementation must decide what to render for each of these window states. Web Flow exposes
the string value of the window state under portletWindowState via the request map on the
external context.
requestContext.getExternalContext().getRequestMap().get("portletWindowState");
externalContext.requestMap.portletWindowState
Portlet Mode
The Portlet API defined three portlet modes: view, edit and help. The portlet implementation
must decide what to render for each of these modes. Web Flow exposes the string value of the
portlet mode under portletMode via the request map on the external context.
requestContext.getExternalContext().getRequestMap().get("portletMode");
Version 2.0.9 87
88 Spring Web Flow
externalContext.requestMap.portletMode
Redirects
The Portlet API only allows redirects to be requested from an action request. Because views are
rendered on the render request, views and view-states cannot trigger a redirect.
One way to start a new flow is to create a URL targeting the mode without the execution key.
88 Portlet Integration
Testing flows 89
14.1. Introduction
This chapter shows you how to test flows.
@Override
protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
return resourceFactory.createFileResource("src/main/webapp/WEB-INF/hotels/booking/booking.xml");
}
@Override
protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
builderContext.registerBean("bookingService", new StubBookingService());
}
If your flow extends from another flow, or has states that extend other states, also override
getModelResources(FlowDefinitionResourceFactory) to return the path to the
parent flows.
@Override
protected FlowDefinitionResource[] getModelResources(FlowDefinitionResourceFactory resourceFactory) {
Version 2.0.9 89
90 Spring Web Flow
Assertions generally verify the flow is in the correct state you expect.
90 Testing flows
Testing flows 91
getFlowDefinitionRegistry().registerFlowDefinition(createMockBookingSubflow());
MockExternalContext context = new MockExternalContext();
context.setEventId("book");
resumeFlow(context);
// verify flow ends on 'bookingConfirmed'
assertFlowExecutionEnded();
assertFlowExecutionOutcomeEquals("finish");
}
public Flow createMockBookingSubflow() {
Flow mockBookingFlow = new Flow("booking");
mockBookingFlow.setInputMapper(new Mapper() {
public MappingResults map(Object source, Object target) {
// assert that 1L was passed in as input
assertEquals(1L, ((AttributeMap) source).get("hotelId"));
return null;
}
});
// immediately return the bookingConfirmed outcome so the caller can respond
new EndState(mockBookingFlow, "bookingConfirmed");
return mockBookingFlow;
}
Version 2.0.9 91
92 Spring Web Flow
92 Testing flows
Upgrading from 1.0 93
15.1. Introduction
This chapter shows you how to upgrade existing Web Flow 1 application to Web Flow 2.
The conversion tool requires spring-webflow.jar, spring-core.jar and an XSLT 1.0 engine. Saxon
6.5.5 is recommended.
The tool can be run from the command line with the following command. Required libraries
must be available on the classpath. The source must be a single flow to convert. The resulting
converted flow will be sent to standard output.
Version 2.0.9 93
94 Spring Web Flow
top-level flow. The inline flow's content has been converted for your convenience.
EL Expressions
EL expressions are used heavily throughout the flow definition language. Many of the attributes
that appear to be plain text are actually interpreted as EL. The standard EL delimiters (either ${}
or #{}) are not necessary and will often cause an exception if they are included.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
flow-executor
The flow executor is the core Web Flow configuration element. This element replaces previous
FlowExecutorFactoryBean bean definitions.
flow-execution-listeners
Flow execution listeners are also defined in the flow executor. Listeners are defined using
standard bean definitions and added by reference.
flow-registry
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/hotels/booking/booking.xml" />
</webflow:flow-registry>
Flow Controller
The package name for flow controllers has changed from
org.springframework.webflow.executor.mvc.FlowController and is now
org.springframework.webflow.mvc.servlet.FlowController for Servlet
MVC requests. The portlet flow controller
org.springframework.webflow.executor.mvc.PortletFlowController has
been replaced by a flow handler adapter available at
org.springframework.webflow.mvc.portlet.FlowHandlerAdapter. They
Version 2.0.9 95
96 Spring Web Flow
View Resolution
Web Flow 2 by default will both select and render views. View were previously selected by Web
Flow 1 and then rendered by an external view resolver.
In order for version 1 flows to work in Web Flow 2 the default view resolver must be overridden.
A common use case is to use Apache Tiles for view resolution. The following configuration will
replace the default view resolver with a Tiles view resolver. The tilesViewResolver in this
example can be replaced with any other view resolver.
OGNL vs EL
Web Flow 1 used OGNL exclusively for expressions within the flow definitions. Web Flow 2
adds support for Unified EL. United EL is used when it is available, OGNL will continue to be
used when a Unified EL implementation is not available. Please see the Expression Language
chapter for details.
Flash Scope
Flash scope in Web Flow 1 lived across the current request and into the next request. This was
conceptually similar to Web Flow 2's view scope concept, but the semantics were not as well
defined. In Web Flow 2, flash scope is cleared after every view render. This makes flashScope
semantics in Web Flow consistent with other web frameworks.
Spring Faces
Web Flow 2 offers significantly improved integration with JavaServerFaces. Please see the JSF
Integration chapter for details.
External Redirects
External redirects in Web Flow 1 were always considered context relative. In Web Flow 2, if the
redirect URL begins with a slash, it is considered servlet-relative instead of context-relative.
URLs without a leading slash are still context relative.
Version 2.0.9 97
98 Spring Web Flow