del.icio.us Digg DZone Reddit StumbleUpon
Tutorial: Build a Shopping Cart with Spring Web Flow 2.0 - Willie Wheeler
« Previous | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Next »

Subflows

Going hand-in-hand with the idea of multiple flows is the idea that some flows might be subflows of other flows. In mycart3, all four flows can be independently accessed, but in addition to that we have the addToCart, login and register flows being subflows to the checkout flow. See Figure 3.

Figure 3. Subflows.
Figure 3. Subflows.

Here's the idea. The three flows we've identified as subflows are defined as separate flows because clearly there are use cases where it makes sense for them to be accessed outside of a checkout process. For example, we want to be able to add products to a shopping cart while we're browsing the product catalog. And of course we want people to be able to register and login even if they're not in a checkout process.

But those are also flows that we might want to include as part of a checkout process too. During checkout, we might want to recommend products to the customer. Or if the user hasn't yet logged in or registered, we'd want them to do that as part of the checkout process rather than forcing them to do that before they could enter the checkout process.

By defining the login, registration and add-to-cart as flows, we make them available both independently (as top-level flows) and also as part of a larger flow (like the checkout flow). That's why we have these defined as flows even though they are currently implemented as single-state flows. (It is however easy to imagine these being multi-state flows. For example, the login flow may ask you to answer a challenge question if it detects that you're coming in from an unusual IP address, or the add-to-cart flow may ask you to enter a quantity before proceeding.)

So here is the checkout flow:

Code listing: /WEB-INF/flows/checkout.xml
<?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">
    
    <!-- Get the products one time, at the beginning of the flow -->
    <on-start>
        <set name="flowScope.products" value="cartService.products"/>
        <set name="flowScope.shippingOptions" value="cartService.shippingOptions"/>
    </on-start>
    
    <!-- If not specified, the start state is the first state specified. -->
    <view-state id="viewCart" view="viewcart">
        <!-- cart is available to SWF but not stored on the session under that
             name when using AOP proxy -->
        <on-render>
            <!-- Carry cart from Spring app context to request scope -->
            <set name="requestScope.shoppingCart" value="shoppingCart"/>
            <set name="requestScope.recommendations" value="cartService.recommendations"/>
        </on-render>
        <transition on="addToCart" to="addProductToCart"/>
        <transition on="register" to="register"/>
        <transition on="login" to="login"/>
    </view-state>
    
    <subflow-state id="addProductToCart" subflow="addToCart">
        <!-- This is where we go when the subflow returns. productAdded is
             the name of an end-state. -->
        <transition on="productAdded" to="viewCart"/>
    </subflow-state>
    
    <!-- New customers create a new account before moving forward -->
    <subflow-state id="register" subflow="register">
        <transition on="accountAdded" to="paymentAndShipmentOptions"/>
        <transition on="cancelRegistration" to="viewCart"/>
    </subflow-state>

    <!-- Existing customers log in before moving forward -->
    <subflow-state id="login" subflow="login">
        <!-- This is where we go when the subflow returns. productAdded is
             the name of an end-state. -->
        <transition on="loginOk" to="paymentAndShipmentOptions"/>
    </subflow-state>

    <!-- Payment and shipment options -->
    <view-state id="paymentAndShipmentOptions" view="options">
        <transition on="submit" to="confirmOrder"/>
        <transition on="back" to="viewCart"/>
    </view-state>
    
    <!-- Confirm order -->
    <view-state id="confirmOrder" view="confirmorder">
        <on-render>
            <set name="requestScope.shoppingCart" value="shoppingCart"/>
        </on-render>
        <transition on="continue" to="thankYou">
            <evaluate expression="cartService.submitOrderForPayment()"/>
        </transition>
    </view-state>
    
    <!-- Thank you page -->
    <view-state id="thankYou" view="thanks">
        <transition on="continue" to="shop"/>
    </view-state>
    
    <!-- Exit the flow, letting the user return to shopping -->
    <end-state id="shop" view="externalRedirect:contextRelative:/home.do"/>
    
    <global-transitions>
        <transition on="cancelCheckout" to="shop"/>
    </global-transitions>
</flow>

In the code above, we are using the <subflow-state> element to call a subflow from a parent flow. The subflow attribute specifies one of the flows you registered with the flow registry in the Spring configuration. The flow starts at the subflow's start state, and continues until the subflow hits an end state. The end state IDs provide keys that you can reference from the calling flow to effect state transitions. For example, in the flow above, accountAdded is one of the end states for the register flows, and so one of the <transition> elements references that end state.

Recall from register.xml (see page 4) that the end states specified a view attribute. If the register flow is called directly, then SWF will use the view attribute to decide which view to show the user when the flow reaches a given end state. If, however, the flow is called as part of a subflow (instead of being called directly), SWF will ignore the view attribute and instead follow whatever transition is defined in the calling <subflow-state>.

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
« Previous | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Next »
Show comments (62)

Post a comment

Your name:
Your e-mail address (won't be displayed):
Your web site (optional):
example: www.xyz.com
Your comment:
Please help us prevent comment spam:
Spring in Practice
My brother and I are writing Spring in Practice for Manning!

What's New?

2008-10-20 - I've added a new mailing list feature to the site. Sign up to receive e-mail updates about new articles.
2008-09-30 - We've released chapter 4 (User registration) and chapter 5 (Authentication) of Spring in Practice.
2008-09-11 - By popular demand, I've added an RSS feed to the site.
Home | Consulting | Tech Articles | Mailing List | About | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.