Tuesday, September 10, 2013

Spring Webflow Code example - Part I

This blog shows how to develop a Spring Webflow application having integration with Spring MVC. Spring WebFlow allows us to create a UI workflow with a series of page navigation and abiltity to navigate back and forth. It also provides a context to work with in addition to many other features.

Overview:

We will be creating a flow to order pizza with the following navigation pages. 

  1. The first page - Enter customer details
  2. The second page - Select pizza
  3. Review Order & submit
  4. Order confirmation

Now, in the second page, you get a few options to select the pizza you want. If the customer selects 'Indian Spicy Pizza', then we will offer free coke (The pizza provider is kind enough to provide some relief to customers after eating spicy stuff. :)  )

So, after the second page, if the customer selects 'Indian Spicy Pizza', then a page showing complimentary coke is displayed. This is conditional navigation.
After submitting the order in the third page, order confirmation page will be shown.

Creating project:

Create a Maven project with a archetype 'maven-archetype-webapp'.

pom.xml

<properties>
    <spring.version>3.1.2.RELEASE</spring.version>
</properties>
<dependencies>
    <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>3.8.1</version>
         <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <type>jar</type> 
      <scope>compile</scope>
    </dependency>  
    <!-- Spring 3 dependencies -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>    
      <groupId>org.springframework.webflow</groupId> 
      <artifactId>spring-webflow</artifactId>
      <version>2.3.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
</dependencies>

web.xml

<web-app id="WebApp_ID" version="2.4" 
        xmlns="http://java.sun.com/xml/ns/j2ee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <!-- Welcome files --> 
 <welcome-file-list>  
     <welcome-file>index.jsp</welcome-file> 
        </welcome-file-list> 
</web-app>

Spring dispatcher servlet xml:

The servlet-name is 'mvc-dispatcher'. So we need a context xml with the name mvc-dispatcher-servlet.xml.

<beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:mvc="http://www.springframework.org/schema/mvc"  
        xmlns:context="http://www.springframework.org/schema/context" 
        xmlns:util="http://www.springframework.org/schema/util"  
        xmlns:webflow="http://www.springframework.org/schema/webflow-config"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd 
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/webflow-config
        http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd">   
        
        <context:component-scan base-package="com.myorg" />
        <mvc:annotation-driven/>
        
        <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
      <property name="basename" value="messages"/>
        </bean>
        
        <bean id="myViewResolver"
                       class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
                       <property name="prefix">
                           <value>/WEB-INF/view/</value>
                       </property>
                       <property name="suffix" value=".jsp"/>
        </bean>
        
        <!-- Web flow configs -->
        
        <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
             <webflow:flow-location path="/WEB-INF/pizza-order-flow.xml" />
        </webflow:flow-registry>
 
        <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" />
 
 
        <!-- Enables FlowHandler URL mapping -->
        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
             <property name="flowExecutor" ref="flowExecutor" />
        </bean>
 
        <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>
 
                <bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
                      <property name="viewResolvers" ref="myViewResolver"/>
                </bean>
  
        <!-- Maps request paths to flows in the flowRegistry; -->           
        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
            <property name="flowRegistry" ref="flowRegistry"/>
            <property name="order" value="0"/>
        </bean>
  
</beans>  

Note the additional configuration for webflow integration. The FlowhandlerMapping and FlowHandlerAdapter are used to identify webflow requests.

Every webflow which is defined should be declared in a registry. Here we have provided the absolute path of the flow xml as '/WEB-INF/pizza-order-flow.xml'.

POJOs:

public class Order implements Serializable{
        private Customer cust;
        private List pizzaList;
        
        //Setters and Getters
}

public class Customer implements Serializable{
        private String firstName;
        private String lastName;
        private String emailAddress;
        
        //Setters and Getters
}

public class Pizza implements Serializable{
        private String name;
 private int quantity;
 
 //Setters and Getters
}

Controller:

We will have a single controller, PizzaOrderController which will be annotated with @Controller. We will add methods to this as we go along.

Web Flow xml:

Create a file 'pizza-order-flow.xml' within WEB-INF and this will have the flow related stuff. Following is the plain flow xml.

<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">
                          
                          
</flow>


                                                                                               ....Click here to continue

No comments:

Post a Comment