Announcement Announcement Module
Collapse
No announcement yet.
Using Session Model Attributes With Multiple Browser Tabs Patch Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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, 12:52 PM.

  • #2
    FYI,

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

    Comment


    • #3
      very good

      i have read this ,it is very good.

      Comment


      • #4
        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

        Comment


        • #5
          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

          Comment


          • #6
            Thanks Marty!

            Comment


            • #7
              Thanks Marty....

              Thanks....

              Comment


              • #8
                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/

                Comment


                • #9
                  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);
                  	}
                  }

                  Comment


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

                    Comment


                    • #11
                      Please suggest how the same issue can be handled on spring 3.2... i am stuck on adding tag on jsp. My issue is i have to login multiple users on multiple tabs of same browser.. Please suggest

                      Comment


                      • #12
                        Originally posted by pmittal11 View Post
                        Please suggest how the same issue can be handled on spring 3.2... i am stuck on adding tag on jsp. My issue is i have to login multiple users on multiple tabs of same browser.. Please suggest
                        as far as I can tell, that is not in the scope of this conversation (pun intended :P )
                        browser tabs all share the same "session" and as such, you cannot log into the same app with different details on multiple tabs.

                        I may be incorrect though

                        Comment

                        Working...
                        X