This commit is contained in:
Keith Donald
2009-03-23 15:20:20 +00:00
parent 0a062cba37
commit 36f424b263
5 changed files with 480 additions and 393 deletions

View File

@@ -3,8 +3,13 @@
<html>
<head>
<title>Getting Started with Spring Web Flow: Creating Your First Web Flow</title>
<link rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css"/>" type="text/css" />
<link rel="stylesheet" href="<c:url value="/resources/styles/tutorial.css"/>" type="text/css" />
<script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js"/>"></script>
</head>
<body>
<body class="tundra">
<h1>
Creating Your First Web Flow
</h1>
@@ -28,185 +33,211 @@
<h2>
Step-by-step instructions for creating your first flow using the Eclipse-based SpringSource Tool Suite IDE:
</h2>
<h3>Setup the project development environment</h3>
<ol>
<li>
Download <a href="http://www.springsource.com/products/sts">SpringSource Tool Suite</a> (STS) and the latest <a href="http://www.springsource.org/download#webflow">Spring Web Flow 2.0.x release</a>.
After downloading completes, extract both archives to your directory of choice.
</li>
<li>
Open STS and access File -&gt; Import... -&gt; Existing Projects Into Workspace. Select Browse... and navigate to where you extracted the Spring Web Flow release.
Select the spring-webflow-samples/getting-started-with-spring-webflow folder and import the project.
</li>
<li>
After the project import, if you do not already have a servlet container such as Tomcat installed on your workstation you can uses STS to install an embedded Tomcat instance.
To do this, select the SpringSource logo on the tool bar, access the Configuration tab, and select Create Server Instance.
</li>
<li>
Next, right-click on the project in your Package Explorer view, and select Run On Server.
Select the server runtime you wish to deploy to and finish to deploy the project.
You should see the tutorial welcome page appear in the embedded web browser.
Alternatively, you can access the application in an external browser such as Firefox at <a href="http://localhost:8080/getting-started-with-spring-webflow">http://localhost:8080/getting-started-with-spring-webflow</a>
</li>
</ol>
<h3>Create your first helloworld flow</h3>
<ol>
<li>
Once the application is running, create a new directory for your flow inside /src/main/webapp/WEB-INF; name the directory helloworld.
Next, right-click on the directory and access New -&gt; Spring Web Flow Definition.
Enter the filename helloworld-flow.xml and finish.
The flow definition will be generated for you with an initial view-state named start.
</li>
<li>
Go ahead and create a start.jsp in your flow directory and paste in the following:
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
Hello world!
&lt;/h1&gt;
&lt;/html&gt;
</pre>
</li>
<li>
From the Servers view, restart your server, then startup your flow by accessing <a href="http://localhost:8080/getting-started-with-spring-webflow/app/helloworld">http://localhost:8080/getting-started-with-spring-webflow/app/helloworld</a>.
You should see your Hello world! message display.
Note you only have to restart your server when you add new flows to the system. When you change flows, changes will be refreshed automatically.
</li>
</ol>
<h3>Add a navigation rule</h3>
<ol>
<li>
Next, try transitioning your flow from one state to another to implement a navigation rule. In your helloworld flow, add the following transition to your start view-state:
<pre>
&lt;transition on="submit" to="page2" /&gt;
</pre>
Then define your page2 view-state:
<pre>
&lt;view-state id="page2"&gt;
&lt;/view-state&gt;
</pre>
And the corresponding page2.jsp:
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
This is page 2!
&lt;/h1&gt;
&lt;/html&gt;
</pre>
Finally, create a button on your start.jsp that raises the submit event to trigger the state transition:
<pre>
&lt;form method="post"&gt;
&lt;input type="submit" name="_eventId_submit" value="Submit" /&gt;
&lt;/form&gt;
</pre>
Click the button and you should be taken to page 2.
</li>
</ol>
<h3>Add a dynamic navigation rule</h3>
<p>
Web flow excels at implementing dynamic navigation logic that takes a user through different paths based on what they enter or who they are.
</p>
<ol>
<li>
Try implementing a dynamic navigation rule by first adding a bound checkbox to your start.jsp.
Do this by replacing the contents of your start.jsp with the following snippet:
<pre>
&lt;%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
Hello world!
&lt;/h1&gt;
&lt;form:form method="post" modelAttribute="helloWorldForm"&gt;
&lt;form:checkbox path="selected" /&gt;
<div id="section1" class="section">
<h3>Setup your project</h3>
<ol>
<li>
Download <a href="http://www.springsource.com/products/sts">SpringSource Tool Suite</a> (STS) and the latest <a href="http://www.springsource.org/download#webflow">Spring Web Flow 2.0.x release</a>.
After downloading completes, extract both archives to your directory of choice.
</li>
<li>
Open STS and access File -&gt; Import... -&gt; Existing Projects Into Workspace. Select Browse... and navigate to where you extracted the Spring Web Flow release.
Select the <span class="file">spring-webflow-samples/getting-started-with-spring-webflow</span> folder and import the project.
</li>
<li>
After the project import, if you do not already have a servlet container such as Tomcat installed on your workstation you can uses STS to install an embedded Tomcat instance.
To do this, select the SpringSource logo on the tool bar, access the Configuration tab, and select Create Server Instance.
</li>
<li>
Next, right-click on the project in your Package Explorer view, and select Run On Server.
Select the server runtime you wish to deploy to and finish to deploy the project.
You should see the tutorial welcome page appear in the embedded web browser.
Alternatively, you can access the application in an external browser such as Firefox at <a href="http://localhost:8080/getting-started-with-spring-webflow">http://localhost:8080/getting-started-with-spring-webflow</a>
</li>
</ol>
</div>
<div id="section2" class="section">
<h3>Create your first helloworld flow</h3>
<ol>
<li>
Once the application is running, create a new directory for your flow inside <span class="file">/src/main/webapp/WEB-INF</span>; name the directory <span class="file">helloworld</span>.
Next, right-click on the directory and access New -&gt; Spring Web Flow Definition.
Enter the filename <span class="file">helloworld-flow.xml</span> and finish.
The flow definition will be generated for you with an initial view-state named start.
</li>
<li>
Go ahead and create a <span class="file">start.jsp</span> in your flow directory and paste in the following:
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
Hello world!
&lt;/h1&gt;
&lt;/html&gt;
</pre>
</li>
<li>
From the Servers view, restart your server, then startup your flow by accessing <a href="http://localhost:8080/getting-started-with-spring-webflow/app/helloworld">http://localhost:8080/getting-started-with-spring-webflow/app/helloworld</a>.
You should see your Hello world! message display.
Note you only have to restart your server when you add new flows to the system. When you change flows, changes will be refreshed automatically.
</li>
</ol>
</div>
<div id="section3" class="section">
<h3>Add a navigation rule</h3>
<ol>
<li>
Next, try transitioning your flow from one state to another to implement a navigation rule. In your helloworld flow, add the following transition to your start view-state:
<pre>
&lt;transition on="submit" to="page2" /&gt;
</pre>
Then define your page2 view-state:
<pre>
&lt;view-state id="page2"&gt;
&lt;/view-state&gt;
</pre>
And the corresponding page2.jsp:
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
This is page 2!
&lt;/h1&gt;
&lt;/html&gt;
</pre>
Finally, create a button on your <span class="file">start.jsp</span> that raises the submit event to trigger the state transition:
<pre>
&lt;form method="post"&gt;
&lt;input type="submit" name="_eventId_submit" value="Submit" /&gt;
&lt;/form:form&gt;
&lt;/html&gt;
</pre>
</li>
<li>
Next, create a HelloWorldForm class in the org.springframework.webflow.samples.helloworld package with the following code:
<pre>
package org.springframework.webflow.samples.helloworld;
&lt;/form&gt;
</pre>
Click the button and you should be taken to page 2.
</li>
</ol>
</div>
<div id="section4" class="section">
<h3>Add a dynamic navigation rule</h3>
<p>
Web flow excels at implementing dynamic navigation logic that takes a user through different paths based on what they enter or who they are.
</p>
<ol>
<li>
Try implementing a dynamic navigation rule by first adding a bound checkbox to your <span class="file">start.jsp</span>.
Do this by replacing its contents with the following snippet:
<pre>
&lt;%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Hello world!&lt;/title&gt;
&lt;/head&gt;
&lt;h1&gt;
Hello world!
&lt;/h1&gt;
&lt;form:form method="post" modelAttribute="helloWorldForm"&gt;
&lt;form:checkbox path="selected" /&gt;
&lt;input type="submit" name="_eventId_submit" value="Submit" /&gt;
&lt;/form:form&gt;
&lt;/html&gt;
</pre>
</li>
<li>
Next, create a <span class="file">HelloWorldForm</span> class in the <span class="file">org.springframework.webflow.samples.helloworld</span> package with the following code:
<pre>
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;
}
}
</pre>
</li>
<li>
At the top of your helloworld-flow, declare the HelloWorldForm as a flow variable:
<pre>
&lt;var name="helloWorldForm" class="org.springframework.webflow.samples.helloworld.HelloWorldForm" /&gt;
</pre>
Then update your start view-state to use this variable as its data model, enabling automatic model binding and validation:
<pre>
&lt;view-state id="start" model="helloWorldForm"&gt; ...
</pre>
<p>
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.
</p>
</li>
<li>
Now insert a decision state that says if the checkbox is selected goto page2, else goto a new page3:
<pre>
&lt;decision-state id="isSelected"&gt;
&lt;if test="helloWorldForm.selected" then="page2" else="page3" /&gt;
&lt;/decision-state&gt;
import java.io.Serializable;
public class HelloWorldForm implements Serializable {
private boolean selected = true;
&lt;view-state id="page2"&gt;
&lt;/view-state&gt;
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
</pre>
</li>
<li>
At the top of your helloworld-flow, declare the HelloWorldForm as a flow variable:
<pre>
&lt;var name="helloWorldForm" class="org.springframework.webflow.samples.helloworld.HelloWorldForm" /&gt;
</pre>
Then update your start view-state to use this variable as its data model, enabling automatic model binding and validation:
<pre>
&lt;view-state id="start" model="helloWorldForm"&gt; ...
</pre>
<p>
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.
</p>
</li>
<li>
Now insert a decision state that says if the checkbox is selected goto page2, else goto a new page3:
<pre>
&lt;decision-state id="isSelected"&gt;
&lt;if test="helloWorldForm.selected" then="page2" else="page3" /&gt;
&lt;/decision-state&gt;
&lt;view-state id="page2"&gt;
&lt;/view-state&gt;
&lt;view-state id="page3"&gt;
&lt;/view-state&gt;
</pre>
Be sure to update your start view-state to transition to the isSelected decision state instead of page2 directly:
<pre>
&lt;view-state id="start"&gt;
&lt;transition on="submit" to="isSelected" /&gt;
&lt;/view-state&gt;
</pre>
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).
</li>
</ol>
<h3>Finish your helloworld flow</h3>
<ol>
<li>
Finish up your helloworld flow by adding another button on the start.jsp that ends the flow:
<pre>
&lt;input type="submit" name="_eventId_finish" value="Finish" /&gt;
</pre>
In your start view-state, declare the finish transition:
<pre>
&lt;transition on="finish" to="finished" /&gt;
</pre>
And finally define the end-state:
<pre>
&lt;end-state id="finished" view="externalRedirect:welcome" /&gt;
</pre>
Click the Finish button and you should be taken back to the application welcome screen.
</li>
</ol>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
&lt;view-state id="page3"&gt;
&lt;/view-state&gt;
</pre>
Be sure to update your start view-state to transition to the isSelected decision state instead of page2 directly:
<pre>
&lt;view-state id="start"&gt;
&lt;transition on="submit" to="isSelected" /&gt;
&lt;/view-state&gt;
</pre>
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).
</li>
</ol>
</div>
<div id="section5" class="section">
<h3>Finish your helloworld flow</h3>
<ol>
<li>
Finish up your helloworld flow by adding another button on the <span class="file">start.jsp</span> that ends the flow:
<pre>
&lt;input type="submit" name="_eventId_finish" value="Finish" /&gt;
</pre>
In your start view-state, declare the finish transition:
<pre>
&lt;transition on="finish" to="finished" /&gt;
</pre>
And finally define the end-state:
<pre>
&lt;end-state id="finished" view="externalRedirect:welcome" /&gt;
</pre>
Click the Finish button and you should be taken back to the application welcome screen.
</li>
</ol>
</div>
<div id="commandBar">
<p>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
</p>
</div>
</body>
<script type="text/javascript">
dojo.query('.section > h3').forEach(function(titleElement){
Spring.addDecoration(new Spring.ElementDecoration({
elementId : titleElement.parentNode.id,
widgetType : 'dijit.TitlePane',
widgetAttrs : {
title : titleElement.innerHTML,
open : false
}
}));
}).style('display','none');
</script>
</html>

View File

@@ -3,46 +3,59 @@
<html>
<head>
<title>Getting Started with Spring Web Flow: Overview of the Spring Web Flow Project</title>
<link rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css"/>" type="text/css" />
<link rel="stylesheet" href="<c:url value="/resources/styles/tutorial.css"/>" type="text/css" />
<script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js"/>"></script>
</head>
<body>
<body class="tundra">
<h1>
Overview of the Spring Web Flow Project
</h1>
<h2>
What is Spring Web Flow?
</h2>
<p>
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.
</p>
<h2>
When do I use Web Flow?
</h2>
<p>
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 <i>flow definition language</i> for authoring flows that define screen navigation rules.
The framework also cares for managing conversational state and preventing duplicate transactions.
</p>
<h2>
How does Web Flow relate to other Spring projects?
</h2>
<p>
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.
</p>
<p>
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.
</p>
<p>
How Spring Web Flow fits into Spring's layered, a-la-carte "Web Stack" is illustrated below:<br>
<img src="<c:url value="/resources/images/tutorial/spring-web-stack.png" />" />
</p>
<p>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
</p>
<div id="question1" class="question">
<h2>
What is Spring Web Flow?
</h2>
<p>
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.
</p>
</div>
<div id="question2" class="question">
<h2>
When do I use Web Flow?
</h2>
<p>
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 <i>flow definition language</i> for authoring flows that define screen navigation rules.
The framework also cares for managing conversational state and preventing duplicate transactions.
</p>
</div>
<div id="question3" class="question">
<h2>
How does Web Flow relate to other Spring projects?
</h2>
<p>
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.
</p>
<p>
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.
</p>
<p>
How Spring Web Flow fits into Spring's layered, a-la-carte "Web Stack" is illustrated below:<br>
<img src="<c:url value="/resources/images/tutorial/spring-web-stack.png" />" />
</p>
</div>
<div id="commandBar">
<p>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
</p>
</div>
</body>
</html>

View File

@@ -3,8 +3,13 @@
<html>
<head>
<title>Getting Started with Spring Web Flow: Setting up Web Flow in a Spring Web Application</title>
<link rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css"/>" type="text/css" />
<link rel="stylesheet" href="<c:url value="/resources/styles/tutorial.css"/>" type="text/css" />
<script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js"/>"></script>
</head>
<body>
<body class="tundra">
<h1>
Setting up Web Flow in a Spring Web Application
</h1>
@@ -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 <a href="tutorial?execution=${flowExecutionKey}&_eventId=next"">skip</a> this step.
</p>
<h2>
What does the configuration of a typical Spring web application look like?
</h2>
<p>
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:
</p>
<pre class="code">
&lt;!-- The front controller of this Spring MVC application, responsible for handling all application requests --&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;Spring MVC Dispatcher Servlet&lt;/servlet-name&gt;
&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
&lt;param-value&gt;
/WEB-INF/spring/*.xml
&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;!-- Map all /app requests to the DispatcherServlet for handling --&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;Spring MVC Dispatcher Servlet&lt;/servlet-name&gt;
&lt;url-pattern&gt;/app/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
</pre>
<p>
This DispatcherServlet is configured to process requests into /app/*.
The servlet's configuration is defined in the .xml files in /WEB-INF/spring.
</p>
<h2>
How are Spring configuration files typically organized?
</h2>
<p>
Inside /WEB-INF/spring, we generally recommend defining a configuration file for your application logic,
and separate configuration files for framework infrastructure. For example:
</p>
<pre class="code">
/webapp
/WEB-INF
/spring
app-config.xml
mvc-config.xml
webflow-config.xml
web.xml
</pre>
<p>
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.
</p>
<p>
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:
</p>
<pre class="code">
&lt;!-- Scans within the base package of the application for @Components to configure as beans --&gt;
&lt;context:component-scan base-package="org.springframework.webflow.samples.gettingstarted" /&gt;
</pre>
<p>
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.
</p>
<h2>
How do I plug-in Spring Web Flow?
</h2>
<p>
In webflow-config.xml, first define a flow-registry to register the flows you have defined in your application:
</p>
<pre class="code">
&lt;!-- Registers the web flows that can be executed --&gt;
&lt;webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/"&gt;
&lt;webflow:flow-location-pattern value="**/*-flow.xml" /&gt;
&lt;/webflow:flow-registry&gt;
</pre>
<p>
The example above scans /WEB-INF looking for -flow.xml files and registers them.
</p>
<p>
Then, define a flow-executor that uses this registry to execute your flows:
</p>
<pre class="code">
&lt;!-- Configures the engine that executes web flows in this application --&gt;
&lt;webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" /&gt;
</pre>
<p>
Finally, in mvc-config.xml plug in adapters to hook the flow-executor into the Spring MVC DispatcherServlet request processing pipeline:
</p>
<pre class="code">
&lt;!-- Maps requests to flows in the flowRegistry --&gt;
&lt;bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"&gt;
&lt;property name="order" value="0" /&gt;
&lt;property name="flowRegistry" ref="flowRegistry" /&gt;
&lt;/bean&gt;
&lt;!-- Enables Spring Web Flow as a Spring MVC request handler --&gt;
&lt;bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"&gt;
&lt;property name="flowExecutor" ref="flowExecutor" /&gt;
&lt;/bean&gt;
</pre>
<p>
We also recommend you turn on development mode while developing so you never have to redeploy your application to test changes:
</p>
<pre class="code">
&lt;webflow:flow-builder-services id="flowBuilderServices" development="true" /&gt;
</pre>
<h2>
How do Spring MVC @Controllers and Web Flows co-exist in the same application?
</h2>
<p>
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.
</p>
<p>
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:
</p>
<pre class="code">
&lt;!-- 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). --&gt;
&lt;bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"&gt;
&lt;property name="order" value="0" /&gt;
&lt;property name="flowRegistry" ref="flowRegistry" /&gt;
&lt;/bean&gt;
&lt;!-- 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). --&gt;
&lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt;
&lt;property name="order" value="1" /&gt;
&lt;/bean&gt;
</pre>
<p>
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:
</p>
<pre class="code">
&lt;!-- Enables annotated @Controllers; responsible for invoking an annotated POJO @Controller when one is mapped. --&gt;
&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /&gt;
&lt;!-- Enables web flows; responsible for calling the Spring Web Flow system to execute a flow when one is mapped. --&gt;
&lt;bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"&gt;
&lt;property name="flowExecutor" ref="flowExecutor" /&gt;
&lt;/bean&gt;
</pre>
<p>
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:<br>
<img src="<c:url value="/resources/images/tutorial/dispatcher-servlet-flow-handler.png" />" />
</p>
<p>
In this scenario, the FlowHandlerMapping returned the tutorial flow which was then invoked by the FlowHandlerAdapter.
</p>
<p>
The following graphic shows the sequence in this application when the /welcome resource is requested, which is handled by the annotated WelcomeController:<br>
<img src="<c:url value="/resources/images/tutorial/dispatcher-servlet-annotated-controller-handler.png" />" />
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
</p>
<div id="question1" class="question">
<h2>
What does the configuration of a typical Spring web application look like?
</h2>
<p>
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:
</p>
<pre class="code">
&lt;!-- The front controller of this Spring MVC application, responsible for handling all application requests --&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;Spring MVC Dispatcher Servlet&lt;/servlet-name&gt;
&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
&lt;param-value&gt;
/WEB-INF/spring/*.xml
&lt;/param-value&gt;
&lt;/init-param&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;!-- Map all /app requests to the DispatcherServlet for handling --&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;Spring MVC Dispatcher Servlet&lt;/servlet-name&gt;
&lt;url-pattern&gt;/app/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
</pre>
<p>
This DispatcherServlet is configured to process requests into /app/*.
The servlet's configuration is defined in the .xml files in /WEB-INF/spring.
</p>
</div>
<div id="question2" class="question">
<h2>
How are Spring configuration files typically organized?
</h2>
<p>
Inside /WEB-INF/spring, we generally recommend defining a configuration file for your application logic,
and separate configuration files for framework infrastructure. For example:
</p>
<pre class="code">
/webapp
/WEB-INF
/spring
app-config.xml
mvc-config.xml
webflow-config.xml
web.xml
</pre>
<p>
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.
</p>
<p>
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:
</p>
<pre class="code">
&lt;!-- Scans within the base package of the application for @Components to configure as beans --&gt;
&lt;context:component-scan base-package="org.springframework.webflow.samples.gettingstarted" /&gt;
</pre>
<p>
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.
</p>
</div>
<div id="question3" class="question">
<h2>
How do I plug-in Spring Web Flow?
</h2>
<p>
In webflow-config.xml, first define a flow-registry to register the flows you have defined in your application:
</p>
<pre class="code">
&lt;!-- Registers the web flows that can be executed --&gt;
&lt;webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/"&gt;
&lt;webflow:flow-location-pattern value="**/*-flow.xml" /&gt;
&lt;/webflow:flow-registry&gt;
</pre>
<p>
The example above scans /WEB-INF looking for -flow.xml files and registers them.
</p>
<p>
Then, define a flow-executor that uses this registry to execute your flows:
</p>
<pre class="code">
&lt;!-- Configures the engine that executes web flows in this application --&gt;
&lt;webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry" /&gt;
</pre>
<p>
Finally, in mvc-config.xml plug in adapters to hook the flow-executor into the Spring MVC DispatcherServlet request processing pipeline:
</p>
<pre class="code">
&lt;!-- Maps requests to flows in the flowRegistry --&gt;
&lt;bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"&gt;
&lt;property name="order" value="0" /&gt;
&lt;property name="flowRegistry" ref="flowRegistry" /&gt;
&lt;/bean&gt;
&lt;!-- Enables Spring Web Flow as a Spring MVC request handler --&gt;
&lt;bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"&gt;
&lt;property name="flowExecutor" ref="flowExecutor" /&gt;
&lt;/bean&gt;
</pre>
<p>
We also recommend you turn on development mode while developing so you never have to redeploy your application to test changes:
</p>
<pre class="code">
&lt;webflow:flow-builder-services id="flowBuilderServices" development="true" /&gt;
</pre>
</div>
<div id="question4" class="question">
<h2>
How do Spring MVC @Controllers and Web Flows co-exist in the same application?
</h2>
<p>
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.
</p>
<p>
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:
</p>
<pre class="code">
&lt;!-- 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). --&gt;
&lt;bean id="flowMappings" class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"&gt;
&lt;property name="order" value="0" /&gt;
&lt;property name="flowRegistry" ref="flowRegistry" /&gt;
&lt;/bean&gt;
&lt;!-- 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). --&gt;
&lt;bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"&gt;
&lt;property name="order" value="1" /&gt;
&lt;/bean&gt;
</pre>
<p>
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:
</p>
<pre class="code">
&lt;!-- Enables annotated @Controllers; responsible for invoking an annotated POJO @Controller when one is mapped. --&gt;
&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /&gt;
&lt;!-- Enables web flows; responsible for calling the Spring Web Flow system to execute a flow when one is mapped. --&gt;
&lt;bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"&gt;
&lt;property name="flowExecutor" ref="flowExecutor" /&gt;
&lt;/bean&gt;
</pre>
<p>
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:<br>
<img src="<c:url value="/resources/images/tutorial/dispatcher-servlet-flow-handler.png" />" />
</p>
<p>
In this scenario, the FlowHandlerMapping returned the tutorial flow which was then invoked by the FlowHandlerAdapter.
</p>
<p>
The following graphic shows the sequence in this application when the /welcome resource is requested, which is handled by the annotated WelcomeController:<br>
<img src="<c:url value="/resources/images/tutorial/dispatcher-servlet-annotated-controller-handler.png" />" />
</p>
<p>
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.
</p>
<p>
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.
</p>
</div>
<div id="commandBar">
<p>
<a href="tutorial?execution=${flowExecutionKey}&_eventId=next">Next &gt;</a>
</p>
</div>
</body>
<script type="text/javascript">
dojo.query('.question > h2').forEach(function(titleElement){
Spring.addDecoration(new Spring.ElementDecoration({
elementId : titleElement.parentNode.id,
widgetType : 'dijit.TitlePane',
widgetAttrs : {
title : titleElement.innerHTML,
open : false
}
}));
}).style('display','none');
</script>
</html>

View File

@@ -3,8 +3,13 @@
<html>
<head>
<title>Getting Started with Spring Web Flow: Where To Go From Here</title>
<link rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css"/>" type="text/css" />
<link rel="stylesheet" href="<c:url value="/resources/styles/tutorial.css"/>" type="text/css" />
<script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js"/>"></script>
<script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js"/>"></script>
</head>
<body>
<body class="tundra">
<h1>
Where To Go with From Here
</h1>

View File

@@ -0,0 +1,11 @@
.dijitTitlePane + .dijitTitlePane {
padding-top: 1em;
}
.file {
font-family: monospace;
}
ol li {
padding-bottom: 1em;
}