Spring Roo and WebFlow (by Ken Rimple, Co-author, Spring Roo in Action)

Datetime:2017-02-06 21:02:15         Topic: JSP          Share        Original >>
Here to See The Original Article!!!

June 19, 2012

Roo and Web Flow

In this series of posts, based on a "cutting room floor chapter" of Spring Roo in Action , we'll explore how Spring Roo does (and does not) integrate with various technologies. We'll start by discussing Roo and Spring Web Flow, and we'll write two custom tags to help make them work better together.

I'll assume you already know a little bit about Spring Web MVC and have at least gone through some basic Roo tutorials. If you haven't done so, go back and run through the free first chapter of Spring Roo in Action.


How many times have you met with your end-users, figured out the navigational steps for a highly procedural web application, coded it, and found out it was just plain wrong? Every time? If you're like us, you've re-written HTML links, menus, redirects, forward instructions and controller methods too many times to count. Wouldn't your navigation code be less brittle if you could capture those rules in a descriptive language that you could change at will? Enter Spring Web Flow.

What is Web Flow?

Web Flow is a process definition language for web applications. Users are directed through a series of pages through navigational instructions, defined within an XML-based Web Flow Definition file. Web Flow is implemented as a controller layered on top of Spring MVC; instead of coding individual controllers for each step in a process, developers manipulate the instructions in the flow definition file.

Web flow definitions are made of several building blocks:

  • States - which can render the next view (page), execute Spring Bean methods, perform branching logic, and call subroutines called subflows .
  • Events - named activities that can be passed to a web flow via a button click, hyperlink or other mechanism.
  • Transitions - define the valid ways to move from state to state. Each transition is wired to a particular event. For example, the "continue" event can cause a transition to move from the "form entry state" to the "form processing state".

If you're imagining each user running the logic from a flow chart or state transition diagram, you're getting the idea.

Configuring Web Flow without Spring Roo

Due to its complexity, the configuration of Web Flow involves several beans, and a custom name space. To install in a typical Spring MVC application, you would:

  • Install the name space in a Spring MVC application context file.
  • Configure a Web Flow registry, which defines the locations of the web flow definition files, and views.
  • Configure a Web Flow Executor, which manages the web flow state instances.
  • Wire a FlowHandlerAdapter, which knows how to adapt a standard Spring MVC request to the Flow Executor.
  • Configure a FlowHandlerMapping, which coordinates with the Flow Registry, and
    helps look up the Web Flow instances when attempting to process an URL.

In short, you'd be doing a lot, but Roo can do this for you.

Installing Web Flow in a Roo application

Let's dive right in and set up Web Flow, by issuing the command web flow setup . Type that command into the Roo shell on an existing project configured with Spring MVC (we'll assume you've named this project webflowquickstart), and you'll see Roo respond with output similar to the following:

roo> web flow setup
Created SRC_MAIN_WEBAPP/WEB-INF/spring/webflow- config.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/config-flow.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/view-state-1.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/view-state-2.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/end-state.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/views.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/views/sampleflow/views.xml
Managed ROOT/pom.xml
[Added dependency org.springframework.webflow:spring-webflow:2.2.1.RELEASE]

Do I have to set up the MVC framework first?

No, you don't. Spring Roo will automatically configure Spring MVC
if you haven't done so already.

Spring Roo configures the Web Flow framework, and installs a demonstration
flow, samplewebflow . This webflow has two views, view-sampleflow state-1.jspx , and view-state-2.jspx . It is defined by the file named config-flow.xml in the views/sampleflow directory. Roo also added this flow to the menu system
and added the web flow library to the Maven build POM.

Running our Web Flow

Let's run the web application with mvn install tomcat:run. Launching
our web browser, we can access the web flow by browsing to
http://localhost:8080/webflowquickstart/sampleflow . You'll see a page looking
something like this:

Figure 1

The simple web flow defines three distinct views, each rendered using the Web Flow view-state tag, which displays a JSP, and waits for user input. The first page, view-state-1 , starts the web flow. The user can click on two buttons, CANCEL or PROCEED .

Clicking on the PROCEED button sends the proceed event to the web flow. Since the first view state contains a transition that responds to that event, Web Flow transitions the user to the next view state,
view-state-2 , shown below:

Figure 2

In view-state-2 , we can click the END or CANCEL buttons, which both end the web flow, and show the ending state, end-state:

Figure 3

As you can see, Web Flow keeps us following a navigational model -- we can go backward to back-trace our steps, and forward to complete our flow. Once the flow is finished, it starts over again at the first flow step.

The Web Flow navigational model

Let's look at a visual representation of the web flow:

Figure 4

So far, with a minimum of effort, Spring Roo installed and configured Spring
Web Flow and created a state-driven navigational flow.

Let's dig in a little deeper and learn a bit about the components of Web Flow.
Experienced Web Flow users can skip this section and go to Roo and Web
Flow Forms

Web Flow components

As we stated above, Web Flow uses an XML-based to define the Flow Definition File steps, navigation rules and intermediate data storage and to orchestrate calls to business logic.

Let's take a look at the components that make up a flow definition. They are
the flow definition itself, states, transitions, events and data.

The Web Flow definition

The web flow we diagrammed above is implemented using an XML flow control language. The code below shows the web flow definition, flow.xml, which lives
along with views and other files within WEB-INF/views/sampleflow :

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
   <!-- A sample view state -->
   <view-state id="view-state-1" view="sampleflow/view-state-1">
     <transition on="success" to="view-state-2"/>
     <transition on="cancel" to="end-state"/>
   <view-state id="view-state-2" view="sampleflow/view-state-2">
     <transition on="cancel" to="end-state"/>
   <!-- A sample end state -->
   <end-state id="end-state" view="sampleflow/end-state"/>

As you can see above, the flow is defined using a simple XML language. The
first state defined in the flow definition is view-state-1 . The URL to browse to this web flow is exposed as the URL
http://localhost:8080/webflowquickstart/sampleflow . Web Flow renders the view associated with this state and waits for the next event.

Our flow has two more state nodes— view-state-2 and
end-state . Transitions wire navigation between states, using names such as
success and cancel . This makes basic flow definition language easy to interpret and explain to less technical people.
Let's see how these components work together.

Flow states

Web Flows perform actions, such as executing Spring Beans, and can accept input
in stopping points, called view states. There are actually a number of different states, including view-state, action-state, decision-state, subflow-state and end-state. Their uses:

  • A view-state renders a view and waits for the user to submit a form.
  • A action-state executes business logic and transitions immediately to another state.
  • A decision-state can be used to branch on a binary condition. This is out of favor in the current web flow approach but can be seen on simple yes/no branches. There are better ways to select from a set of choices today.
  • A subflow-state allows flows to call re-usable flow logic from another web flow.

Transitions and events

Let's focus a bit on those two possible transitions in view-state-1, defined by
the >transition < tag:

The on= keyword defines an event—a named action that can be triggered by a number of activities, such as a button or link click, or the results of a method call.

View states and transitions

We can link two view states together using a transition, by referencing the id of the target event in the to= attribute. A bidirectional linkage between two states, where the user can move back and forth from one state to the other, may be defined like this:

 <view-state id="state-one"...>
   <transition on="next" to="state-two"/>
<view-state id="state-two"...>
   <transition on="previous" to="state-one"/>

When Web Flow pauses the controller and renders the view state, it expects to
receive another GET or POST to the same web flow URL. It also expects the
form submission to contain a special field defining the triggered event. The field must start with a prefix of <em>eventId</em> , and contain the name of a valid transition event. The value does not matter, but the name is critically important.

Here are the transitions defined for events that can be triggered on view-state-1:

 <transition on="success" to="view-state-2"/>
<transition on="cancel" to="end-state"/>

You'll need to construct a form that renders with the following syntax:

 <form method="POST">
    <input type="submit" name="_eventId_success";/>CONTINUE</input>
    <input type="submit" name="_eventId_cancel">CANCEL</input>

As we discussed above, each web flow is exposed via a single URL. The forms processed by the web flow always POST or GET to that URL, which is the location they came from. In the form above, two valid events are enabled: <em>eventId</em>proceed and <em>eventId</em>cancel . If one of those values are present in the submission, the flow will be updated to move to view-state-2 or end-state , respectively.

Keeping track of state

You may notice that Web Flow adds a parameter to the end of the URL for every
request: a two-part token known as the execution key. The first time a user executes a flow, it may look like /sampleflow?execution=e1s1 . The e1
component denotes the first execution of the web flow by the user, and the s1 component describes the current step. Each subsequent transition step bumps the step up by one, and once a flow finishes, the execution id for the next flow instance will be bumped up by one.

You can try experimenting with this in your web browser. Switch between the
first and second states, and see the step increase. Now, change the step back to the prior value on the browser URL and hit [ENTER] . You'll see the prior state again.

In this way, users can move back and forth in the history of the web flow. The
flow execution engine actually stores data for each step, so the variables can be restored by navigating to prior steps in the flow.

Those are the major components of Spring Web Flow. It would (and does) take
an entire book to go into detail about good Web Flow design, and we're only
scratching the surface with our discussion.

Web Flow challenges in Spring Roo

Web Flow isn't completely on board with the way Roo does its form processing. For one thing, Roo approaches web forms using REST—submitting new data with POST, updating entities with PUT, removing with DELETE, and so on. That certainly is not the way Web Flow operates, as it expects POSTs back to the same URL with different data, rather to resource URLs with the verbs in control of the action.

Another problem is that the Spring MVC form tags, create.tagx , and update.tagx , already build the form with the expectation of a single submit button, but Web Flow developers generally provide one or more event names in different links or buttons, so we can't use those tags.

Creating our own Web Flow compatible form tags

We'll create two new JSPX tags— webflow:form , which is a customized HTML form tag that deals with non-RESTful Web Flow forms, and webflow:formbutton , which generates a Web Flow-friendly button and exposes an event id for each button.

The webflow:form tag

To build the form tag, you merely have to take one of the existing tags and whittle it down to a simpler form, making the URL optional, and removing the default button generation.

You can start by copying /WEB-INF/tags/form/create.tagx into another directory, /WEB-INF/tags/webflow , as form.tagx . Then, make your changes. An example is shown below:

 <?xml version="1.0"?>
<jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core"
   xmlns:spring="http://www.springframework.org/tags" version="2.0">

   <jsp:output omit-xml-declaration="yes"/>

   <jsp:directive.attribute name="id" type="java.lang.String"
      required="true" rtexprvalue="true"
      description="The identifier for this tag"/>         
   <jsp:directive.attribute name="modelAttribute"
      type="java.lang.String" required="true"
      description="The name of the model attribute for form binding"/>         
   <jsp:directive.attribute name="title"
      type="java.lang.String" required="true"
      rtexprvalue="true" description="The title used for this object"/>

   <util:panel id="${id}" title="${title}}">
     <form:form method="POST" modelAttribute="${modelAttribute}">

The tag's jsp:root mostly stays the same. We replace the existing JSP tag attributes (parameters) with id, title, and modelAttribute, the essentials for web flow. We then don't bother to set a URL as we are going to post back to the place the form came from - the Web Flow's unique Flow URL.

Inside the tag content, we use the title and id to construct a Roo Dojo TitlePane via the util:panel tag, and we create a wrapper Spring MVC form tag within the title pane. Finally, we instruct the tag to emit whatever the user has wrapped with it inside of the jsp:doBody tag.

The webflow:formbutton tag

To trigger events using form submit buttons, we need to create our own submit
button widget. The snippet shows an example, formbutton.jspx , which lets us add our own button instances for each event we want to trigger. This button had to be created from scratch, using a fragment of the create.tagx tag file, to mimic the Spring Roo Dojo component stylings:

 <?xml version="1.0"?>
<jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:spring="http://www.springframework.org/tags" version="2.0">

   <jsp:output omit-xml-declaration="yes"/>

   <jsp:directive.attribute name="id"
     type="java.lang.String" required="true"
     description="The id of the generated input button"/>
   <jsp:directive.attribute name="event"
     type="java.lang.String" required="true"
     description="Webflow event to submit"/>
   <jsp:directive.attribute name="label"
     type="java.lang.String" required="true"
     description="The label used for this field."/>

   <script type="text/javascript">
        Spring.addDecoration(new Spring.ValidateAllDecoration({

   <input id="button_${event}" type="submit"
     value="${fn:escapeXml(label)}" name="_eventId_${event}"/>


Notice that this is not a container tag; it doesn't nest any additional content. Therefore, we don't have a tag. We begin <by defining three parameters, the button's id, submitted Web Flow event name, and the button label.

We define the button itself with a standard HTML submit input tag, binding
the name to the Web Flow Event name, with the syntax of _<em>eventId</em>_event.

Finally, we tag the button with the Spring JavaScript / Dojo client-side form validation decoration, ValidateAll , so that it does not allow submission until the fields pass all client-side form validation rules.

Using the Tag Library

To use these custom tags, just declare them as with any other local tag library
using the prefix urn:jsptagdir:/WEB-INF/tags/webflow . Here is a view that is using webflow:form and webflow:formbutton tags, as well as a Roo fields:select drop-down list tag:

 <div xmlns:webflow="urn:jsptagdir:/WEB-INF/tags/webflow" 
   xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">

   <webflow:form id="title" title="${title}"

     <fields:select path="offeringId"
       itemValue="id" />

      <div class="submit">
           label="Cancel" event="cancel" />

           label="Proceed" event="proceed" />


The webflow, jsp and pre-generated Roo fields tag libraries are defined
in the preamble. We then define our form using the webflow:form tag, and use the Spring Roo form tag library, which we've mounted as fields: , to create our select field.

We close out the form by wrapping our buttons within a DIV with the class of
submit , which Roo's style sheet uses to outline form buttons. We install two webflow:formbutton tags, one for each event, proceed and cancel .


Feel free to use this tag library in your own applications or build your own. It would make a great Roo tag library add-on.

As you can see, it's quite simple to define your own custom tags. If you adhere to the Dojo stylings and validation rules, you can make Web Flow views fit in visually with your other pages. Of course, if you don't like Roo's Dojo-based forms approach, feel free to gut the tag libraries and do what you wish for the views in your Web Flows.

Ken Rimple is a trainer, mentor and consultant for Chariot Solutions , where he is the Director of Education Services, and is a co-author, along with Srini Penchikala, of Spring Roo in Action . Ken writes about Spring, photography, music and other topics on his personal blog, rimple.com , and runs Chariot's Emerging Technologies resources website at emergingtech.chariotsolutions.com . He is also a podcaster with four years of interviews under his belt in the "Chariot TechCast" podcast series . You can reach him on twitter as @krimple or on java.net as 'kerimple'.