tags:

views:

88

answers:

4

i'm looking into using Spring MVC - how would I structure the fact that a page can be composed of several different views Consider a controller that's basically:

 public ModelAndView handleRequest(HttpServletRequest request, 
                                   HttpServletResponse response) 
                                  throws ServletException, IOException {
          List<Post> posts = repository.getNewPosts();

          return new ModelAndView("posts", "posts", posts);
    }

However, I decide that on every page, I'd also want a side "pane" that shows data based on some logic. That "pane" would just be a .jsp that gets included from the above "posts" view, and I could change my controller to:

 public ModelAndView handleRequest(HttpServletRequest request, 
                                   HttpServletResponse response) 
                                  throws ServletException, IOException {
      List<Post> posts = repository.getNewPosts();
      List<Items> items= repository.getItems();    
      return new ModelAndView("model", "model", new MyCommonViewModel(posts,items));
    }

But then I'd have to change every controller to also do List<Items> items= repository.getItems(); , and change everything again the next time I come up with something new.

This seems messy. How do I structure this ?

`

+1  A: 

Take a look at Tiles.

matt b
+1 Tiles works well with my solution!
Paul Hanbury
A: 

Firstly, you could extend AbstractController so that you have a base class that can load the data that you need to use in all of your Controllers.

public class AbstractHasPaneController extends AbstractController {

    public Object getPaneData() {
        return repository.getItems();
    }

    // ...
}

Then, your other Controllers extend your abstract Controller

public class MyPageController extends AbstractHasPaneController {

    public ModelAndView 
    handleRequest(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        ModelAndView modelAndView = new ModelAndView("posts");
        modelAndView.addObject( "posts", repository.getNewPosts() );
        modelAndView.addObject( "model", this.getPaneData() );    
        return modelAndView  ;
    }

    // ...
}

When you come up with something new, all you have to edit is AbstractHasPaneController.getPaneData().

Paul Hanbury
+2  A: 

If every page in your system needs to display a kind of pane, then you can provide the model data for this using an interceptor. This is almost always preferable to putting code in an abstract controller (as suggested in another answer) because that then forces you to always extend that from that particular class hierarchy.

public class YourInterceptor extends HandlerInterceptorAdapter {

    private Repository repository;
    public void setRepository (Repository repository) {
        this.repository = repository;
    }

    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler)
    throws Exception {
        List<Post> posts = repository.getNewPosts();
        List<Items> items= repository.getItems();    
        request.setAttribute("model", new MyCommonViewModel(posts,items));
    }
}

wiring it up like

<beans>
    <bean id="handlerMapping"
          class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="interceptors">
            <list>
                <ref bean="yourInterceptor"/>
            </list>
        </property>
        <property name="mappings">
            <props>
                <!-- SNIP -->
            </props>
        </property>
    </bean>

    <bean id="yourInterceptor"
          class="your.YourInterceptor">
        <property name="repository"><ref bean="repository" /></property>
    </bean>
<beans>

You could also look at using something like sitemesh. This allows you to create a template page which is a base for all your other pages (or certain sets of pages depending on how you configure it). This would prevent you from having to include the pane jsp on every page. But if your project is small enough it may not be worth the bother.

anger
A: 

I very much anticapte the proposal to use an HandlerInterceptor for providing general purpose information to your view. And to extend the answer from bart and regarding setting up the interceptors more easily Spring 3.0 provides the mvc configuration namespace

On the top-level element beans simply add

xmlns:mvc="http://www.springframework.org/schema/mvc"

And inside your bean configuration you can then use:

<mvc:annotation-driven />

<mvc:interceptors>
    <bean class="org.example.web.interceptors.YourInterceptor"/>
</mvc:interceptors>
ngeek