Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: Using Session Model Attributes With Multiple Browser Tabs Patch

  1. #1
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default Using Session Model Attributes With Multiple Browser Tabs Patch

    I wanted to share a solution that I came up with using Spring 3 with session level Model Attributes and multiple tabs within the same session.

    First here is a brief description of the problem: Basically the issue is that if you open the first tab and do a get to load the command object into the session and then open a second tab and do a get on the same controller with a different command object then the first tab's command object has been replaced by the second tab's command object and if you submit the form on the first tab then it will update the second tab's command object with the data from the first command object!

    Spring by default uses the class DefaultSessionAttributeStore to store and retrieve the session level command objects based upon the session attribute name only. This is what causes the command objects to be stomped on by multiple requests within the same session with the same attribute name.

    This is a known issue and a JIRA (SPR-4160) ticket has been created that will address this in version 3.1M1.

    To address this issue until the fix is incorporated into Spring, I created the following solution:

    I created the a class that implements the SessionAttributeStore interface. This class stores and retrieves the session level command objects based upon a unique (conversation id) that is automatically generated when the command object is stored on the session. So when you do a get request with a controller that has session attributes and you assign your command object to the model map, the storeAttribute method will be invoked and it will generate a unique conversation id (System.currTimeInMillis()) and append this to the attribute name (your command object name) and store it on the session as well as set the conversation id as a request attribute so that the view that is displayed can post back the conversation that it will be involved in.

    The only other thing that needs to be done is add a hidden input field in your form that will post back the conversation id. The controller will invoke the retrieveAttribute method and based upon the incoming conversation id will retrieve the correct command object from the session. I created a simple tag library that will create a hidden input field for you.

    It is pretty simple to setup, basically you do the following:

    In your dispatcher-servlet.xml file you define the class that you want to do the storing and retrieving of command objects from the session:
    Code:
    <bean id="sessionConversationAttributeStore" class="com.marty.support.SessionConversationAttributeStore">
        <property name="numConversationsToKeep" value="10"/>
    </bean>
    Then you tell the AnnotationMethodHandlerAdapter class that you want to use a custom sessionAttributeStore:
    Code:
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="webBindingInitializer">
            <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
                <property name="conversionService" ref="conversionService" />
            </bean>
        </property>
        <property name="sessionAttributeStore">
            <ref bean="sessionConversationAttributeStore"/>
        </property>     
    </bean>
    Finally you add the following tag library call inside your forms that use session model attributes:
    Code:
    <sessionConversation:insertSessionConversationId attributeName="<your command name here>"/>
    Here is a link to a sample application that shows how the custom SessionAttributeStore works along with the source code for the SessionConversationAttributeStore class and the SessionConversationIdTag tag library.

    Hopefully this will help someone else with the issues of using session level model attributes like it has for me.

    Marty Jones
    Last edited by MartyJones; Sep 13th, 2010 at 11:52 AM.

  2. #2
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    FYI,

    I made a small change to the ConversationExample.zip file that I initially uploaded.

  3. #3
    Join Date
    Sep 2010
    Posts
    2

    Smile very good

    i have read this ,it is very good.

  4. #4
    Join Date
    Oct 2010
    Posts
    10

    Default Does it override the SessionAttributeStore for all Controllers ?

    hello Marty,

    When we tell the AnnotationMethodHandlerAdapter class that you want to use a custom sessionAttributeStore,
    does it use this custom sessionAttributeStore for all controller ?
    is there a way to esecute this custom sessionAttributeStore only for one particular controller ? Would you know?
    Thanks ,
    sdt_dev

  5. #5
    Join Date
    Oct 2005
    Location
    Mobile, AL
    Posts
    345

    Default

    sdt_dev,

    The adaptor is used for all controllers that use the @SessionAttributes attribute to mark command objects as "session" scoped. Controllers that use "request" scoped command objects will not use the adaptor.

    Marty

  6. #6
    Join Date
    Oct 2010
    Posts
    10

    Default

    Thanks Marty!

  7. #7
    Join Date
    Jul 2011
    Posts
    5

    Default Thanks Marty....

    Thanks....

  8. #8
    Join Date
    Apr 2011
    Posts
    2

    Default Changes in Spring 3.1

    Thanks, Marty.

    This worked great until I upgraded to Spring 3.1. It appears you have to instantiate RequestMappingHandlerAdapter instead of AnnotationMethodHandlerAdapter, i.e.:
    Code:
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
            <property name="sessionAttributeStore">
                <ref bean="conversationSessionAttributeStore"/>
            </property>   
        </bean>
    In the documentation:
    http://static.springsource.org/sprin...ew-in-3.1.html
    http://static.springsource.org/sprin...pping-31-vs-30

    Conversation support won't happen until 3.2 per this blog post discussing 3.1 RC1:
    http://blog.springsource.org/2011/10...-rc1-released/

  9. #9

    Default

    I changed this for Spring 3.1, because if you are using <mvc:annotation-driven /> then the bean declaration for RequestMappingHandlerAdapter is ignored

    Code:
    public class SessionConversationAttributeStore implements SessionAttributeStore, InitializingBean {
    	
    	@Autowired 
    	private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    
            //snipped...
    
            @Override
    	public void afterPropertiesSet() throws Exception {
    		requestMappingHandlerAdapter.setSessionAttributeStore(this);
    	}
    }

  10. #10
    Join Date
    Oct 2012
    Location
    Wellington, NZ
    Posts
    2

    Default

    Also - removed the need for the tag - http://duckranger.com/2012/11/add-co...to-spring-mvc/

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •