Spring Web Flow – Concepts [Part 1]
In this post we will see the major concepts relates to Spring web flow. Spring flow is an approach to implement multi page flow web applications like shopping portal. For example in shopping portal application a user may involve in the below steps.
- Login to the application
- Surf among the products
- Add needed products to the cart
- view/edit cart if needed
- Click checkout
- Provide contact information
- Payment
- End
As there are multiple pages involved in the shopping flow, the data needs to be carried throughout multiple pages. If we handle this task manually it will be tedious task. We will go out of our indented business logic. To implement these kinds of tasks easily Spring provides the web flow framework.
A flow is nothing but a set of tasks to be done in a particular order. In webflow it is an xml file which tells the exactly how this flow should works. If we configure our application flow in spring web flow, the data carrying portion as well as the page navigation issues will be taken care by spring web flow itself. We can concentrate on our business logic rather than spending time on working those mundane tasks.
Spring web flow can be configured only via xml file. Currently it is not feasible to configure via only java.
The first thing to setup a web flow is configuration. A flow configuration involves below major components. Let’s go through them.
Flow executor: Flow executor is responsible to drive the flow. The syntax will be like below.
<flow:flow-executor id="flowExecutor"/>
Flow Registry: Flow registry is responsible to load the flow definitions. For example if all flows under folder WEB-INF/flows needs to be loaded it has to be configured like below.
<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows"> <flow:flow-location-pattern value = "**/*-flow.xml"/> </flow:flow-registry>
Here one important thing to note is the url path to the flow will be determined by the path of the flow location. For example if the path of a flow is /WEB-INF/flows/order/order-flow.xml then the id will be order (relative to the base path.) So the flow will be triggered while accessing the url http://{url}/{contextpath}/order
Instead of the pattern the path of the flow file also can be configured. For example to load order-flow.xml flow it can be configured like below.
<flow:flow-registry id="flowRegistry"> <flow:flow-location path = "/WEB-INF/flows/order/order-flow.xml"/> </flow:flow-registry>
If the full path is specified then the filename will become the id of that flow. In the above case it will be order-flow . If id needs to be different from the path it can be specified with id attribute like below.
<flow:flow-location path = "/WEB-INF/flows/order/order-flow.xml" id="custom/path/flow"/>
As per the above code the flow will be triggered when the url {contextPath}/custom/path/ flow is entered.
Flow Handler Mapping : Like DispatcherServlet for controller mapping, there is a class FlowHandlerMapping for URL to flow mapping for web flow.
Flow Handler Adapter : Like Controllers for handling the requests, there is a class FlowHandlerAdapter to handle the flow requests
The next important thing is the flow. A Flow is an xml file which tells the exactly how this flow should works. A flow will have three major components.
- State
- Transition
- Data
State : As per the name it is the state of the flow, which means the flows should be in a state. There are five types of states possible.
- View-state
- To display some pages to the user
- <view-state id=”welcome”/> will redirect to the view named welcome
- <view-state id=”welcome” view=”success”/> will redirect to the view named success
- <view-state id=”welcome” view=”success” model=”flowScope.paymentDetails”/> will redirect to the view named success with model attribute paymentDetails
- Action-state
- To execute logical conditions. The syntax will be like below.
<action-state id="saveOrder"> <evaluate expression="pizzaFlowActions.saveOrder(order)"/> <transition to="thankYou"/> </action-state>
- When flow reaches the above state the method pizzaFlowActions.saveOrder(order) will be executed and once done thankYou state will be invoked.
- To execute logical conditions. The syntax will be like below.
- Decision-state
- To decide which path to proceed based on particular condition. Can be of only two paths. Either True or false
<decision-state id="checkDeliveryArea"> <if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)" then="addCustomer" else="deliveryWarning"/> </decision-state>
- To decide which path to proceed based on particular condition. Can be of only two paths. Either True or false
- Subflow-state
- To trigger a sub-flow from the current flow. Once the sub-flow ends the current flow will resume
<subflow-state id="order" subflow="pizza/order"> <input name="order" value="order"/> <transition on="orderCreated" to="payment"/> </subflow-state>
- To trigger a sub-flow from the current flow. Once the sub-flow ends the current flow will resume
- End-state
- To denote the end of the flow. Syntax will be like below.
- <end-state id=”customerReady”/>
- If this is the sub flow the parent flow will resume once this flow ends.
- If this is not sub flow and has a view it will be rendered.
- If view name is prefixed with externalRedirect: it will redirect to that page outside the flow
- If view name is prefixed with flowRedirect: it will redirect to that page to another flow
- If this is not sub flow and there is no view, then the flow will end and go to the first state of the flow as a new flow.
Transition: To move from one state to another state the transition element will be used.
- It will be child element of the state elements view-state,subflow-state or action-state. The syntax will be like below.
- <transition to=”customerReady”> – If no on event is attached, it will be the default transition.
- <transition on=”submit” to=”customerReady”> – On submit event it will be fired
- <transition on-exception=”org.span.server.UserNotFoundException” to=”registrationForm”> – On UserNotfoundException this event will be fired.
- Instead of repeating same transitions on multiple states we can use global transitions like below. It will be applied to all states by default.
<global-transitions> <transition on="cancel" to="endState"/> </global-transitions>
Data: To store and pass data through out the flow the data elements will be used. The syntax will be <var name=”customer” class=”org.span.domain.Customer”/>
- In the above example a new Customer object will be created and assigned to customer. Also will be available across all state in that flow
- Also <evaluate> can be used on a view state or action state like below
- <evaluate result=”viewScope.toppingsList” expression=”T(org.span.domain.pizza.Topping).asList()”/>
- Also <set> can be used to set a variable’s value.
- <set name=”flowScope.pizza” value=”new org.span.domain.Pizza()”/>
- We can set the scope of the variables. It can be any one of the five types as below
- Conversion Scope -> Created at the top level and destroyed when top flow ends. Available under all sub flows too.
- Flow Scope -> Created at the flow level and available only within that level
- Request Scope -> Created when a request is made into a flow and destroyed when the flow returns
- Flash Scope -> Created when a flow starts and destroyed when flow ends. It is also cleared when a view state is rendered
- View Scope -> Created when a view state is entered, and destroyed when the state exists. Visible only to the view state.
- Default scope of variable declared via <var> tag will be flow scope.
- Default scope of variable declared via <set> ,<evaluate> will be mentioned along with the variable name like <set name=”flowScope.totalMarks” value=”499″/>
That is all about the major components of the web flow. Also web flow can be secured as well. To secure a flow it has to be configured like below.
<view-state id="restricted" view="paymentdetails"> <secured attributes="ROLE_ADMIN,ROLE_FINANCE" match="all"/> </view-state>
attributes are comma separated roles. match can be ‘any’ – At least one role required or ‘all’ – All roles required .
In this section we have discussed the concepts of Spring web flow. In the next tutorial we will implement a simple web flow application to understand all the discussed concepts.