I have a menu that is data driven(cached) and it is a global component. I want to be able to inject the menu items for every request since every page is going to be using it. What is the best place to put it? I'm using annotation based Spring3. Best solution I can think of is using a OncePerRequestFilter and adding it there or sub-classing the Controller, but not sure how to do that with @Controller annotation.
5 Answers
I can think of two easy options:
Each @Controller
class exposes the data as a method annotated with @ModelAttribute
, e.g.
@ModelAttribute
public MyData getMyData() {
...
}
That's not really nice if you have multiple controllers, though. Also, this has the annoying side-effect of encoding the myData
on to the URL for every redirect
I suggest instead that implement a HandlerInterceptor
, and expose the data to every request that way. You can't use any annotation-lovin, but it's better separated from your business logic this way. This is similar to your OncePerRequestFilter
idea, but a but more Spring-y.

- 398,947
- 96
- 818
- 769
-
3+1 for mentioning the side-effect of ModelAttribute. I wish that some one had told me that before :( Thanks for the direction. – Hoàng Long Jun 13 '12 at 10:03
Starting Spring 3.2, you can use @ControllerAdvice instead of using @ExceptionHandler, @InitBinder, and @ModelAttribute in each Controller. They will be applied to all @Controller beans.
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class GlobalBindingInitializer {
@InitBinder
public void registerCustomEditors(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}
If you had started out with Spring Roo generated code, or limit the annotations scanned by component-scan using include-filter, then add the required filter in webmvc-config.xml
<!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
<context:component-scan base-package="com.sensei.encore.maininterface" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<!-- ADD THE BELOW LINE -->
<context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
</context:component-scan>

- 8,967
- 3
- 49
- 55
-
May be also useful link about `@ControllerAdvice` in `Spring 4`: http://blog.codeleak.pl/2013/11/controlleradvice-improvements-in-spring.html – Andremoniy Apr 11 '16 at 12:44
I just found an answer for the very same question. It's part of my post:
You just need to set the expose model attributes variable to false on the RedirectView.
If you need add some global variables that every view can resolve these variables, why not define into a properties or map? then use spring DI, refer to the view resolver bean. it is very useful,such as static veriable, e.g. resUrl.
<property name="viewResolvers">
<list>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="attributes" ref="env" />
<property name="exposeContextBeansAsAttributes" value="false" />
<property name="prefix" value="${webmvc.view.prefix}" />
<property name="suffix" value="${webmvc.view.suffix}" />
</bean>
</list>
</property>

- 11
- 1