By Justin Freeman
Recently, I was tasked with taking a paper application and turning it into a web application. A colleague suggested I try Spring Web Flow since the application was several pages long. I had heard of Spring Web Flow but never used it, so decided to take the opportunity to learn something new and see if it meets my requirements. Now that the application is complete, I’ll share my experience using Spring Web Flow for web application development.
Starting in Spring Web Flow is Easy
Getting started in Spring Web Flow couldn’t be any easier. Just import your jars into your favorite IDE, setup a few configuration files and a few classes and you're practically done. For a novice Java developer, it is pretty straightforward. Below is a sample flow.xml file that basically outlines your application or flow.
<?xml version="1.0" encoding="UTF-8"?> <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="userId" required="true" type="long" /> <on-start> <evaluate expression="flowService.addListObjects(flowScope)"/> </on-start> <view-state id="stepOne" model="stepOneDao" view= "flow/stepOne"> <on-entry> <evaluate expression="flowService.loadStepOne(flowScope)" result="flowScope.stepOneDao"/> </on-entry> <on-render> <evaluate expression="flowService.wizardSteps(1, flowScope, flowExecutionContext)"result="requestScope.steps"/> </on-render> <transition on="cancel" to="exit" bind="false" validate="false"></transition> <transition on="continue" to="stepTwo"> <evaluate expression="flowService.saveStepOne(flowScope)" result="flowScope.stepOneDao"/> </transition> </view-state> <view-state id="stepTwo" model="stepTwo" view="flow/stepTwo"> <on-entry> <evaluate expression="flowService.loadStepTwo(flowScope)"result="flowScope.stepTwp"/> </on-entry> <on-render> <evaluate expression="flowService.wizardSteps(2, flowScope, flowExecutionContext)" result="requestScope.steps"/> </on-render> <transition on="cancel" to="exit" bind="false" validate="false"></transition> <transition on="back" to="exit" bind="false" validate= "false"></transition> <transition on="continue" to="stepTwo"> <evaluate expression="flowService.saveStepTwo(flowScope)" result="flowScope.stepTwoDao"/> </transition> </transition> <end-state id="exit" view="externalRedirect:/index.html"/> </flow>
Spring Web Flow works like a wizard. It saves your data in your session automatically, or if you choose, to the data store. It also allows you to control the back and forward steps of the application making it browser independent.
You don’t have to manage all these variables on your own and every developer knows what a huge pain that can be. The "back", "cancel" and "continue" buttons are all configured to buttons in your application and define your transitions.
A transition is an action like a button click. A transition can go to a new screen or add data to the existing screen. The data for each screen is saved and loaded into the DAOs that are configured in this file. If there is data you need throughout the application such as options for a checkbox selection, you can add those in the beginning of the flow using a tag.
In order to use Spring Web Flow in your spring web application, you will need to config it in your spring config file. Here is a sample of what that would like:
<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.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd; <!-- Dispatches requests mapped to flows to FlowHandler implementations--> <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> <property name="flowExecutor" ref="flowExecutor"/> </bean> <!-- Custom FlowHandler for the webflow stuff --> <bean name="jsp/flow" class="com.WebFlowHandler" /> <!-- Executes flows: the entry point into the Spring Web Flow system --> <webflow:flow-executor id="flowExecutor"> <webflow:flow-execution-listeners> <webflow:listener ref="securityFlowExecutionListener" /> </webflow:flow-execution-listeners> </webflow:flow-executor> <!-- The registry of executable flow definitions --> <webflow:flow-registry id="flowRegistry" flow-builder-services= "flowBuilderServices" base-path="/WEB-INF"> <webflow:flow-location-pattern value="/**/*-flow.xml" /> </webflow:flow-registry> <!-- Plugs in a custom creator for Web Flow views --> <webflow:flow-builder-services id="flowBuilderServices"view-factory-creator="mvcViewFactoryCreator" development="true" validator="validator"/>
That is pretty much it. Your Spring Web Flow application is defined with 2 steps and WebFlowHandler defines the methods you will use to save and load your steps into your DAOs. No session management and no back and forward management needed. It really can’t get any simpler.
Spring Web Flow allows you to keep everything linear in your web application. So with an application that needs 4 or 5 steps completed in order, this works perfectly and keeps the user on task while minimizing user error.
Spring Web Flow Page Jumping Issues
I mentioned in the previous section that this works well with steps that need to be completed in order. The issue arises when everything doesn’t need to be so linear.
For example, what if a user is on page 7 on a wizard application and needs to make a correction on page 2. You can’t just jump back to page 2 in a wizard. Fortunately Web Flow gives you a way to traverse back to page 2, but it only works a page at a time. This is very cumbersome for a user to have to go back through each page to correct one issue and move forward all the way to where they came from. It is a frustrating user experience to say the least.
I have found a way to configure this in Spring Web Flow but it makes your flow.xml EXTREMELY complex and really defeats the purpose of Spring Web Flow, so I would not try it unless it is absolutely necessary. It will make your web application very difficult to maintain and that isn’t the goal of any Java developer.
Spring Web Flow Transition Issues
The problem here is that add content refreshes the page by default. This behavior was perfectly acceptable back in the 1990s, but in the age of AJAX refreshing the entire page just to add content is very archaic. It confuses the user since you don’t always go back to the place where the button was pushed. The user also has no idea what happened until they scroll down and see the new content on the screen.
AJAX in Spring Web Flow
Spring Web Flow works great and is fast if the needs of your web application are very strict and linear. Your application steps need to be completed in order and all validation takes place on each screen and saving is done at the step level or at the completion of every step. If your wizard needs to step outside those boundaries, the degree of difficulty will escalate quickly and the flow.xml file will become quite confusing.
I would also recommend keeping your AJAX calls to minimum as Web Flow doesn’t handle them too well. I still think it is a nice library to use and something worth learning.