2

I am trying to set a default model value for all of my controllers, which is interpreted by my HTML template's layout (this is to add a top banner to all pages, such as to warn about upcoming maintenance). I wrote an @ControllerAdvice class with an @ModelAttribute method, and this works correctly on all of my custom controllers.

However, it does nothing when I visit a mapping registered directly with the ViewControllerRegistry; the method is simply never called, and ParameterizableViewController seems to bypass the normal binding and model generation.

Is there a way to write advice that will get applied to view controllers as well as custom controllers?

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152

2 Answers2

2

Is there a way to write advice that will get applied to view controllers as well as custom controllers?

For your particular use case, I recommend to register a HandlerInterceptor and add your common model attributes to ModelAndView instance in postHandle method. Something like following:

public class CommonModelInterceptor extends HandlerInterceptorAdapter {
    @Override
    public void postHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler, 
                           ModelAndView modelAndView) throws Exception {
        modelAndView.addObject("Favorite Quote", "Welcome to the real world");
       // Go crazy with modelAndView
    }
}

Also, don't forget to register your interceptor:

public class WebConfig extends WebMvcConfigurerAdapter {
    // Usual stuff

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CommonModelInterceptor());
    }
}
Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
  • I've run into issues before where the `ModelAndView` presented to `postHandle` isn't the same one as is actually used; there appears to be an invisible hierarchy with the "default" model. I need this value to be overridable by individual controllers, and I'm concerned about not reliably detecting if the value's been added to the model already. – chrylis -cautiouslyoptimistic- May 13 '16 at 16:45
  • @chrylis In order to override model attributes, i guess you could add model attributes conditionally in `postHandle`. Get current model values using `modelAndView.getModel()` and if they weren't already provided, add them. – Ali Dehghani May 13 '16 at 16:49
  • That's what I meant about "reliably detecting", though: The `ModelAndViewContainer` creates a model hierarchy, and querying the model passed in can miss "default" (i.e., controller-provided `@ModelAttribute`) attributes. – chrylis -cautiouslyoptimistic- May 13 '16 at 16:58
0

@ControllerAdvice and other related annotations are handled by a RequestMappingHandlerAdapter registered automatically when you use @EnableWebMcv or

Other handling methods e.g resources or view controllers are handled by HttpRequestHandler and SimpleControllerHandlerAdapter which have no knowlege of @ControllerAdvice.

You can write a custom HandlerInterceptor which is application wide to handle the common logic and use the addInterceptors method of WebMvcConfigurer to register the interceptor

ekem chitsiga
  • 5,523
  • 2
  • 17
  • 18