portlet and spring mvc docs

This commit is contained in:
Scott Andrews
2008-04-10 22:32:44 +00:00
parent 722a832958
commit 15e3dd5cf8
4 changed files with 328 additions and 4 deletions

View File

@@ -612,7 +612,7 @@
name or value
</entry>
<entry colname="comments">
name when in flow element, value when in subflow-state element
value when in flow element, name when in subflow-state element
</entry>
</row>
<row>

View File

@@ -5,6 +5,228 @@
<title>Introduction</title>
<para>
This chapter shows you how to use Web Flow in a Portlet environment.
Web Flow has full support for JSR-168 portlets.
The <code>booking-portlet-mvc</code> sample application is a good reference for using Web Flow within a portlet.
This application is a simplified travel site that allows users to search for and book hotel rooms.
</para>
</sect1>
</chapter>
<sect1 id="portlet-config-core">
<title>Configuring web.xml &amp; portlet.xml</title>
<para>
The configuration for a portlet depends on the portlet container used.
The <code>booking-portlet-mvc</code> and <code>booking-portlet-faces</code> sample application are both configured to use <ulink url="http://portals.apache.org/pluto/">Apache Pluto</ulink>, the JSR-168 reference implementation.
</para>
<para>
In general the configuration requires adding a servlet mapping in the <code>web.xml</code> file to dispatch request to the portlet container.
</para>
<programlisting language="xml"><![CDATA[
<servlet>
<servlet-name>swf-booking-mvc</servlet-name>
<servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-name</param-name>
<param-value>swf-booking-mvc</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>swf-booking-mvc</servlet-name>
<url-pattern>/PlutoInvoker/swf-booking-mvc</url-pattern>
</servlet-mapping>
]]></programlisting>
<para>
The <code>portlet.xml</code> configuration is a standard portlet configuration.
The <code>portlet-class</code> needs to be set along with a pair of <code>init-param</code>s.
Setting the <code>expiration-cache</code> to <code>0</code> is recommended to force Web Flow to always render a fresh view.
</para>
<programlisting language="xml"><![CDATA[
<portlet>
...
<portlet-class>
org.springframework.web.portlet.DispatcherPortlet
</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>
/WEB-INF/web-application-config.xml
</value>
</init-param>
<init-param>
<name>viewRendererUrl</name>
<value>/WEB-INF/servlet/view</value>
</init-param>
<expiration-cache>0</expiration-cache>
...
</portlet>
]]></programlisting>
</sect1>
<sect1 id="portlet-config-spring">
<title>Configuring Spring</title>
<sect2 id="portlet-config-spring-handler">
<title>Flow Handlers</title>
<para>
The only supported mechanism for bridging a portlet request to Web Flow is via a <code>FlowHandler</code>.
The <code>PortletFlowController</code> used in Web Flow 1.0 is no longer supported.
</para>
<para>
The flow handler, similar to the servlet flow handler, provides hooks that can:
<itemizedlist>
<listitem>
<para>select the flow to execute</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 any exceptions</para>
</listitem>
</itemizedlist>
The <code>AbstractFlowHandler</code> class is an implementation of <code>FlowHandler</code> that provides default implementations for these hooks.
</para>
<para>
In a portlet environment the targeted flow id can not be inferred from the URL and must be defined explicitly in the handler.
</para>
<programlisting language="java"><![CDATA[
public class ViewFlowHandler extends AbstractFlowHandler {
public String getFlowId() {
return "view";
}
}
]]></programlisting>
</sect2>
<sect2 id="portlet-config-spring-mappings">
<title>Adapter Mappings</title>
<para>
Spring Portlet MVC provides a rich set of methods to map portlet requests.
Complete documentation of the available methods is available in the <ulink url="http://static.springframework.org/spring/docs/2.5.x/reference/portlet.html#portlet-handlermapping">Spring Reference Documentation</ulink>.
</para>
<para>
The <code>booking-portlet-mvc</code> sample application uses a <code>PortletModeHandlerMapping</code> to map portlet requests.
The sample application only supports <code>view</code> mode, but support for other portlet modes is available.
Other modes can be added and point to the same flow as <code>view</code> mode, or any other flow.
</para>
<programlisting language="xml"><![CDATA[
<bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<bean class="org.springframework.webflow.samples.booking.ViewFlowHandler" />
</entry>
</map>
</property>
</bean>
]]></programlisting>
</sect2>
<sect2 id="portlet-config-spring-handler-adapter">
<title>Flow Handler Adapter</title>
<para>
A <code>FlowHandlerAdapter</code> converts the handler mappings to the flow handlers.
The flow executor is required as a constructor argument.
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowHandlerAdapter" class="org.springframework.webflow.mvc.portlet.FlowHandlerAdapter">
<constructor-arg ref="flowExecutor" />
</bean>
]]></programlisting>
</sect2>
<sect2 id="portlet-config-spring-redirectonpause">
<title>Redirect on Pause</title>
<para>
In a portlet environemnt, <code>alwaysRedirectOnPause</code> must be set to <code>false</code>.
If not turned off, the initial view will fail to render.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<webflow:flow-execution-attributes>
<webflow:alwaysRedirectOnPause value="false"/>
</webflow:flow-execution-attributes>
</webflow:flow-executor>
]]></programlisting>
</sect2>
</sect1>
<sect1 id="portlet-views">
<title>Portlet Views</title>
<para>
In order to facilitate view rendering, a <code>ViewRendererServlet</code> must be added to the <code>web.xml</code> file.
This servlet is not invoked directly, but it used by Web Flow to render views in a portlet environment.
</para>
<programlisting language="xml"><![CDATA[
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
]]></programlisting>
</sect1>
<sect1 id="portlet-modes">
<title>Portlet Modes and Window States</title>
<sect2 id="portlet-modes-state">
<title>Window State</title>
<para>
The Portlet API defined three window states: normal, minimized and maximized.
The portlet implementation must decide what to render for each of these window states.
Web Flow exposes the string value of the window state under <code>portletWindowState</code> via the request map on the external context.
</para>
<programlisting language="java"><![CDATA[
ExternalContextHolder.getExternalContext().getRequestMap().get("portletWindowState");
]]></programlisting>
<programlisting language="el"><![CDATA[
${externalContext.requestMap.portletWindowState}
]]></programlisting>
</sect2>
<sect2 id="portlet-modes-mode">
<title>Portlet Mode</title>
<para>
The Portlet API defined three portlet modes: view, edit and help.
The portlet implementation must decide what to render for each of these modes.
Web Flow exposes the string value of the portlet mode under <code>portletMode</code> via the request map on the external context.
</para>
<programlisting language="java"><![CDATA[
ExternalContextHolder.getExternalContext().getRequestMap().get("portletMode");
]]></programlisting>
<programlisting language="el"><![CDATA[
${externalContext.requestMap.portletMode}
]]></programlisting>
</sect2>
</sect1>
<sect1 id="portlet-issues">
<title>Issues in a Portlet Environment</title>
<sect2 id="portlet-issues-redirects">
<title>Redirects</title>
<para>
The Portlet API only allows redirects to be requested from an action request.
Because views are rendered on the render request, views and <code>view-state</code>s cannot trigger a redirect.
</para>
</sect2>
<sect2 id="portlet-issues-modes">
<title>Switching Portlet Modes</title>
<para>
The portlet container passes the execution key from the previous flow when switching to a new mode.
Even if the mode is mapped to a different <code>FlowHandler</code> the flow execution will resume the previous execution.
</para>
<para>
One way to start the new flow is to create a URL targeting the mode without the execution key.
</para>
</sect2>
<sect2 id="portlet-issues-jsf">
<title>Portlets and JSF</title>
<para>
Web Flow supports JSF as the view technology for a portlet.
However, a jsf-portlet bridge (JSR-301) must be provided.
At the time of this writing, no feature complete jsf-portlet bridge exists.
Some of the existing bridge implementations may appear to work, however, strange side effect may occur.
</para>
<para>
JSF portlets are considered experimental at this time.
</para>
</sect2>
</sect1>
</chapter>

View File

@@ -5,6 +5,108 @@
<title>Introduction</title>
<para>
This chapter shows you how to integrate Web Flow into a Spring MVC web application.
The <code>booking-mvc</code> sample application is a good reference for Spring MVC with Web Flow.
This application is a simplified travel site that allows users to search for and book hotel rooms.
</para>
</sect1>
</chapter>
<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.
The servlet needs to be configured.
An <code>init-param</code> is used in the servlet to pass the <code>contextConfigLocation</code>.
This is the location of the Spring configuration for your application.
</para>
<programlisting language="xml"><![CDATA[
<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/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>
</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">
<property name="mappings">
<value>
/hotels/booking=bookingFlowHandler
/hotels/*=hotelsController
</value>
</property>
</bean>
]]></programlisting>
<para>
For this example both a standard MVC controller and a Web Flow handler are configured.
The controller supports the free navigation aspects of searching and viewing hotels.
The flow handler supports the controlled navigation aspect of booking a hotel room.
</para>
</sect2>
<sect2 id="spring-mvc-config-spring-flow-adapters">
<title>Flow Adapters</title>
<para>
The recommended way to bridge Spring MVC requests to Web Flow is via a flow adapter.
</para>
<programlisting language="xml"><![CDATA[
<bean id="bookingFlowHandler" class="org.springframework.webflow.samples.booking.BookingFlowHandler" />
]]></programlisting>
<para>
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 any exceptions</para>
</listitem>
</itemizedlist>
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="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));
}
}
]]></programlisting>
</sect2>
<sect2 id="spring-mvc-config-spring-flow-controllers">
<title>Flow Controllers</title>
<para>
Flow controllers provide a direct hook from Spring MVC into Web Flow.
The <code>FlowController</code> class is an implementation of an MVC Controller.
</para>
<para>
Web Flow 1.0 used controllers as the only way to hook Web Flow into Spring MVC.
In Web Flow 2.0 flow handler adapters are recommended instead of controllers as they provide much richer hooks into the web flow engine.
</para>
</sect2>
</sect1>
</chapter>

View File

@@ -292,7 +292,7 @@ context.addMessage(builder.warn().source("smoking").defaultText("Smoking is bad
context.addMessage(builder.info().defaultText("We have processed your reservation - thank you and enjoy your stay").build());
</programlisting>
</sect2>
<sect2 id="plain-text-message">
<sect2 id="plain-text-message-intl">
<title>Adding internationalized messages</title>
<programlisting type="java">
MessageContext context = ...