Add option to save Web Flow output to MVC flash scope
Output from a flow can now be saved to the flash scope of Spring MVC when the 'saveOutputToFlashScopeOnRedirect' property of the FlowHandlerAdapter is 'true'. For backwards compatibility this is an opt-in feature that must be configured by the user. Issues: SWF-1561
This commit is contained in:
committed by
Rossen Stoyanchev
parent
d066f1f8ad
commit
91e8a96c11
@@ -27,9 +27,14 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.js.ajax.AjaxHandler;
|
||||
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.HandlerAdapter;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
import org.springframework.web.servlet.support.WebContentGenerator;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import org.springframework.webflow.context.servlet.DefaultFlowUrlHandler;
|
||||
import org.springframework.webflow.context.servlet.FlowUrlHandler;
|
||||
import org.springframework.webflow.context.servlet.ServletExternalContext;
|
||||
@@ -45,8 +50,9 @@ import org.springframework.webflow.executor.FlowExecutor;
|
||||
* A custom MVC HandlerAdapter that encapsulates the generic workflow associated with executing flows in a Servlet
|
||||
* environment. Delegates to mapped {@link FlowHandler flow handlers} to manage the interaction with executions of
|
||||
* specific flow definitions.
|
||||
*
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAdapter, InitializingBean {
|
||||
|
||||
@@ -77,6 +83,8 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
|
||||
private boolean redirectHttp10Compatible = true;
|
||||
|
||||
private boolean saveOutputToFlashScopeOnRedirect;
|
||||
|
||||
/**
|
||||
* Creates a new flow handler adapter.
|
||||
* @see #setFlowExecutor(FlowExecutor)
|
||||
@@ -157,6 +165,32 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
this.redirectHttp10Compatible = redirectHttp10Compatible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether servlet relative redirects sent by this handler adapter
|
||||
* should pass {@link FlowExecutionOutcome#getOutput() flow output} to the
|
||||
* Spring MVC {@link FlashMap flash scope}.
|
||||
*
|
||||
* <p>By default, to remain compatible with previous releases, flow output is
|
||||
* not mapped to flash scope.
|
||||
*
|
||||
* @param saveOutputToFlashScopeOnRedirect
|
||||
* @see #getFlashOutput(HttpServletRequest, HttpServletResponse, FlowExecutionResult)
|
||||
*/
|
||||
public void setSaveOutputToFlashScopeOnRedirect(boolean saveOutputToFlashScopeOnRedirect) {
|
||||
this.saveOutputToFlashScopeOnRedirect = saveOutputToFlashScopeOnRedirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether servlet relative redirects should pass
|
||||
* {@link FlowExecutionOutcome#getOutput() flow output} to the Spring MVC
|
||||
* {@link FlashMap flash scope}.
|
||||
*
|
||||
* @return {@code true} if so, {@code false} otherwise
|
||||
*/
|
||||
public boolean getSaveOutputToFlashScopeOnRedirect() {
|
||||
return this.saveOutputToFlashScopeOnRedirect;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(flowExecutor, "The FlowExecutor to execute flows is required");
|
||||
if (flowUrlHandler == null) {
|
||||
@@ -339,11 +373,11 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
if (context.getFlowDefinitionRedirectRequested()) {
|
||||
sendFlowDefinitionRedirect(result, context, request, response);
|
||||
} else if (context.getExternalRedirectRequested()) {
|
||||
sendExternalRedirect(context.getExternalRedirectUrl(), request, response);
|
||||
sendExternalRedirect(context.getExternalRedirectUrl(), request, response, result);
|
||||
} else {
|
||||
String location = handler.handleExecutionOutcome(result.getOutcome(), request, response);
|
||||
if (location != null) {
|
||||
sendExternalRedirect(location, request, response);
|
||||
sendExternalRedirect(location, request, response, result);
|
||||
} else {
|
||||
defaultHandleExecutionOutcome(result.getFlowId(), result.getOutcome(), context, request, response);
|
||||
}
|
||||
@@ -382,15 +416,20 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
|
||||
private void sendExternalRedirect(String location, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
sendExternalRedirect(location, request, response, null);
|
||||
}
|
||||
|
||||
private void sendExternalRedirect(String location, HttpServletRequest request, HttpServletResponse response,
|
||||
FlowExecutionResult result) throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Sending external redirect to '" + location + "'");
|
||||
}
|
||||
if (location.startsWith(SERVLET_RELATIVE_LOCATION_PREFIX)) {
|
||||
sendServletRelativeRedirect(location.substring(SERVLET_RELATIVE_LOCATION_PREFIX.length()), request,
|
||||
response);
|
||||
response, result);
|
||||
} else if (location.startsWith(CONTEXT_RELATIVE_LOCATION_PREFIX)) {
|
||||
sendContextRelativeRedirect(location.substring(CONTEXT_RELATIVE_LOCATION_PREFIX.length()), request,
|
||||
response);
|
||||
response, result);
|
||||
} else if (location.startsWith(SERVER_RELATIVE_LOCATION_PREFIX)) {
|
||||
String url = location.substring(SERVER_RELATIVE_LOCATION_PREFIX.length());
|
||||
if (!url.startsWith("/")) {
|
||||
@@ -401,9 +440,9 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
sendRedirect(location, request, response);
|
||||
} else {
|
||||
if (isRedirectServletRelative(request)) {
|
||||
sendServletRelativeRedirect(location, request, response);
|
||||
sendServletRelativeRedirect(location, request, response, result);
|
||||
} else {
|
||||
sendContextRelativeRedirect(location, request, response);
|
||||
sendContextRelativeRedirect(location, request, response, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,7 +452,7 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
* such as "contextRelative: was not specified. This answer depends on how the MVC Dispatcher Servlet is mapped: (1)
|
||||
* default servlet, (2) prefix, (3) extension, (4) exact match. In (1), (3), and (4) it doesn't make sense to
|
||||
* prepend the servlet path, which contains the entire URL after the context path.
|
||||
*
|
||||
*
|
||||
* Because there is no simple way to get the servlet mapping, this method is implemented to return True if path info
|
||||
* is not null. Also see SWF-1385.
|
||||
*/
|
||||
@@ -421,25 +460,48 @@ public class FlowHandlerAdapter extends WebContentGenerator implements HandlerAd
|
||||
return (request.getPathInfo() != null);
|
||||
}
|
||||
|
||||
private void sendContextRelativeRedirect(String location, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
private void sendContextRelativeRedirect(String location, HttpServletRequest request, HttpServletResponse response,
|
||||
FlowExecutionResult result) throws IOException {
|
||||
StringBuilder url = new StringBuilder(request.getContextPath());
|
||||
if (!location.startsWith("/")) {
|
||||
url.append('/');
|
||||
}
|
||||
url.append(location);
|
||||
sendRedirect(url.toString(), request, response);
|
||||
sendRedirect(url.toString(), request, response, result);
|
||||
}
|
||||
|
||||
private void sendServletRelativeRedirect(String location, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
private void sendServletRelativeRedirect(String location, HttpServletRequest request, HttpServletResponse response,
|
||||
FlowExecutionResult result) throws IOException {
|
||||
StringBuilder url = new StringBuilder(request.getContextPath());
|
||||
url.append(request.getServletPath());
|
||||
if (!location.startsWith("/")) {
|
||||
url.append('/');
|
||||
}
|
||||
url.append(location);
|
||||
sendRedirect(url.toString(), request, response);
|
||||
sendRedirect(url.toString(), request, response, result);
|
||||
}
|
||||
|
||||
private void sendRedirect(String url, HttpServletRequest request, HttpServletResponse response,
|
||||
FlowExecutionResult result) throws IOException {
|
||||
|
||||
if (this.saveOutputToFlashScopeOnRedirect) {
|
||||
saveFlashOutput(url.toString(), request, response, result);
|
||||
}
|
||||
sendRedirect(url, request, response);
|
||||
}
|
||||
|
||||
private void saveFlashOutput(String location, HttpServletRequest request, HttpServletResponse response,
|
||||
FlowExecutionResult result) {
|
||||
Map<String, Object> output = result.getOutcome().getOutput().asMap();
|
||||
FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
|
||||
if (flashMapManager != null && output != null && !output.isEmpty()) {
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(location).build();
|
||||
FlashMap flashMap = new FlashMap();
|
||||
flashMap.setTargetRequestPath(uriComponents.getPath());
|
||||
flashMap.addTargetRequestParams(uriComponents.getQueryParams());
|
||||
flashMap.putAll(output);
|
||||
flashMapManager.saveOutputFlashMap(flashMap, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFlowException(FlowException e, HttpServletRequest request, HttpServletResponse response,
|
||||
|
||||
@@ -13,6 +13,9 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.FlashMapManager;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.webflow.context.servlet.ServletExternalContext;
|
||||
import org.springframework.webflow.core.FlowException;
|
||||
@@ -34,6 +37,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
private LocalAttributeMap<Object> flowInput = new LocalAttributeMap<Object>();
|
||||
private boolean handleException;
|
||||
private boolean handleExecutionOutcome;
|
||||
private MockFlashMapManager flashMapManager = new MockFlashMapManager();
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
flowExecutor = EasyMock.createMock(FlowExecutor.class);
|
||||
@@ -80,14 +84,11 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
context = new ServletExternalContext(servletContext, request, response, flowHandlerAdapter.getFlowUrlHandler());
|
||||
request.setAttribute(DispatcherServlet.FLASH_MAP_MANAGER_ATTRIBUTE, flashMapManager);
|
||||
}
|
||||
|
||||
public void testLaunchFlowRequest() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/whatever");
|
||||
request.setRequestURI("/springtravel/app/whatever");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/whatever", "GET");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
EasyMock.expectLastCall().andReturn(result);
|
||||
@@ -97,11 +98,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowRequestEndsAfterProcessing() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/whatever");
|
||||
request.setRequestURI("/springtravel/app/whatever");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/whatever", "GET");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
@@ -117,11 +114,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowRequestEndsAfterProcessingAjaxRequest() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/whatever");
|
||||
request.setRequestURI("/springtravel/app/whatever");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/whatever", "GET");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
context.setAjaxRequest(true);
|
||||
@@ -139,11 +132,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testResumeFlowRequest() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("POST");
|
||||
setupRequest("/springtravel", "/app", "/foo", "POST");
|
||||
request.addParameter("execution", "12345");
|
||||
flowExecutor.resumeExecution("12345", context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "123456");
|
||||
@@ -154,11 +143,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testResumeFlowRequestEndsAfterProcessing() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("POST");
|
||||
setupRequest("/springtravel", "/app", "/foo", "POST");
|
||||
request.addParameter("execution", "12345");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
@@ -176,11 +161,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testResumeFlowRequestEndsAfterProcessingFlowCommittedResponse() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("POST");
|
||||
setupRequest("/springtravel", "/app", "/foo", "POST");
|
||||
request.addParameter("execution", "12345");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
@@ -199,11 +180,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExecutionRedirect() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestFlowExecutionRedirect();
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -216,11 +193,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithDefinitionRedirect() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
LocalAttributeMap<Object> input = new LocalAttributeMap<Object>();
|
||||
@@ -241,11 +214,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalHttpRedirect() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("http://www.paypal.com");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -258,11 +227,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalHttpsRedirect() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("https://www.paypal.com");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -275,11 +240,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectServletRelative() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("servletRelative:bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -292,11 +253,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectServletRelativeWithSlash() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("servletRelative:/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -309,11 +266,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectContextRelative() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("contextRelative:bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -326,11 +279,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectContextRelativeWithSlash() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("contextRelative:/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -343,11 +292,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectServerRelative() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("serverRelative:bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -360,11 +305,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectServerRelativeWithSlash() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("serverRelative:/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -378,11 +319,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
|
||||
public void testLaunchFlowWithExternalRedirectNotHttp10Compatible() throws Exception {
|
||||
flowHandlerAdapter.setRedirectHttp10Compatible(false);
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
context.requestExternalRedirect("serverRelative:/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -396,14 +333,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testSwf1385DefaultServletExternalRedirect() throws Exception {
|
||||
// The default case in accordance with the servlet spec:
|
||||
// "A string containing only the ’/’ character indicates the "default" servlet of the application.
|
||||
// In this case the servlet path is the request URI minus the context path and the path info is null."
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/foo");
|
||||
request.setPathInfo(null);
|
||||
request.setRequestURI("/springtravel/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/foo", null, "GET");
|
||||
context.requestExternalRedirect("/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -419,11 +349,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
// Deviation from the default case:
|
||||
// In some containers the default behavior can be switched so that the contents of the URI after
|
||||
// the context path is in the path info while the servlet path is empty.
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "", "/foo", "GET");
|
||||
context.requestExternalRedirect("/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -436,10 +362,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testSwf1385DefaultServletExternalRedirectServletRelative() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/foo");
|
||||
request.setRequestURI("/springtravel/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/foo", null, "GET");
|
||||
context.requestExternalRedirect("/bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -452,10 +375,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testExternalRedirectServletRelativeWithDefaultServletMapping() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/foo");
|
||||
request.setRequestURI("/springtravel/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/foo", null, "GET");
|
||||
context.requestExternalRedirect("servletRelative:bar");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
FlowExecutionResult result = FlowExecutionResult.createPausedResult("foo", "12345");
|
||||
@@ -468,11 +388,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testDefaultHandleFlowException() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
request.setParameters(parameters);
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
@@ -490,11 +406,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testDefaultHandleNoSuchFlowExecutionException() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
request.addParameter("execution", "12345");
|
||||
flowExecutor.resumeExecution("12345", context);
|
||||
FlowException flowException = new NoSuchFlowExecutionException(new MockFlowExecutionKey("12345"), null);
|
||||
@@ -506,11 +418,7 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testDefaultHandleNoSuchFlowExecutionExceptionAjaxRequest() throws Exception {
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
request.addParameter("execution", "12345");
|
||||
flowExecutor.resumeExecution("12345", context);
|
||||
FlowException flowException = new NoSuchFlowExecutionException(new MockFlowExecutionKey("12345"), null);
|
||||
@@ -524,12 +432,37 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
}
|
||||
|
||||
public void testHandleFlowOutcomeCustomFlowHandler() throws Exception {
|
||||
doHandleFlowServletRedirectOutcome();
|
||||
EasyMock.verify(new Object[] { flowExecutor });
|
||||
}
|
||||
|
||||
public void testHandleFlowExceptionCustomFlowHandler() throws Exception {
|
||||
handleException = true;
|
||||
final FlowException flowException = new FlowException("Error") {
|
||||
};
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
EasyMock.expectLastCall().andThrow(flowException);
|
||||
EasyMock.replay(new Object[] { flowExecutor });
|
||||
flowHandlerAdapter.handle(request, response, flowHandler);
|
||||
EasyMock.verify(new Object[] { flowExecutor });
|
||||
}
|
||||
|
||||
public void testHandleFlowServletRedirectOutcomeWithoutFlash() throws Exception {
|
||||
doHandleFlowServletRedirectOutcome();
|
||||
assertNull(flashMapManager.getFlashMap());
|
||||
}
|
||||
|
||||
public void testHandleFlowServletRedirectOutcomeWithFlash() throws Exception {
|
||||
flowHandlerAdapter.setSaveOutputToFlashScopeOnRedirect(true);
|
||||
doHandleFlowServletRedirectOutcome();
|
||||
assertEquals("baz", flashMapManager.getFlashMap().get("bar"));
|
||||
assertEquals("/springtravel/app/home", flashMapManager.getFlashMap().getTargetRequestPath());
|
||||
}
|
||||
|
||||
private void doHandleFlowServletRedirectOutcome() throws Exception {
|
||||
handleExecutionOutcome = true;
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
setupRequest("/springtravel", "/app", "/foo", "GET");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
LocalAttributeMap<Object> output = new LocalAttributeMap<Object>();
|
||||
output.put("bar", "baz");
|
||||
@@ -541,19 +474,28 @@ public class FlowHandlerAdapterTests extends TestCase {
|
||||
EasyMock.verify(new Object[] { flowExecutor });
|
||||
}
|
||||
|
||||
public void testHandleFlowExceptionCustomFlowHandler() throws Exception {
|
||||
handleException = true;
|
||||
final FlowException flowException = new FlowException("Error") {
|
||||
};
|
||||
request.setContextPath("/springtravel");
|
||||
request.setServletPath("/app");
|
||||
request.setPathInfo("/foo");
|
||||
request.setRequestURI("/springtravel/app/foo");
|
||||
request.setMethod("GET");
|
||||
flowExecutor.launchExecution("foo", flowInput, context);
|
||||
EasyMock.expectLastCall().andThrow(flowException);
|
||||
EasyMock.replay(new Object[] { flowExecutor });
|
||||
flowHandlerAdapter.handle(request, response, flowHandler);
|
||||
EasyMock.verify(new Object[] { flowExecutor });
|
||||
private void setupRequest(String contextPath, String servletPath, String pathInfo, String method) {
|
||||
request.setContextPath(contextPath);
|
||||
request.setServletPath(servletPath);
|
||||
request.setPathInfo(pathInfo);
|
||||
request.setRequestURI(contextPath + servletPath + (pathInfo == null ? "" : pathInfo));
|
||||
request.setMethod(method);
|
||||
}
|
||||
|
||||
private static class MockFlashMapManager implements FlashMapManager {
|
||||
|
||||
private FlashMap flashMap;
|
||||
|
||||
public FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
|
||||
this.flashMap = flashMap;
|
||||
}
|
||||
|
||||
public FlashMap getFlashMap() {
|
||||
return flashMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,6 +469,31 @@ mvn package
|
||||
# import into Eclipse</programlisting>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="spring-mvc-flash-output">
|
||||
<title>Saving Flow Output to MVC Flash Scope</title>
|
||||
<para>Flow output can be automatically saved to MVC flash scope when an <code>end-state</code>
|
||||
performs an internal redirect. This is particularly useful when displaying a summary
|
||||
screen at the end of a flow. For backwards compatibility this feature is disabled by
|
||||
default, to enable set <code>saveOutputToFlashScopeOnRedirect</code> on your
|
||||
<code>FlowHandlerAdapter</code> to <code>true</code>.</para>
|
||||
|
||||
<programlisting language="xml">
|
||||
<!-- Enables FlowHandler URL mapping -->
|
||||
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
|
||||
<property name="flowExecutor" ref="flowExecutor" />
|
||||
<property name="saveOutputToFlashScopeOnRedirect" value="true" />
|
||||
</bean>
|
||||
</programlisting>
|
||||
|
||||
<para>The following example will add <code>confirmationNumber</code> to the MVC flash scope
|
||||
before redirecting to the <code>summary</code> screen.</para>
|
||||
|
||||
<programlisting language="xml">
|
||||
<end-state id="finish" view="externalRedirect:summary">
|
||||
<output name="confirmationNumber" value="booking.confirmationNumber" />
|
||||
</end-state>
|
||||
</programlisting>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
included as part of their Spring configuration. See <xref linkend="portlet-jsf"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="whatsnew-swf-mvcflash">
|
||||
<title>Saving Flow Output to Spring MVC Flash Scope</title>
|
||||
<para>
|
||||
Flow output can now be saved to Spring MVC Flash Scope for any <code>end-state</code> that issues an internal redirect. To enable this feature set <code>FlowHandlerAdapter.saveOutputToFlashScopeOnRedirect</code>. See <xref linkend="spring-mvc-flash-output"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1 id="whatsnew-swf-230">
|
||||
<title>Spring Web Flow 2.3</title>
|
||||
|
||||
Reference in New Issue
Block a user