From 36f424b263fff08bba58db74980b1f0241b1af0d Mon Sep 17 00:00:00 2001
From: Keith Donald
- Web flow excels at implementing dynamic navigation logic that takes a user through different paths based on what they enter or who they are.
-
+ Web flow excels at implementing dynamic navigation logic that takes a user through different paths based on what they enter or who they are.
+
+ Refresh your flow and the checkbox should render checked since the default value for the HelloWorldForm selected property is true.
+ Uncheck the box and submit and go back in your browser and the unchecked status should be preserved.
+
- Refresh your flow and the checkbox should render checked since the default value for the HelloWorldForm.selected property is true.
- Uncheck the box and submit and go back in your browser and the unchecked status should be preserved.
-
+ Next >
+
- Spring Web Flow is a framework for implementing stateful web controllers.
- It is a Spring Project and part of Spring's open-source Web Stack.
-
-Use Spring Web Flow when you need to implement a flow that guides your users through a series of screens to complete a business goal.
-Web Flow provides a flow definition language for authoring flows that define screen navigation rules.
-The framework also cares for managing conversational state and preventing duplicate transactions.
-
-Spring Web Flow builds on the Spring Framework project, which includes the Spring MVC web framework.
-Concretely, Spring Web Flow plugs into Spring MVC as a Controller technology.
-A typical Spring-powered web application is implemented using a mix of annotated Spring MVC Controllers and web flows.
-In general, use @Controllers for implementing simple, single-request user interactions, and web flows for stateful, multi-step user interactions.
-
-A number of other Spring projects also integrate with Spring Web Flow.
-The Spring Faces project uses Spring Web Flow as the controller framework to support implementing Spring-powered web applications that use JavaServerFaces (JSF) as the view technology.
-Spring Web Flow also provides integration with Spring Security for securing web flows.
-
-How Spring Web Flow fits into Spring's layered, a-la-carte "Web Stack" is illustrated below:
- Next >
-
+ Spring Web Flow is a framework for implementing stateful web controllers.
+ It is a Spring Project and part of Spring's open-source Web Stack.
+
+ Use Spring Web Flow when you need to implement a flow that guides your users through a series of screens to complete a business goal.
+ Web Flow provides a high-level flow definition language for authoring flows that define screen navigation rules.
+ The framework also cares for managing conversational state and preventing duplicate transactions.
+
+ Spring Web Flow builds on the Spring Framework project, which includes the Spring MVC web framework.
+ Concretely, Spring Web Flow plugs into Spring MVC as a Controller technology.
+ A typical Spring-powered web application is implemented using a mix of annotated Spring MVC Controllers and web flows.
+ In general, use @Controllers for implementing simple, single-request user interactions, and web flows for stateful, multi-step user interactions.
+
+ A number of other Spring projects also integrate with Spring Web Flow.
+ The Spring Faces project uses Spring Web Flow as the controller framework to support implementing Spring-powered web applications that use JavaServerFaces (JSF) as the view technology.
+ Spring Web Flow also provides integration with Spring Security for securing web flows.
+
+ How Spring Web Flow fits into Spring's layered, a-la-carte "Web Stack" is illustrated below:
+ Next >
+
Creating Your First Web Flow
@@ -28,185 +33,211 @@
Step-by-step instructions for creating your first flow using the Eclipse-based SpringSource Tool Suite IDE:
-Setup the project development environment
-
-
-Create your first helloworld flow
-
-
-
- <html>
- <head>
- <title>Hello world!</title>
- </head>
- <h1>
- Hello world!
- </h1>
- </html>
-
- Add a navigation rule
-
-
-
- <transition on="submit" to="page2" />
-
- Then define your page2 view-state:
-
- <view-state id="page2">
- </view-state>
-
- And the corresponding page2.jsp:
-
- <html>
- <head>
- <title>Hello world!</title>
- </head>
- <h1>
- This is page 2!
- </h1>
- </html>
-
- Finally, create a button on your start.jsp that raises the submit event to trigger the state transition:
-
- <form method="post">
- <input type="submit" name="_eventId_submit" value="Submit" />
- </form>
-
- Click the button and you should be taken to page 2.
- Add a dynamic navigation rule
-
-
- <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
- <html>
- <head>
- <title>Hello world!</title>
- </head>
- <h1>
- Hello world!
- </h1>
- <form:form method="post" modelAttribute="helloWorldForm">
- <form:checkbox path="selected" />
+
Setup your project
+
+
+Create your first helloworld flow
+
+
+
+ <html>
+ <head>
+ <title>Hello world!</title>
+ </head>
+ <h1>
+ Hello world!
+ </h1>
+ </html>
+
+ Add a navigation rule
+
+
+
+ <transition on="submit" to="page2" />
+
+ Then define your page2 view-state:
+
+ <view-state id="page2">
+ </view-state>
+
+ And the corresponding page2.jsp:
+
+ <html>
+ <head>
+ <title>Hello world!</title>
+ </head>
+ <h1>
+ This is page 2!
+ </h1>
+ </html>
+
+ Finally, create a button on your start.jsp that raises the submit event to trigger the state transition:
+
+ <form method="post">
<input type="submit" name="_eventId_submit" value="Submit" />
- </form:form>
- </html>
-
-
- package org.springframework.webflow.samples.helloworld;
+ </form>
+
+ Click the button and you should be taken to page 2.
+ Add a dynamic navigation rule
+
+
-
+ <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
+ <html>
+ <head>
+ <title>Hello world!</title>
+ </head>
+ <h1>
+ Hello world!
+ </h1>
+ <form:form method="post" modelAttribute="helloWorldForm">
+ <form:checkbox path="selected" />
+ <input type="submit" name="_eventId_submit" value="Submit" />
+ </form:form>
+ </html>
+
+
+ package org.springframework.webflow.samples.helloworld;
+
+ import java.io.Serializable;
+
+ public class HelloWorldForm implements Serializable {
+ private boolean selected = true;
+
+ public boolean isSelected() {
+ return selected;
+ }
+
+ public void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+ }
+
+
+ <var name="helloWorldForm" class="org.springframework.webflow.samples.helloworld.HelloWorldForm" />
+
+ Then update your start view-state to use this variable as its data model, enabling automatic model binding and validation:
+
+ <view-state id="start" model="helloWorldForm"> ...
+
+
+ <decision-state id="isSelected">
+ <if test="helloWorldForm.selected" then="page2" else="page3" />
+ </decision-state>
- import java.io.Serializable;
-
- public class HelloWorldForm implements Serializable {
- private boolean selected = true;
+ <view-state id="page2">
+ </view-state>
- public boolean isSelected() {
- return selected;
- }
-
- public void setSelected(boolean selected) {
- this.selected = selected;
- }
- }
-
-
- <var name="helloWorldForm" class="org.springframework.webflow.samples.helloworld.HelloWorldForm" />
-
- Then update your start view-state to use this variable as its data model, enabling automatic model binding and validation:
-
- <view-state id="start" model="helloWorldForm"> ...
-
-
- <decision-state id="isSelected">
- <if test="helloWorldForm.selected" then="page2" else="page3" />
- </decision-state>
-
- <view-state id="page2">
- </view-state>
-
- <view-state id="page3">
- </view-state>
-
- Be sure to update your start view-state to transition to the isSelected decision state instead of page2 directly:
-
- <view-state id="start">
- <transition on="submit" to="isSelected" />
- </view-state>
-
- Click the Submit button with the checkbox selected and you should be taken to page2.
- Click the button with the checkbox de-selected and you should be taken to page3 (you'll need to create a JSP or you'll get a 404).
- Finish your helloworld flow
-
-
- Next >
+ <view-state id="page3">
+ </view-state>
+
+ Be sure to update your start view-state to transition to the isSelected decision state instead of page2 directly:
+
- <input type="submit" name="_eventId_finish" value="Finish" />
-
- In your start view-state, declare the finish transition:
-
- <transition on="finish" to="finished" />
-
- And finally define the end-state:
-
- <end-state id="finished" view="externalRedirect:welcome" />
-
- Click the Finish button and you should be taken back to the application welcome screen.
-
+ <view-state id="start">
+ <transition on="submit" to="isSelected" />
+ </view-state>
+
+ Click the Submit button with the checkbox selected and you should be taken to page2.
+ Click the button with the checkbox de-selected and you should be taken to page3 (you'll need to create a JSP or you'll get a 404).
+
+
+Finish your helloworld flow
+
+
+
+ <input type="submit" name="_eventId_finish" value="Finish" />
+
+ In your start view-state, declare the finish transition:
+
+ <transition on="finish" to="finished" />
+
+ And finally define the end-state:
+
+ <end-state id="finished" view="externalRedirect:welcome" />
+
+ Click the Finish button and you should be taken back to the application welcome screen.
+
Overview of the Spring Web Flow Project
-
- What is Spring Web Flow?
-
-
- When do I use Web Flow?
-
-
- How does Web Flow relate to other Spring projects?
-
-
-" />
-
+ What is Spring Web Flow?
+
+
+ When do I use Web Flow?
+
+
+ How does Web Flow relate to other Spring projects?
+
+
+ " />
+
Setting up Web Flow in a Spring Web Application
@@ -12,181 +17,203 @@
This step covers the one-time configuration step of setting Web Flow up in a Spring web application.
If you prefer to go right to implementing your first flow, you can skip this step.
- The configuration of every Spring web application starts in web.xml. - There, a Spring MVC DispatcherServlet is defined to process all requests into the application. - The DispatcherServlet itself is configured using a Spring container. - It is responsible for routing web requests to the proper application controllers, such as your Spring MVC @Controllers and web flows. - A typical DispatcherServlet declaration is shown below: -
-- <!-- The front controller of this Spring MVC application, responsible for handling all application requests --> - <servlet> - <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> - <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> - <init-param> - <param-name>contextConfigLocation</param-name> - <param-value> - /WEB-INF/spring/*.xml - </param-value> - </init-param> - <load-on-startup>1</load-on-startup> - </servlet> - - <!-- Map all /app requests to the DispatcherServlet for handling --> - <servlet-mapping> - <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> - <url-pattern>/app/*</url-pattern> - </servlet-mapping> --
- This DispatcherServlet is configured to process requests into /app/*. - The servlet's configuration is defined in the .xml files in /WEB-INF/spring. -
-- Inside /WEB-INF/spring, we generally recommend defining a configuration file for your application logic, - and separate configuration files for framework infrastructure. For example: -
-- /webapp - /WEB-INF - /spring - app-config.xml - mvc-config.xml - webflow-config.xml - web.xml --
- The example above shows the configuration for a Spring web application spread across three files. - The app-config.xml file configures your components that carry out application-specific controller, business, and data access logic. - The mvc-config.xml file configures the Spring MVC framework infrastructure, including the properties of the DispatcherServlet. - The webflow-config.xml file configures the Spring Web Flow infrastructure. -
-- We also generally recommend using annotations to configure your application components, and externalized XML to configure infrastructure. - This is illustrated in app-config.xml by use of the component-scan directive to scan your classpath for application components to deploy: -
-- <!-- Scans within the base package of the application for @Components to configure as beans --> - <context:component-scan base-package="org.springframework.webflow.samples.gettingstarted" /> --
- With this technique, your Spring configuration is setup once and you generally never have to update your configuration files again as new components are added to your application. -
-- In webflow-config.xml, first define a flow-registry to register the flows you have defined in your application: -
-- <!-- Registers the web flows that can be executed --> - <webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/"> - <webflow:flow-location-pattern value="**/*-flow.xml" /> - </webflow:flow-registry> --
- The example above scans /WEB-INF looking for -flow.xml files and registers them. -
-- Then, define a flow-executor that uses this registry to execute your flows: -
-- <!-- Configures the engine that executes web flows in this application --> - <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" /> --
- Finally, in mvc-config.xml plug in adapters to hook the flow-executor into the Spring MVC DispatcherServlet request processing pipeline: -
-- <!-- Maps requests to flows in the flowRegistry --> - <bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> - <property name="order" value="0" /> - <property name="flowRegistry" ref="flowRegistry" /> - </bean> - - <!-- Enables Spring Web Flow as a Spring MVC request handler --> - <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> - <property name="flowExecutor" ref="flowExecutor" /> - </bean> --
- We also recommend you turn on development mode while developing so you never have to redeploy your application to test changes: -
-- <webflow:flow-builder-services id="flowBuilderServices" development="true" /> --
- A typical Spring web application consists of a mix of stateless MVC @Controllers and stateful web flows, which are two distinct types of handlers. - When a web request comes in for a resource, the DispatcherServlet figures out which handler should be invoked. - This is done by consulting an ordered chain of HandlerMapping objects configured in your mvc-config.xml. - Generally, the first HandlerMapping consulted is the FlowHandlerMapping, which determines if the requested resource should be handled by a web flow. - If no flow handler is found, the next HandlerMapping in the chain is queried. - This is generally the DefaultAnnotationHandlerMapping, which consults explicit @RequestMapping rules defined inside annotated Spring MVC Controllers. -
-- Setting up the HandlerMapping chain is a one-time configuration step, and makes it easy to plug in different types of handlers and mapping strategies. - A typical HandlerMapping chain for Spring web applications looks like: -
-
- <!-- Maps requests to flows in the flowRegistry; for example, a request for resource /hotels/booking maps to a flow with id "hotels/booking"
- If no flow is found with that id, Spring MVC proceeds to the next HandlerMapping (order=1 below). -->
- <bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
- <property name="order" value="0" />
- <property name="flowRegistry" ref="flowRegistry" />
- </bean>
-
- <!-- Maps requests to @Controllers based on @RequestMapping("path") annotation values
- If no annotation-based path mapping is found, Spring MVC proceeds to the next HandlerMapping (order=2 below). -->
- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
- <property name="order" value="1" />
- </bean>
-
-- Once a request has been mapped to a handler object such as a @Controller of web flow, the DispatcherServlet uses the HandlerAdapter registered for that kind of handler to invoke it. - This decouples the DispatcherServlet from specific handler implementations, which allows Spring MVC to support different controller technologies in an extensible manner. - As a one-time configuration step, a typical Spring web application registers HandlerAdapters that know how to invoke @Controllers and web flows when they are mapped: -
-- <!-- Enables annotated @Controllers; responsible for invoking an annotated POJO @Controller when one is mapped. --> - <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> - - <!-- Enables web flows; responsible for calling the Spring Web Flow system to execute a flow when one is mapped. --> - <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> - <property name="flowExecutor" ref="flowExecutor" /> - </bean> --
- To illustrate a typical DispatcherServlet pipeline, the following graphic illustrates the sequence of events that happen in this application when the /tutorial resource is requested, which is handled by the web flow you are interacting with right now:
- " />
-
- In this scenario, the FlowHandlerMapping returned the tutorial flow which was then invoked by the FlowHandlerAdapter. -
-
- The following graphic shows the sequence in this application when the /welcome resource is requested, which is handled by the annotated WelcomeController:
- " />
-
- In this scenario, the FlowHandlerMapping returned null because the /welcome resource was not mapped to a web flow. - The DefaultAnnotationHandlerMapping was then queried and returned the WelcomeController, which was invoked by the AnnotationMethodHandlerAdapter. -
-- The main point to understand here is there is one-time configuration that enables full customization of the DispatcherServlet processing pipeline. - Once this configuration is established, you simply create new controllers and web flows, and they get picked up and hooked into the pipeline automatically. - No other configuration is required. -
-- Next > -
++ The configuration of every Spring web application starts in web.xml. + There, a Spring MVC DispatcherServlet is defined to process all requests into the application. + The DispatcherServlet itself is configured using a Spring container. + It is responsible for routing web requests to the proper application controllers, such as your Spring MVC @Controllers and web flows. + A typical DispatcherServlet declaration is shown below: +
++ <!-- The front controller of this Spring MVC application, responsible for handling all application requests --> + <servlet> + <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> + <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> + <init-param> + <param-name>contextConfigLocation</param-name> + <param-value> + /WEB-INF/spring/*.xml + </param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + + <!-- Map all /app requests to the DispatcherServlet for handling --> + <servlet-mapping> + <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> + <url-pattern>/app/*</url-pattern> + </servlet-mapping> ++
+ This DispatcherServlet is configured to process requests into /app/*. + The servlet's configuration is defined in the .xml files in /WEB-INF/spring. +
++ Inside /WEB-INF/spring, we generally recommend defining a configuration file for your application logic, + and separate configuration files for framework infrastructure. For example: +
++ /webapp + /WEB-INF + /spring + app-config.xml + mvc-config.xml + webflow-config.xml + web.xml ++
+ The example above shows the configuration for a Spring web application spread across three files. + The app-config.xml file configures your components that carry out application-specific controller, business, and data access logic. + The mvc-config.xml file configures the Spring MVC framework infrastructure, including the properties of the DispatcherServlet. + The webflow-config.xml file configures the Spring Web Flow infrastructure. +
++ We also generally recommend using annotations to configure your application components, and externalized XML to configure infrastructure. + This is illustrated in app-config.xml by use of the component-scan directive to scan your classpath for application components to deploy: +
++ <!-- Scans within the base package of the application for @Components to configure as beans --> + <context:component-scan base-package="org.springframework.webflow.samples.gettingstarted" /> ++
+ With this technique, your Spring configuration is setup once and you generally never have to update your configuration files again as new components are added to your application. +
++ In webflow-config.xml, first define a flow-registry to register the flows you have defined in your application: +
++ <!-- Registers the web flows that can be executed --> + <webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/"> + <webflow:flow-location-pattern value="**/*-flow.xml" /> + </webflow:flow-registry> ++
+ The example above scans /WEB-INF looking for -flow.xml files and registers them. +
++ Then, define a flow-executor that uses this registry to execute your flows: +
++ <!-- Configures the engine that executes web flows in this application --> + <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" /> ++
+ Finally, in mvc-config.xml plug in adapters to hook the flow-executor into the Spring MVC DispatcherServlet request processing pipeline: +
++ <!-- Maps requests to flows in the flowRegistry --> + <bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> + <property name="order" value="0" /> + <property name="flowRegistry" ref="flowRegistry" /> + </bean> + + <!-- Enables Spring Web Flow as a Spring MVC request handler --> + <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> + <property name="flowExecutor" ref="flowExecutor" /> + </bean> ++
+ We also recommend you turn on development mode while developing so you never have to redeploy your application to test changes: +
++ <webflow:flow-builder-services id="flowBuilderServices" development="true" /> ++
+ A typical Spring web application consists of a mix of stateless MVC @Controllers and stateful web flows, which are two distinct types of handlers. + When a web request comes in for a resource, the DispatcherServlet figures out which handler should be invoked. + This is done by consulting an ordered chain of HandlerMapping objects configured in your mvc-config.xml. + Generally, the first HandlerMapping consulted is the FlowHandlerMapping, which determines if the requested resource should be handled by a web flow. + If no flow handler is found, the next HandlerMapping in the chain is queried. + This is generally the DefaultAnnotationHandlerMapping, which consults explicit @RequestMapping rules defined inside annotated Spring MVC Controllers. +
++ Setting up the HandlerMapping chain is a one-time configuration step, and makes it easy to plug in different types of handlers and mapping strategies. + A typical HandlerMapping chain for Spring web applications looks like: +
+
+ <!-- Maps requests to flows in the flowRegistry; for example, a request for resource /hotels/booking maps to a flow with id "hotels/booking"
+ If no flow is found with that id, Spring MVC proceeds to the next HandlerMapping (order=1 below). -->
+ <bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
+ <property name="order" value="0" />
+ <property name="flowRegistry" ref="flowRegistry" />
+ </bean>
+
+ <!-- Maps requests to @Controllers based on @RequestMapping("path") annotation values
+ If no annotation-based path mapping is found, Spring MVC proceeds to the next HandlerMapping (order=2 below). -->
+ <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
+ <property name="order" value="1" />
+ </bean>
+
+ + Once a request has been mapped to a handler object such as a @Controller of web flow, the DispatcherServlet uses the HandlerAdapter registered for that kind of handler to invoke it. + This decouples the DispatcherServlet from specific handler implementations, which allows Spring MVC to support different controller technologies in an extensible manner. + As a one-time configuration step, a typical Spring web application registers HandlerAdapters that know how to invoke @Controllers and web flows when they are mapped: +
++ <!-- Enables annotated @Controllers; responsible for invoking an annotated POJO @Controller when one is mapped. --> + <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> + + <!-- Enables web flows; responsible for calling the Spring Web Flow system to execute a flow when one is mapped. --> + <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> + <property name="flowExecutor" ref="flowExecutor" /> + </bean> ++
+ To illustrate a typical DispatcherServlet pipeline, the following graphic illustrates the sequence of events that happen in this application when the /tutorial resource is requested, which is handled by the web flow you are interacting with right now:
+ " />
+
+ In this scenario, the FlowHandlerMapping returned the tutorial flow which was then invoked by the FlowHandlerAdapter. +
+
+ The following graphic shows the sequence in this application when the /welcome resource is requested, which is handled by the annotated WelcomeController:
+ " />
+
+ In this scenario, the FlowHandlerMapping returned null because the /welcome resource was not mapped to a web flow. + The DefaultAnnotationHandlerMapping was then queried and returned the WelcomeController, which was invoked by the AnnotationMethodHandlerAdapter. +
++ The main point to understand here is there is one-time configuration that enables full customization of the DispatcherServlet processing pipeline. + Once this configuration is established, you simply create new controllers and web flows, and they get picked up and hooked into the pipeline automatically. + No other configuration is required. +
++ Next > +
+