Recently, I was tasked with taking a paper application and turning it into a web application. A colleague suggested I try Spring WebFlow since the application is several pages along. I had heard of Spring WebFlow but never used it, so I decided to take the opportunity to learn something new and see if it meets my requirements. Now that the application is complete, I’d like to write about my experience using Spring WebFlow for web application development.

The Good

Getting started in Spring WebFlow 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 WebFlow 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. As you can see, 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 WebFlow 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"/>





And that is pretty much it. Your Spring WebFlow 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 WebFlow 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.

THE NOT SO GOOD

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 WebFlow 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 WebFlow but it makes your flow.xml EXTREMELY complex and really defeats the purpose of Spring WebFlow, 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.

THE BAD

Another bad user experience I have in WebFlow has to do with transitions. As I mentioned before, a transition is defined as an action whether it be a button click or click on a click in the wizard. These buttons can do several things such as executing JavaScript, executing an action to go to another page or executing an action that keeps you on the current page and just add more content to the data dynamically. 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.
Another point I would like to make along the same lines is that AJAX is not very good in Spring WebFlow. You can do some very basic JavaScript with WebFlow but overall it doesn’t support the ever growing functionality of AJAX and you need that kind of support in today’s web application. For example, dynamically loading selection data for your web application does not work well, if at all. I could not get it to run properly in every browser that I work with so I resorted to loading the data necessary in the beginning of the application. This isn’t a bad approach for an application that has minimal sets of that kind of data. However it will slow your application down in the beginning if you have lots of data that needs to be pre-loaded.

Conclusion

Spring WebFlow works great and is fast if the needs of your web application are very strict and linear. What I mean is that your application steps needs 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 WebFlow doesn’t handle them too well. I still think it is a nice library to use and something worth learning.