mvc and upgrade guide updates

This commit is contained in:
Keith Donald
2008-04-13 07:27:14 +00:00
parent ec96e9bb51
commit 4e58e543de
2 changed files with 216 additions and 134 deletions

View File

@@ -12,10 +12,13 @@
<sect1 id="spring-mvc-config-web.xml">
<title>Configuring web.xml</title>
<para>
The first step to using Spring MVC is to route requests to the <code>DispatcherServlet</code> in the <code>web.xml</code> file.
In this example, we map all URLs that begin with <code>/spring/</code> to the servlet.
An <code>init-param</code> is used to pass the <code>contextConfigLocation</code>.
This is the location of the Spring configuration for the application.
The first step to using Spring MVC is to configure the <code>DispatcherServlet</code> in <code>web.xml</code>.
You typically do this once per web application.
</para>
<para>
The example below maps all requests that begin with <code>/spring/</code> to the DispatcherServlet.
An <code>init-param</code> is used to provide the <code>contextConfigLocation</code>.
This is configuration file for the web application.
</para>
<programlisting language="xml"><![CDATA[
<servlet>
@@ -25,121 +28,207 @@
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-application-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>
]]></programlisting>
</servlet-mapping>]]></programlisting>
</sect1>
<sect1 id="spring-mvc-config-spring">
<title>Configuring Spring</title>
<sect2 id="spring-mvc-config-spring-url-mapping">
<title>URL Mapping</title>
<para>
Inside the <code>DispatcherServlet</code> request need to be mapped with finer grain.
Using a <code>SimpleUrlHandlerMapping</code>, request URLs are mapped to controllers and handlers.
</para>
<programlisting language="xml"><![CDATA[
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<sect1 id="spring-mvc-config-spring-url-mapping">
<title>Mapping URLs to Flows</title>
<para>
The <code>DispatcherServlet</code> maps request URLs to handlers.
A simple way to create URL mapping rules is to define a <code>SimpleUrlHandlerMapping</code>:
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowUrlMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/hotels/*=hotelsController
/hotels/booking=bookingFlowHandler
</value>
</property>
</bean>
]]></programlisting>
</bean>]]>
</programlisting>
<para>
The example above maps the servlet-relative request URL <code>/hotels/booking</code> to the <code>bookingFlowHandler</code>.
</para>
</sect1>
<sect1 id="spring-mvc-config-flow-handlers">
<title>Flow Handlers</title>
<para>
A <code>FlowHandler</code> manages executions of a single flow definition.
A <code>FlowHandler</code> is responsible for:
</para>
<itemizedlist>
<listitem>
<para>Providing the <code>id</code> of the flow definition to execute</para>
</listitem>
<listitem>
<para>Creating the input to pass new flow executions</para>
</listitem>
<listitem>
<para>Handling flow execution outcomes</para>
</listitem>
<listitem>
<para>Handling flow execution exceptions</para>
</listitem>
</itemizedlist>
<para>
These responsibilities are illustrated in the definition of the <code>org.springframework.mvc.servlet.FlowHandler</code> interface:
</para>
<programlisting type="java">
public interface FlowHandler {
public String getFlowId();
public MutableAttributeMap createExecutionInputMap(HttpServletRequest request);
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request, HttpServletResponse response);
public ModelAndView handleException(FlowException e, HttpServletRequest request, HttpServletResponse response);
}
</programlisting>
<para>
To implement a FlowHandler, subclass <code>AbstractFlowHandler</code>. You only need to override the methods that you need.
Specifically:
</para>
<itemizedlist>
<listitem>
<para>
Override <code>getFlowId(HttpServletRequest)</code> when the id of your flow cannot be derived from the URL.
By default, the flow id is derived from the last path element in the request URI, before any query parameters.
For example, <code>http://localhost/hotels/booking?hotelId=1</code> results in a flow id of <code>booking</code> by default.
</para>
</listitem>
<listitem>
<para>
Override <code>createExecutionInputMap(HttpServletRequest)</code> when you need fine-grained control over extracting
flow input parameters from the HttpServletRequest. By default, all request parameters are treated as flow input parameters.
</para>
</listitem>
<listitem>
<para>
Override <code>handleExecutionOutcome</code> when you need to handle specific flow execution outcomes in a custom manner.
The default behavior sends a redirect to the ended flow's URL to restart a new execution of the flow.
</para>
</listitem>
<listitem>
<para>
Override <code>handleException</code> when you need fine-grained control over unhandled flow exceptions.
The default behavior attempts to restart the flow when a client attempts to access an ended or expired flow execution.
Any other exception is rethrown to the Spring MVC ExceptionResolver infrastructure by default.
</para>
</listitem>
</itemizedlist>
<sect2 id="spring-mvc-flow-handler-example">
<title>Example FlowHandler</title>
<para>
In this example both a standard MVC controller and a Web Flow handler are configured.
The <code>hotelsController</code> supports the free navigation aspects of searching and viewing hotels.
The <code>bookingFlowHandler</code> supports the controlled navigation aspect of booking a hotel room.
A common interaction pattern between Spring MVC And Web Flow is for a Flow to redirect to a Controller when it ends.
FlowHandlers allow this to be done without coupling the flow definition with a specific controller URL.
An example FlowHandler that redirects to a Spring MVC Controller is shown below:
</para>
</sect2>
<sect2 id="spring-mvc-config-spring-flow-controllers">
<title>Flow Controllers</title>
<para>
Flow controllers provide a basic hook from Spring MVC into Web Flow.
The <code>FlowController</code> class is an implementation of MVC's <code>Controller</code> interface.
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
<constructor-arg ref="flowExecutor"/>
</bean>
]]></programlisting>
<para>
Web Flow 1.0 used controllers as the only way to hook Web Flow into Spring MVC.
With Web Flow 2.0 flow controllers should be used when the flow is self contained and does not need to interact with the environment.
</para>
</sect2>
<sect2 id="spring-mvc-config-spring-flow-adapters">
<title>Flow Adapters</title>
<para>
Flow adapters provide a richer integration point between Spring MVC and Web Flow.
The flow adapter provides hooks into the flow execution that can:
<itemizedlist>
<listitem>
<para>select the flow to execute (by default the flow id is inferred from the URL)</para>
</listitem>
<listitem>
<para>pass input parameters to the flow on initialization</para>
</listitem>
<listitem>
<para>handle the flow execution outcome</para>
</listitem>
<listitem>
<para>handle exceptions</para>
</listitem>
</itemizedlist>
</para>
<para>
A flow handler should be used whenever integration with any of these hooks is desired.
</para>
<para>
The <code>AbstractFlowHandler</code> class is an implementation of <code>FlowHandler</code> that provides default implementations for these hooks.
</para>
<para>
A common pattern to handle a flow outcome is to redirect to a new page instead of rendering a view in the <code>end-state</code>.
This allows the URL to be refreshed without throwing an exception.
</para>
<programlisting language="xml"><![CDATA[
<bean id="bookingFlowHandler"
class="org.springframework.webflow.samples.booking.BookingFlowHandler" />
]]></programlisting>
<programlisting language="java"><![CDATA[
public class BookingFlowHandler extends AbstractFlowHandler {
public ModelAndView handleExecutionOutcome(String outcome, AttributeMap output,
HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView(new RedirectView("/spring/hotels/index", true));
public String handleExecutionOutcome(String outcome, AttributeMap output, HttpServletRequest request, HttpServletResponse response) {
if (outcome.equals("bookingConfirmed")) {
return "booking/show?bookingId=" + output.get("bookingId");
} else {
return "hotels/index";
}
}
}
]]></programlisting>
</sect2>
<sect2 id="spring-mvc-config-spring-view-resolution">
<title>View Resolution</title>
}]]>
</programlisting>
<para>
Views in Web Flow 2.0 attempt to automatically resolve unless explicitly specified.
In a Spring MVC environment, a <code>view-state</code> will try to find a JSP view based on the <code>id</code> of the state.
For example, <code>&lt;view-state id="intro"&gt;</code> will resolve to <code>intro.jsp</code> in the same directory as the flow definition.
By specifying the <code>view</code> attribute, a different file name can be selected, however, it must still be a JSP file.
Since this handler only needs to handle flow execution outcomes in a custom manner, nothing else is overridden.
The <code>bookingConfirmed</code> outcome will result in a redirect to show the new booking.
Any other outcome will redirect back to the hotels index page.
</para>
<para>
A custom view resolver is required if different behavior is needed.
To create a custom view resolver the <code>flow-builder-services</code> attribute on <code>flow-registry</code> must define a new <code>webflow:flow-builder-services</code> element with a <code>view-factory-creator</code>.
To use your FlowHandler, first deploy an instance to Spring so it can be mapped to a URL:
</para>
<programlisting language="xml"><![CDATA[
<bean id="bookingFlowHandler" class="org.springframework.webflow.samples.booking.BookingFlowHandler" />]]>
</programlisting>
<para>
Then add the URL mapping rule:
</para>
<programlisting language="xml"><![CDATA[
<property name="mappings">
<value>
/hotels/booking=bookingFlowHandler
</value>
</property>]]>
</programlisting>
<para>
With this configuration, accessing the URL <code>/hotels/booking</code> will launch the <code>booking</code> flow.
When the booking flow ends, the FlowHandler will process the flow execution outcome and redirect to the appropriate controller.
</para>
</sect2>
<sect2 id="spring-mvc-flow-handler-adapter">
<title>Registering the FlowHandlerAdapter</title>
<para>
To enable flow handlers, make sure you define the special <code>FlowHandlerAdapter</code>. You only need to do this once.
</para>
<programlisting language="xml"><![CDATA[
<!-- Enables FlowHandler URL mapping -->
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<constructor-arg ref="flowExecutor" />
</bean>
]]>
</programlisting>
</sect2>
</sect1>
<sect1 id="spring-mvc-config-spring-flow-controllers">
<title>Flow Controller</title>
<para>
With the FlowHandler MVC integration approach, you define one handler per flow.
This is overkill in the cases where default flow handling rules are sufficient.
</para>
<para>
For simple cases, consider using the <code>FlowController</code> to map flow requests to a single handler.
You only have to configure this controller once and it will apply the flow handling defaults outlined in the previous section.
Also, you can still override these defaults by configuring the controller's <code>flowHandlers</code> property.
</para>
<para>
Below is a typical <code>FlowController</code> definition:
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">
<constructor-arg ref="flowExecutor"/>
</bean>]]>
</programlisting>
<para>
Below illustrates several URLs mapped to this controller:
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowUrlMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/hotels/booking=flowController
/login=flowController
</value>
</property>
</bean>]]>
</programlisting>
<para>
With this configuration, accessing <code>/login</code> launches the login flow.
Accessing <code>/hotels/booking</code> launches the booking flow.
</para>
</sect1>
<sect1 id="spring-mvc-config-spring-view-resolution">
<title>View Resolution</title>
<para>
Web Flow 2 maps selected view identifiers to files located within the flow's working directory unless otherwise specified.
For existing Spring MVC + Web Flow applications, an external <code>ViewResolver</code> is likely already handling this mapping for you.
Therefore, to continue using that resolver and to avoid having to change how your existing flow views are packaged, configure Web Flow as follows:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
...
</webflow:flow-registry>
<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.MvcViewFactoryCreator">
<property name="viewResolvers" ref="customViewResolver"/>
</bean>
]]></programlisting>
</sect2>
<bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.view.MvcViewFactoryCreator">
<property name="viewResolvers" ref="myExistingViewResolverToUseForFlows"/>
</bean>]]>
</programlisting>
</sect1>
</chapter>
</chapter>

View File

@@ -4,23 +4,23 @@
<sect1 id="upgrade-guide-introduction">
<title>Introduction</title>
<para>
This chapter shows you how to upgrade existing Web Flow 1.0 application to Web Flow 2.0.
This chapter shows you how to upgrade existing Web Flow 1 application to Web Flow 2.
</para>
</sect1>
<sect1 id="upgrade-guide-definition-language">
<title>Flow Definition Language</title>
<para>
The core concepts behind the flow definition language have not changed between Web Flow 1.0 and 2.0.
However, many of the element and attribute names have changed.
The core concepts behind the flow definition language have not changed between Web Flow 1 and 2.
However, some of the element and attribute names have changed.
These changes allow for the language to be both more concise and expressive.
A <link linkend="field-mappings">complete mapping of changes</link> is available as an appendix.
A complete list of <link linkend="field-mappings">mapping changes</link> is available as an appendix.
</para>
<sect2 id="upgrade-guide-definition-language-tool">
<title>Flow Definition Updater Tool</title>
<para>
An automated tool is available to aid in the conversion of existing 1.0 flows to the new 2.0 style.
An automated tool is available to aid in the conversion of existing 1.x flows to the new 2.x style.
The tool will convert all the old tag names to their new equivalents, if needed.
While the tool will make a best effort attempt at conversion, there is not a one-to-one mapping for all 1.0 concepts.
While the tool will make a best effort attempt at conversion, there is not a one-to-one mapping for all version 1 concepts.
If the tool was unable to convert a portion of the flow, it will be marked with a <code>WARNING</code> comment in the resulting flow.
</para>
<para>
@@ -34,7 +34,7 @@
The resulting converted flow will be sent to standard output.
</para>
<programlisting language="shell">
java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowToUpgrade.xml
java org.springframework.webflow.upgrade.WebFlowUpgrader flow-to-upgrade.xml
</programlisting>
<sect3 id="upgrade-guide-definition-language-tool-warnings">
<title>Flow Definition Updater Tool Warnings</title>
@@ -92,14 +92,14 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect1 id="upgrade-guide-webflow-config">
<title>Web Flow Configuration</title>
<para>
In Web Flow 1.0 there were two options available for configuring Web Flow, with standard spring bean XML or with the <code>webflow-config</code> schema.
The schema configuration option simplifies the configuration process keeping long internal class name hidden and provides contextual auto-complete.
The schema configuration option is the standard way to configure Web Flow 2.0.
In Web Flow 1 there were two options available for configuring Web Flow, one using standard spring bean XML and the other using the <code>webflow-config-1.0</code> schema.
The schema configuration option simplifies the configuration process by keeping long internal class names hidden and enabling contextual auto-complete.
The schema configuration option is the only way to configure Web Flow 2.
</para>
<sect2 id="upgrade-guide-webflow-config-beans">
<title>Web Flow Bean Configuration</title>
<para>
The bean configuration method used in Web Flow 1.0 is no longer supported.
The <code>FactoryBean</code> bean XML configuration method used in Web Flow 1 is no longer supported.
The schema configuration method should be used instead.
In particular beans defining <code>FlowExecutorFactoryBean</code> and <code>XmlFlowRegistryFactoryBean</code> should be updated.
Continue reading Web Flow Schema Configuration for details.
@@ -108,9 +108,9 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect2 id="upgrade-guide-webflow-config-schema">
<title>Web Flow Schema Configuration</title>
<para>
The configuration schema has change slightly in 2.0.
The <code>webflow-config</code> configuration schema has also changed slightly from version 1 to 2.
The simplest way to update your application is modify the version of the schema to 2.0 then fix any errors in a schema aware XML editor.
The most common change is add 'flow-' to the beginning of elements defined by the schema.
The most common change is add 'flow-' to the beginning of the elements defined by the schema.
</para>
<programlisting language="xml"><![CDATA[
<beans xmlns="http://www.springframework.org/schema/beans"
@@ -125,8 +125,8 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect3 id="upgrade-guide-webflow-config-schema-executor">
<title>flow-executor</title>
<para>
The flow executor is the core of Web Flow.
This element replaces previous bean definitions for <code>FlowExecutorFactoryBean</code>.
The flow executor is the core Web Flow configuration element.
This element replaces previous <code>FlowExecutorFactoryBean</code> bean definitions.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"/>
@@ -154,7 +154,7 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<para>
The <code>flow-registry</code> contains a set of <code>flow-location</code>s.
Every flow definition used by Web Flow must be added to the registry.
This element replaces previous bean definitions for <code>XmlFlowRegistryFactoryBean</code>.
This element replaces previous <code>XmlFlowRegistryFactoryBean</code> bean definitions.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry">
@@ -170,21 +170,12 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
The portlet flow controller <code>org.springframework.webflow.executor.mvc.PortletFlowController</code> has been replaced by a flow handler adapter available at <code>org.springframework.webflow.mvc.portlet.FlowHandlerAdapter</code>.
They will need to be updated in the bean definitions.
</para>
<para>
The flowExecutor can no longer be set via a mutator.
It must be set as a constructor argument.
</para>
<programlisting language="xml"><![CDATA[
<bean name="/pos.htm" class="org.springframework.webflow.mvc.servlet.FlowController">
<constructor-arg ref="flowExecutor"/>
</bean>
]]></programlisting>
</sect2>
<sect2 id="upgrade-guide-java-url-handler">
<title>Flow Request URL Handler</title>
<para>
The default URL handler has changed in Web Flow 2.0.
The flow identifier is now inferred from the URL rather then passed explicitly.
The default URL handler has changed in Web Flow 2.
The flow identifier is now derived from the URL rather then passed explicitly.
In order to maintain comparability with existing views and URL structures a <code>WebFlow1FlowUrlHandler</code> is available.
</para>
<programlisting language="xml"><![CDATA[
@@ -199,11 +190,11 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect2 id="upgrade-guide-webflow-config-view-resolver">
<title>View Resolution</title>
<para>
Web Flow 2.0 by default will both select and render views.
View were previously selected by Web Flow 1.0 and then rendered by an external view resolver.
Web Flow 2 by default will both select and render views.
View were previously selected by Web Flow 1 and then rendered by an external view resolver.
</para>
<para>
In order for 1.0 based flows to work in Web Flow 2.0 the default view resolver must be overridden.
In order for version 1 flows to work in Web Flow 2 the default view resolver must be overridden.
A common use case is to use <ulink url="http://tiles.apache.org/">Apache Tiles</ulink> for view resolution.
The following configuration will replace the default view resolver with a Tiles view resolver.
The <code>tilesViewResolver</code> in this example can be replaced with any other view resolver.
@@ -236,16 +227,17 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect2 id="upgrade-guide-webflow-concepts-binding">
<title>Automatic Model Binding</title>
<para>
Web Flow 1.0 required Spring MVC based flows to manually call <code>FormAction</code> methods, mainly: <code>setupForm</code>, <code>bind</code> and <code>bindAndValidate</code>.
Web Flow 2.0 now supports automatic setup, binding and validation via the <code>model</code> attribute for <code>view-state</code>s.
Web Flow 1 required Spring MVC based flows to manually call <code>FormAction</code> methods, notably:
<code>setupForm</code>, <code>bindAndValidate</code> to process form views.
Web Flow 2 now provides automatic model setup and binding using the <code>model</code> attribute for <code>view-state</code>s.
Please see the <link linkend="view-model">Binding to a Model</link> section for details.
</para>
</sect2>
<sect2 id="upgrade-guide-webflow-concepts-el-v-ognl">
<title>OGNL vs EL</title>
<para>
Web Flow 1.0 used OGNL exclusively for expressions within the flow definitions.
Web Flow 2.0 adds support for Unified EL.
Web Flow 1 used OGNL exclusively for expressions within the flow definitions.
Web Flow 2 adds support for Unified EL.
United EL is used when it is available, OGNL will continue to be used when a Unified EL implementation is not available.
Please see the <link linkend="el">Expression Language</link> chapter for details.
</para>
@@ -253,23 +245,24 @@ java org.springframework.webflow.engine.model.builder.xml.WebFlowUpgrader flowTo
<sect2 id="upgrade-guide-webflow-concepts-flash-scope">
<title>Flash Scope</title>
<para>
Flash scope in Web Flow 1.0 persisted across the current request and into the next request.
In Web Flow 2.0 flash scope is cleared after every view render.
This allows objects to persist across the POST-REDIRECT-GET pattern, while being independent of the next request.
Flash scope in Web Flow 1 lived across the current request and into the next request.
This was conceptually similar to Web Flow 2's view scope concept, but the semantics were not as well defined.
In Web Flow 2, flash scope is cleared after every view render.
This makes flashScope semantics in Web Flow consistent with other web frameworks.
</para>
</sect2>
<sect2 id="upgrade-guide-webflow-concepts-jsf">
<title>Spring Faces</title>
<para>
Web Flow 2.0 provides significant support for JavaServer Faces.
Web Flow 2 offers significantly improved integration with JavaServerFaces.
Please see the <link linkend="spring-faces">JSF Integration</link> chapter for details.
</para>
</sect2>
<sect2 id="upgrade-guide-webflow-concepts-redirects">
<title>External Redirects</title>
<para>
External redirects in Web Flow 1.0 were always considered context relative.
In Web Flow 2.0, if the redirect URL begins with a slash, it is considered absolute to the server root instead of the application context.
External redirects in Web Flow 1 were always considered context relative.
In Web Flow 2, if the redirect URL begins with a slash, it is considered servlet-relative instead of context-relative.
URLs without a leading slash are still context relative.
</para>
</sect2>