Reputation:
I have a Spring MVC 3 application which integrates tiles 3 to use a common view template for every page. For the sake of simplicity assume this template consists of a header, a body and a footer part. The header and footer parts always display the same type of data, which is retrieved from a database. The body part changes from request to request.
Since Spring MVC is based on an MVC architecture, my first idea was that each controller has to provide the data which is displayed in the header and footer part. This is ugly and feels not appropriate, because it leads to duplication of the same code in multiple controllers. Also, storing this type of data as session values seems not to be a good solution.
How is this problem usually solved?
Thanks a lot!
Upvotes: 2
Views: 156
Reputation: 17371
You could create an interceptor which will inject the common data into your model. A nice feature of using interceptors is that you can easily map them to URLs of your choice.
public class CommonDataInjectingInterceptor extends HandlerInterceptorAdapter {
@Autowired
private CommonDataHolder holder;
public void setCommonDataHolder(CommonDataHolder holder) {
this.holder = holder;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (holder != null && modelAndView != null) {
modelAndView.addObject("menu", holder.getMenu());
modelAndView.addObject("footer", holder.getFooter());
}
}
}
Another way could be to create a @ControllerAdvice
which will define generic behavior shared across all controllers. The functionality of such @ControllerAdvice
in Spring 3 is rather basic. Spring 4 introduces new options to control which controllers should be affected by it.
Using a @ControllerAdvice
in combination with @ModelAttribute
can be quite handy. Like Ayub Malik partially explained in his answer.
@ControllerAdvice
public class CommonDataControllerAdvice {
@Autowired
private CommonDataHolder holder;
public void setCommonDataHolder(CommonDataHolder holder) {
this.holder = holder;
}
@ModelAttribute("menu")
public Menu menu() {
return holder.getMenu();
}
@ModelAttribute("footer")
public Footer footer() {
return holder.getFooter();
}
}
Upvotes: 1
Reputation: 2578
In your controller create a method (or methods) with the annotation @ModelAttribute.
e.g.
@ModelAttribute("someData")
public SomeData getData() {
return new SomeData(); // init your common data here
}
This will make 'someData' available to your Tiles view layer.
You could then have an abstract base class with this method, if you need to reuse.
Upvotes: 1