Announcement Announcement Module
Collapse
No announcement yet.
Rendering a page using multiple controllers, views, models Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Rendering a page using multiple controllers, views, models

    Hi all,

    I'm evaluating Spring and its MVC web framework for use in a new project. I've read through some of the MVC docs, but still have one major question. Is there a way to get Spring to use multiple controllers, views and models to render a single page?

    For example, our site will have on any given page a side nav menu, a top nav menu, login and search widgets, and some type of content. I'd like to model each of these as separate reusable components, each with its own MVC triumvirate.

    Is there some way to get Spring to aggregate these separate controllers, models and views into a single page? Perhaps some kind of composite controller class that calls out to other sub-controllers and aggregates the views that each of them returns?

    Thanks,

    Morley

  • #2
    It's possible to use multiple controllers to render a single page, but it's a bit overkill since there is only one resulting view. You would do this by making one controller invoke the handleRequest() method of another controller.

    I find it much simpler to put my navigation/template concerns in interceptors that are processed on each request (before and/or after controller execution). With this approach you have a single controller per page. The controller only worries about the main content of the page. The interceptor(s) supply all of the extra information needed for headers, sidebars, footers, etc. Another advantage here is that a single interceptor can be configured to handle many different requests (URLs), while a controller is usually mapped to a single URL or page.

    Comment


    • #3
      Daniel,

      I agree that multiple MVCs is overkill if the navigation/template stuff is fairly simple, which it would be in most cases. With our system, when a user logs in, that user may have admin rights to one or more of the components on the page, including the navigation/template stuff. We want the user to be able to edit the component in-place, so for us it makes sense for each component to have its own model, view and controller.

      We had the same idea for having one controller call the handleRequest method of other controllers. But the parent controller has to return just a single ModelAndView, so what would it do with the ModelAndView's returned by all of its sub-controllers? I think it would need to compose these somehow into a composite ModelAndView, probably containing a composite View that renders each of its sub-views. Is there anything like this already in the Spring MVC web framework?

      Thanks,

      Morley

      Comment


      • #4
        I've been running into some simillar issues here

        Daniel,

        your response about interceptors sounds very interesting. Could you expand on that a bit. Or perhaps point to some areas of the documentation that discuss what you are talking about.

        Our team is still somewhat new to Spring (struts converts) and this interceptor concept is something I haven't heard of yet.

        Thanks.

        Comment


        • #5
          Morley,

          it sounds like your looking portlet support. I don't know much about it, but I know it is currently under development for SpringFramework.


          rwells,

          You can get a good handle on Spring AOP here:
          http://www.springframework.org/docs/reference/aop.html

          If you're not familiar with AOP, then you may find it simpler to look at some code that uses interceptors. The JPetStore sample app distributed with the Spring source code has such an example. Take a look at the "secureHandlerMapping" object that's defined in petstore-servlet.xml. It intercepts HTTP requests and performs authentication checking using the signonInterceptor object.

          Code:
          <bean id="secureHandlerMapping"
            class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="interceptors">
              <list>
                <ref bean="signonInterceptor"/>
              </list>
            </property>
            ...
          </bean>
          
          <bean id="signonInterceptor"
            class="org.springframework.samples.jpetstore.web.spring.SignonInterceptor"/>
          The SignonIntercetpor class is what you're interested in here. Note that this class only overrides the preHandle() method of HandlerInterceptorAdapter. To create an interceptor, you would create your own class that extends HandlerInterceptorAdapter and override one or more of it's three methods. The preHandle() method is invoked before the controller is invoked. If you are loading data to be used by the view (not needed by the controller), you will want to override postHandle(). It is invoked after the controller has returned it's ModelAndView, but before the view is rendered. The afterCompletion() method is invoked after the view has been rendered.

          HTH

          Comment


          • #6
            Is there anything like this already in the Spring MVC web framework?
            AFAIK Spring does not support this out of the box. I've coded a simple chained controler that does some of what you're requesting:

            Code:
            public class ChainedController extends AbstractController &#123;
            	private Controller&#91;&#93; controllerChain;
            	private String defaultView;
            
            	/** Creates a new instance of ChainedController */
            	public ChainedController&#40;&#41; &#123;
            	&#125;
            
            	public void setControllerChain&#40;Controller&#91;&#93; controllerChain&#41; &#123;
            		this.controllerChain = controllerChain;
            	&#125;
            
            	public void setDefaultView&#40;String defaultView&#41; &#123;
            		this.defaultView = defaultView;
            	&#125;
            
            	public String getDefaultView&#40;&#41; &#123;
            		return defaultView;
            	&#125;
            
            	protected ModelAndView handleRequestInternal&#40;HttpServletRequest request,
            			HttpServletResponse response&#41; throws Exception &#123;
            		boolean hasAlternativeViewName = false;
            		String viewName = getDefaultView&#40;&#41;;
            		Map chainedModel = new HashMap&#40;&#41;;
            
            		for &#40;int i = 0; i < controllerChain.length; i++&#41; &#123;
            			ModelAndView modelAndView = controllerChain&#91;i&#93;.handleRequest&#40;
            					request, response&#41;;
            
            			if &#40;modelAndView.getViewName&#40;&#41; == null&#41; &#123;
            				throw new ServletException&#40;
            						"Controller did not return a view name."&#41;;
            			&#125;
            
            			if &#40;!getDefaultView&#40;&#41;.equals&#40;modelAndView.getViewName&#40;&#41;&#41;
            					&& !viewName.equals&#40;modelAndView.getViewName&#40;&#41;&#41;&#41; &#123;
            				if &#40;hasAlternativeViewName&#41; &#123;
            					throw new ServletException&#40;
            							"More than 1 controller specified an alternative view."&#41;;
            				&#125;
            				hasAlternativeViewName = true;
            				viewName = modelAndView.getViewName&#40;&#41;;
            			&#125;
            
            			for &#40;Iterator it = modelAndView.getModel&#40;&#41;.entrySet&#40;&#41;.iterator&#40;&#41;; it
            					.hasNext&#40;&#41;;&#41; &#123;
            				Map.Entry e = &#40;Map.Entry&#41; it.next&#40;&#41;;
            				Object oldVal = chainedModel.put&#40;e.getKey&#40;&#41;, e.getValue&#40;&#41;&#41;;
            				if &#40;oldVal != null && &#40;!oldVal.equals&#40;e.getValue&#40;&#41;&#41;&#41;&#41; &#123;
            					throw new ServletException&#40;
            							"Different objects placed into the model under the same key &#91;"
            									+ e.getKey&#40;&#41; + "&#93;."&#41;;
            				&#125;
            			&#125;
            		&#125;
            
            		return new ModelAndView&#40;viewName, chainedModel&#41;;
            	&#125;
            &#125;
            HTH

            Ollie

            Comment


            • #7
              mhowell,

              Have you tried looking into using Strut's "Tiles" framework with Spring's MVC? I'm just starting out with the two, and haven't yet put more than one form on a rendered view. But I'd be suprised if it support it in some fashion.

              There's a tiles example in the Spring distribution.

              Comment


              • #8
                Hi Morley,

                Half a year ago i was facing the same problem: i wanted to build a kind of portal based on multiple Spring controllers and views.

                I looked into Portlets but the Spring integration was in a very early stage and it seemed to me a bit overhead for simply building a page based on components.

                Then i tried Tiles (a part of Struts, but can be used separatly with Spring MVC) which already had some Spring integration and basically does what i want: combining multiple jsp's into one big jsp, so you can use a block based layout.

                Tiles also offers to connect "sub-views" with separate "controllers" (components in Tiles-speak), which add the model data for this single view. So you really have small views with small controllers which you can combine to a complete page.

                The problem with this: Tiles is Struts based and does not use Springs controllers to handle the sub-views. I wanted to have a page made up of real Spring controllers, which could also be called directly, completely without Tiles.

                So i wrote some connectors, which use Tiles to build up a page of multiple jsp's. Every jsp receives its data from a normal Spring controller. POST's also are handled by the correct contoller only, not by all. The jsp's and controllers have no dependency on Tiles and can also be used directly.

                This Spring-Tiles-integration is part of a project i am currently working on, and it is not that simple to cut this part out. Anyway, if you -really- are interested in this solution and prepared to spend some time diving into Tiles and my own code, perhaps i could extract the important parts for you.

                Regards,
                Sebastian

                Comment


                • #9
                  Sebastian,

                  I've just started working on a Spring MVC / Tiles project and would love to see someone else's code. A lot of this stuff is new to me, and I'm not sure if what I'm doing is a hack, or just the way it needs to be done.

                  Any samples you can send my way would be greatly appreciated. (Heck, you might want to consider posting an article on your Tiles integration.)

                  Thanks in advance,
                  -michael.

                  Comment


                  • #10
                    I believe SiteMesh might be just what you are looking for. Find out more about it here:
                    http://opensymphony.com/sitemesh/

                    Comment


                    • #11
                      Originally posted by eliot
                      I believe SiteMesh might be just what you are looking for.
                      I quickly looked through the Sitemesh docu, and though it sounds interesting i think it concentrates on putting together multiple JSPs (at least in the out-of-the-box-version). But my impression might be wrong about that...
                      At least to me the interesting point was to have one Spring-controller/view-combination for every part of the page, so these parts are really self-contained and can be used separately.

                      Sebastian

                      Comment


                      • #12
                        Originally posted by michael
                        I've just started working on a Spring MVC / Tiles project and would love to see someone else's code. A lot of this stuff is new to me, and I'm not sure if what I'm doing is a hack, or just the way it needs to be done.

                        Any samples you can send my way would be greatly appreciated. (Heck, you might want to consider posting an article on your Tiles integration.)
                        Hi Michael,

                        i will try to extract the important code parts on the weekend and make those available here. I very well can imagine that others find this code useful too, so lets see if it works... anyway, you should be prepared for a bit of fiddling around, i am not sure if i can provide you with an already working version...

                        Sebastian

                        Comment


                        • #13
                          Originally posted by Sebastian
                          I quickly looked through the Sitemesh docu, and though it sounds interesting i think it concentrates on putting together multiple JSPs...But my impression might be wrong about that...
                          It can be used with any view/controller technology. You can build composite views very easily. It's more powerful than tiles in this way as it is view-generation agnostic - any page, dynamic or static, jsp, servlet can be used with it.

                          Originally posted by Sebastian
                          At least to me the interesting point was to have one Spring-controller/view-combination for every part of the page
                          To be correct, this is possible with SiteMesh. Its a proper tool for building proper portals.

                          Comment


                          • #14
                            In addition you might want to get other views on this topic.

                            http://raibledesigns.com/page/rd?anc...emesh_tutorial

                            Comment


                            • #15
                              Originally posted by eliot
                              It's more powerful than tiles in this way as it is view-generation agnostic - any page, dynamic or static, jsp, servlet can be used with it.
                              Thanks for the clarification, eliot. That really sounds interesting.

                              I looked for more information, but i still did not find the answer i am looking for. Maybe this code snippet from one of the Sitemesh-Tutorials shows my question more clearly:
                              Code:
                              <td valign="top" width="200">
                                 <%-- grabs the naivation.jsp page and decorates with the panel decorator and puts it here --%>
                                 <page&#58;applyDecorator page="/WEB-INF/jsps/navigation.jsp" name="panel" />
                              </td>
                              This seems to directly include a jsp. What i would like to do, is to have this jsp generated by a Sping Controller (to provide data to the jsp) and not to have the jsp included.

                              Is this possible with Sitemesh?

                              Thanks,
                              Sebastian

                              Comment

                              Working...
                              X