This commit is contained in:
Keith Donald
2009-03-23 15:38:11 +00:00
parent 36f424b263
commit 7564f5469e
2 changed files with 120 additions and 126 deletions

View File

@@ -68,14 +68,12 @@
<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;
&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>
@@ -91,29 +89,27 @@
<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;
&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;
&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;
&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&gt;
&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>
@@ -129,49 +125,47 @@
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;
&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;
package org.springframework.webflow.samples.helloworld;
import java.io.Serializable;
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;
}
}
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;
&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; ...
&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.
@@ -181,21 +175,21 @@
<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;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="page2"&gt;
&lt;/view-state&gt;
&lt;view-state id="page3"&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;
&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).
@@ -208,15 +202,15 @@
<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;
&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;
&lt;transition on="finish" to="finished" /&gt;
</pre>
And finally define the end-state:
<pre>
&lt;end-state id="finished" view="externalRedirect:welcome" /&gt;
&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>

View File

@@ -29,24 +29,24 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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/*.
@@ -62,13 +62,13 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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
/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.
@@ -81,8 +81,8 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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.
@@ -96,10 +96,10 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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.
@@ -108,29 +108,29 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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;
&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;
&lt;webflow:flow-builder-services id="flowBuilderServices" development="true" /&gt;
</pre>
</div>
<div id="question4" class="question">
@@ -150,18 +150,18 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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.
@@ -169,13 +169,13 @@ If you prefer to go right to implementing your first flow, you can <a href="tuto
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;
&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>