I wish to implement dynamically changeable menu (updating whenever annotated method or controller added) for my Spring MVC application.
What i want is to introduce new annotation (@RequestMenuMapping
) which will go to @Controller
beans and their methods (just like @RequestMapping
works).
Heres is what i want, User
class, producing menu like
Users
Index | List | Signup | Login
with following code:
@Controller
@RequestMapping("user")
@RequestMenuMapping("Users")
public class User {
@RequestMapping("")
@RequestMenuMapping("Index")
public String index(/* no model here - just show almost static page (yet with JSP checks for authority)*/) {
return "user/index.tile";
}
@RequestMapping("list")
@RequestMenuMapping("List")
public String list(Model model) {
model.addAttribute("userList",/* get userlist from DAO/Service */);
return "user/list.tile";
}
@RequestMapping("signup")
@RequestMenuMapping("Signup")
public String signup(Model model) {
model.addAttribute("user",/* create new UserModel instance to be populated by user via html form */);
return "user/signup.tile";
}
@RequestMapping("login")
@RequestMenuMapping("Login")
public String login(Model model) {
model.addAttribute("userCreds",/* create new UserCreds instance to be populated via html form with login and pssword*/);
return "user/login.tile";
}
}
I think that Spring AOP may help me to pointcut methods with @RequestMenuMapping
annotation and via @AfterReturning
add something representing web-site menu to model.
But this raises two questions:
- How do i get
Model
instance in@AfterReturning
advice method in case it is missing in adviced method (as in.index()
)? - How do i get all methods (as in java reflection
Method
) and classes (as in java reflectionClass
) annotated with@RequestMenuMapping
in order to build complete menu index?
InterceptorDemo:
@Aspect
@Component
public class InterceptorDemo {
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void requestMapping() {
}
@Pointcut("@annotation(you.package.RequestMenuMapping)")
public void requestMenuMapping() {
}
@AfterReturning("requestMapping() && equestMenuMapping()")
public void checkServer(JoinPoint joinPoint,Object returnObj) throws Throwable {
Object[] args = joinPoint.getArgs();
Model m = (Model)args[0];
// use joinPoint get class or methd...
}
}
If you want to intercept Contoller with you own, you can wirte another pointcut and ProceedingJoinPoint
object can get what you want.
I think a better soultion would be a bean post processor to scan all controller classes for the @RequestMenuMapping
and a HandlerInterceptor
to add the menu items to every model map.
Q1:
ModelAndView
object create at org.springframework.web.servlet.DispatcherServlet.doDispatch()
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
So, you can intercept handle
method after returing or override the method.
Q2:As far as i know, there are two ways getting annotation methods.
1.Use AOP: You can declare a pointcut like this:
@Pointcut("@annotation(you.package.RequestMenuMapping)")
public void requestMenuMappingPountcut() {
}
2.Use reflection.
Class clazz = Class.forName(classStr);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(RequestMapping.class)
&& method.isAnnotationPresent(RequestMenuMapping.class)) {
// do something
}
}
来源:https://stackoverflow.com/questions/14003035/implementing-dynamic-menu-for-spring-mvc-aop-application