Search code examples
spring-mvcspring-webflow-2

Using a HandlerInterceptor to add model attributes with Spring Web Flow


I have a HandlerInterceptor to add some "global" model variables. It works.

Now, I try to reuse it in Spring Web Flow, for the same reason.

But HandlerInterceptors have the ModelAndView parameter set to NULL under Spring Web Flow (couldn't figure why, but it's a fact).

I have referenced my interceptor in the FlowHandlerMapping bean :

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> 
    <property name="order" value="0" /> 
    <property name="flowRegistry" ref="flowRegistry" />
    <property name="interceptors">
        <list>
            <ref bean="myInterceptor" />
        </list>
    </property>
</bean>

How can I add variables to the model ?

Is there a workaround, with the request parameter for example ?


Solution

  • Starting with Spring Webflow 2, the ModelAndView object is not generated anymore (see this post (and thread) at the SpringSource forum).


    The FlowHandlerAdapter handle() function does not generate a ModedAndView anymore (it just returns null) even if this function is :

    public ModelAndView handle(HttpServletRequest request, 
            HttpServletResponse response, Object handler)
    

    So overriding this function is pointless, but this function creates a ServletExternalContext object, which holds all the flow variable, by calling its method :

    protected ServletExternalContext createServletExternalContext(
        HttpServletRequest request, HttpServletResponse response)
    

    By overriding this function you can pretty much do what you want with this flow variables.


    To do this, just create a class that extends FlowHandlerAdapter, register it instead of FlowHandlerAdapter and override the createServletExternalContext function.

    Basically you use ServletExternalContext.getSessionMap() to access a SharedAttributeMap and register your properties.

    As you have access to the HttpServletRequest and HttpServletResponse objects, this method can act petty much like a HandlerInterceptorAdapter.postHandle function.

    See an example below.

    I left out how to use generic way to reuse the same code for a HandlerInterceptor for the MVC and this object but it's easy to code, by implementing HandlerInterceptor.


    MyFlowHandlerAdapter :

    package my.package;
    public class MyFlowHandlerAdapter extends FlowHandlerAdapter {
    
        @Override
        protected ServletExternalContext createServletExternalContext(
                HttpServletRequest request,
                HttpServletResponse response) {
    
            ServletExternalContext context = 
                super.createServletExternalContext(request,response);
    
            context.getSessionMap().put("myproperty", "myvalue");
    
            return context;
        }
    }
    

    You have the FlowHandlerAdapter object defined in you webflow-context.xml file like that :

    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>
    

    Just replace it with :

    <bean class="my.package.MyFlowHandlerAdapter">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>