Spring – How I will enter into web flow from any point in Spring MVC web app? Spring Web Flow webapp is not working

spring, spring-mvc, spring-webflow

I have been trying to develop an multi-page user registration form using Spring Web Flow but could not completed. Later on I am going to paste my application code in this post.
I would be grateful to one who identify the missing part or error and guide me to resolve the same.

My webapp name is 'UserRegistrationSWF'. Here is the directory structure:

UserRegistrationSWF     -Java Resources         -src            -org.nitest.controller                -UserRegistrationController.java            -org.nitesh.model                -User.java     -WebContent         -WEB-INF            -config                -swf-config.xml                -web-application-config.xml            -swf                -swf-flow.xml                -userRegistrationPage2.jsp                -userRegistrationLastPage.jsp            -view                -cancel.jsp                -success.jsp                -userRegistrationStartPage.jsp            -web.xml              -index.jsp

I am using Spring MVC and my welcome page is 'index.jsp'. Here is the code:

<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Welcome Page</title></head><body><a href="userRegistrationStartPage.htm">User Registration</a></body></html>

Here is 'web.xml' code:

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-    app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">  <display-name>UserRegistrationSWF</display-name>  <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list>  <context-param>  <param-name>contextConfigLocation</param-name>  <param-value>/WEB-INF/config/web-application-config.xml</param-value>  </context-param>  <listener>  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>  <servlet>    <servlet-name>User Registration</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <init-param>    <param-name>contextConfigLocation</param-name>    <param-value></param-value>    </init-param>    <load-on-startup>1</load-on-startup>  </servlet>  <servlet-mapping>    <servlet-name>User Registration</servlet-name>    <url-pattern>*.htm</url-pattern>  </servlet-mapping></web-app>

Here is the 'web-application-config.xml' code:

<?xml version="1.0" encoding="UTF-8"?><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:webflow="http://www.springframework.org/schema/webflow-config"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/webflow-confighttp://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd">    <mvc:annotation-driven/>    <context:component-scan base-package="org.nitesh" />    <bean id="jspViewResolver"        class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="viewClass"            value="org.springframework.web.servlet.view.JstlView" />        <property name="prefix" value="/WEB-INF/view/" />        <property name="suffix" value=".jsp" />    </bean><import resource="swf-config.xml"/> </beans>

Here is the 'swf-config.xml' code:

<?xml version="1.0" encoding="UTF-8"?><beans xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd" xmlns:webflow="http://www.springframework.org/schema/webflow-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"><webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">    <webflow:flow-location path="/swf/swf-flow.xml" /></webflow:flow-registry><webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"></webflow:flow-executor><bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">    <property name="flowExecutor" ref="flowExecutor" /></bean><bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">    <property name="flowRegistry" ref="flowRegistry"/></bean></beans>

Here is the 'swf-flow.xml' code:

<?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-confighttp://www.springframework.org/schema/webflow-config/spring-webflow-config-2.3.xsd"><view-state id="userRegistrationStartPage" view="userRegistrationStartPage.htm" model="user"><transition on="cancel" to="cancel"></transition><transition on="proceed" to="userRegistrationPage2"></transition></view-state><view-state id="userRegistrationPage2" view="userRegistrationPage2.htm"><transition on="revise" to="userRegistrationStartPage"></transition><transition on="proceed" to="userRegistrationLastPage"></transition><transition on="cancel" to="cancel"></transition></view-state><view-state id="userRegistrationLastPage" view="userRegistrationLastPage.htm"><transition on="revise" to="userRegistrationPage2"></transition><transition on="confirm" to="success"></transition><transition on="cancel" to="cancel"></transition></view-state><end-state id="success" view="swf/success.jsp"></end-state><end-state id="cancel" view="swf/cancel.jsp"></end-state></flow>

Here is the 'userRegistrationStartPage.jsp' code:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"pageEncoding="ISO-8859-1"%><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>User Registration Start Page</title></head><body><form:form commandName="user" method="POST"><table><tr><td>Name:</td><td><form:input path="name"/></td></tr><tr><td>Email:</td><td><form:input path="email"/></td></tr><tr><td>Password:</td><td><form:password path="password"/></td></tr><tr><td><input type="submit" name="_eventId_cancel" value="Cancel"></td><td><input type="submit" name="_eventId_proceed" value="Next"></td></tr></table></form:form></body></html>

The 'cancel.jsp' and 'success.jsp' simply prints cancel and success message respectively.
The 'User' class is a userRegistrationStartPage form bean class.
The 'userRegistrationPage2.jsp' and 'userRegistrationLastPage.jsp' Simply prints messgage for now.

Here is web app controller 'UserRegistrationController.java' code:

package org.nitesh.controller;import org.nitesh.model.User;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;@Controllerpublic class UserRegistrationController {    @RequestMapping(value = "userRegistrationStartPage.htm")    public ModelAndView showUserRegistrationFormStartPage(@ModelAttribute("user") User user)    {        return new ModelAndView("userRegistrationStartPage");    }}

Preceding is the web app codes.
Now I would like to come to my questions:
1. How I will enter into web flow from any point in Spring MVC web app? I mean how I will take entry into web flow by clicking following link in 'index.jsp':

<a href="userRegistrationStartPage.htm">User Registration</a>
  1. Above mentioned webapp is not working, what more is missing that do I need to add or change in order to make it working?

I am really looking forward to hear the answer from one.

Thanks.

Best Solution

You're almost there:

It's a best practice to add all elements of your flow in one folder. So move the first page of your flow named 'userRegistrationStartPage.jsp' from /view/ to /swf/

-WebContent    -WEB-INF        -config            -swf-config.xml            -web-application-config.xml        -swf            -swf-flow.xml            -userRegistrationStartPage.jsp            -userRegistrationPage2.jsp            -userRegistrationLastPage.jsp        -view            -cancel.jsp            -success.jsp                        -web.xml          -index.jsp

Because you defined a flow in your swf-config.xml

<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">    <webflow:flow-location path="/swf/swf-flow.xml" /></webflow:flow-registry>

The mapping to start that flow will be swf (the first part of the path)Change your index.jsp to the following

<html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">        <title>Welcome Page</title>    </head>    <body>        <a href="swf">User Registration</a>    </body></html>

Also, because you're using a User object to store the registration information, you need to create one at the start of the flow. See the the booking-mvc example of spring webflow where a Hotel object is needed at the start of the flow:

<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="hotelId" required="true" />    <on-start>        <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)" result="flowScope.booking" />    </on-start>    <view-state id="enterBookingDetails" model="booking">        etc...    </view-state></flow>

Here they use a service to get a hotel from the database, YMMV.

Lastly, the UserRegistrationController isn't needed, so you can remove it.

Update

The quickest way to create a new User object at the start of your flow would be to add the following line at the beginning of swf-flow.xml:

<on-start>    <evaluate expression="new org.nitesh.model.User()" result="flowScope.user" /></on-start>