I recently came across a problem in a Spring Webflow based application where I needed to have one page as a standard Spring MVC page. I needed to write a PDF file to the actual http response and I’m not allowed to do that in WebFlow. So I defined a standard Spring MVC Controller and URL Mapper to complement my existing Flow Controller:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/index.htm">/index.htm</prop>
<prop key="/pdf.htm">PDFPageController</prop>
</props>
</property>
</bean>
<bean id="PDFPageController" class="controller.mvc.PDFPageController" />
<bean name="/index.htm" class="org.springframework.webflow.executor.mvc.FlowController">
<property name="flowExecutor" ref="flowExecutor" />
<property name="defaultFlowId" value="main" />
</bean>
Then inside the MVC Controller (which extends AbstractController), define a method called accessFlowScope like below:
private void accessFlowScope(HttpServletRequest request, HttpServletResponse response) {
// Gain access to the Spring Web Flow context
FlowController controller = (FlowController)getApplicationContext().getBean("/pdf.htm");
FlowExecutionRepository repository = ((FlowExecutorImpl)controller.getFlowExecutor()).getExecutionRepository();
FlowExecutorArgumentHandler handler = controller.getArgumentHandler();
ExternalContext externalContext = new ServletExternalContext(getServletContext(), request, response);
// Make sure we have a flow execution key.
if (handler.isFlowExecutionKeyPresent(externalContext)) {
try {
// Get access to the variable stored in the context.
ExternalContextHolder.setExternalContext(externalContext);
FlowExecutionKey flowExecutionKey = repository.parseFlowExecutionKey(handler.extractFlowExecutionKey(externalContext));
FlowExecution flowExecution = repository.getFlowExecution(flowExecutionKey);
Object variableInFlowScopeObject = flowExecution.getActiveSession().getScope().get("variableInFlowScope");
}
catch(Exception ex) {
logger.error("Error when accessing flow scope from MVC", ex);
}
finally {
ExternalContextHolder.setExternalContext(null);
}
}
else {
logger.error("Handler did not have flow execution key present");
}
}
This can then be called from your handleRequestInternal method of the MVC controller:
public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
All that is required now is to call from the Webflow view jsp into the MVC controller. I had to do a horrible iframe like so:
<iframe id="pdf-view" src="pdf.htm?_flowExecutionKey=${flowExecutionKey}" height="100%" width="50%">
I'm sorry, iframes are not supported by your browser, upgrade to <a href="http://getfirefox.com">Firefox</a>
</iframe>
Now you can pull out whatever values you require from the many scopes (request, flash, flow, conversation) and use them in your MVC controller to do stuff. NB: All the code is used pretty much verbatim from http://www.ervacon.com/products/swf/tips/tip1.html, but it doesn’t say to add the flowExecutionKey onto the URL, which is the part I was missing and thiking that it wasn’t working correctly.