How do you fill reusable partials (like the header) in a Spring MVC web app with dynamic data like username every time a certain group of controllers are called (page controllers) but not for others (form controllers, ajax, ...)?
header:
<#import "../spring.ftl" as spring />
<!DOCTYPE html>
<html>
<head>
<title>DW-Client</title>
</head>
<body>
<h2>Welcome ${menu.userName}</h2>
index:
<#include "common/header.ftl">
<!-- stuff -->
<#include "common/footer.ftl" />
This is kind of a follow up to this SO post. The guy however seems to be no longer active and I wanted to hear some fresh opinions on our approach to filling partials in a spring mvc web app with data like dynamic menus...
The other guy proposed using an AbstractController
that gets extended by all page controllers and fills a variable via an @ModelAttribute
annotated method, which seems like an okay idea. but my initial thought was:
Why not use AOP with pointcuts to fill the ModelAndView.model
One would just annotate a controller or method with say @MenuData
. Now whenever the controlle gets called it will get intercepted by an Aspect that adds the required information to the ModelAndView:
@RequestMapping(value = "/")
@MenuData
public ModelAndView homePath() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
return mav;
}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MenuData {
}
@Aspect
@Component
public class MenuDataAspect {
@Inject
private MenuDataProvider menuDataProvider;
@Pointcut("within(@MenuData *) && execution(public * * (..))")
public void menuDataRequested() {
}
@Around("menuDataRequested()")
public Object provideMenuData(ProceedingJoinPoint pjp) throws Throwable {
Object output = pjp.proceed();
ModelAndView mav = (ModelAndView) output;
mav.getModel().put("menu", menuDataProvider.getMenuData());
return mav;
}
}
Now I should be able to say ${menu.userName}
or whatever in my header partial... This way I can controll exactly which controller should have menuData.
This concept can be made even more flexible by telling the pointcut to intercept all controllers that begin Page (not sure about the syntax, but I know it'll work, something like @Pointcut("within(*.Page*)")
or all controllers in the pageController package or whatever.
Of course one could also define multiple annotations for different menu scenarios that are not depending on the session but rather on the pages.
So I'm wondering, does this approach look like a good idea or are there any pitfalls? What would you do differently / better? Which approach do you use?
Thanks!