使用 Spring MVC 在所有控制器中执行相同的操作
Do the same operation in all controllers with Spring MVC
问题很简单:一旦用户在我的 Spring MVC 应用程序中通过身份验证,我想在导航菜单中显示所有未读消息的计数,在每个页面中.
对于特定页面,我可以在其控制器中执行此操作:
@RequestMapping(value = "/some/url", method = RequestMethod.GET)
public String somePage(Model model, Principal principal) {
// Count messages and add to the view
int countMessages = userService.countAllUnreadMessages(principal.getName());
model.addAttribute("countMessages", countMessages);
// ...
return "some/view";
}
问题是如何避免在每个控制器的所有方法中进行相同的调用?有没有办法将数据参数传递给所有页面的视图? (也许所有页面,当然不包括 /login
表格)
您可以在用户登录后将属性存储在会话中,并从页面访问会话变量。你可以用 @SessionAttributes("countMessages")
注释你的控制器 class ,一旦你将它放入模型中,它就会将你的值存储在会话中。页面访问它的方式与您通过 ${countMessages}
访问模型变量的方式相同。
您也可以显式地使用会话,例如
@RequestMapping(value = "/some/url", method = RequestMethod.GET)
public String somePage(Model model, Principal principal, HttpSession session) {
// Count messages and add to the view
int countMessages = userService.countAllUnreadMessages(principal.getName());
model.addAttribute("countMessages", countMessages);
session.addAttribute("countMessages", countMessages);
// ...
return "some/view";
}
但请注意,会话会回答您问题的这一部分有没有办法将数据参数传递给所有页面的视图?现在只要阅读的消息数你也必须更新会话值,你可以通过简单地再次调用这个控制器方法来做到这一点。
其他答案提供了一种无需显式调用即可自动更新计数的方法,方法是拦截请求或在 @ControllerAdvice
上调用 @ModelAttribute
注释方法,这可能更适合您的问题
您可以使用 controller advice,定义 @ModelAttribute
注释方法,将消息计数添加到模型。
您可以使用拦截器来实现相同的功能。在 Interceptor 中写下你想要一次又一次调用的代码,对于所有你想要排除调用方法的代码,将它映射到排除映射路径中。
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login/**"/>
<bean class="com.test.yourInterceptorClass" />
</mvc:interceptor>
有多种方法可以实现您想要的。
我建议您使用自定义过滤器,它将用作 "decorator",并将您想要的数据添加到请求中。
public class MessagesFilter implements Filter{
@Override
public void destroy() {
// Do nothing
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
int countMessages = userService.countAllUnreadMessages(authentication.getName());
req.addAttribute("countMessages", countMessages);
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// Do nothing
}
}
或
public class MessagesFilter extends GenericFilterBean{
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//Implement this Function to have your filter working
}
请参阅此 answer 以获取适当的示例
问题很简单:一旦用户在我的 Spring MVC 应用程序中通过身份验证,我想在导航菜单中显示所有未读消息的计数,在每个页面中.
对于特定页面,我可以在其控制器中执行此操作:
@RequestMapping(value = "/some/url", method = RequestMethod.GET)
public String somePage(Model model, Principal principal) {
// Count messages and add to the view
int countMessages = userService.countAllUnreadMessages(principal.getName());
model.addAttribute("countMessages", countMessages);
// ...
return "some/view";
}
问题是如何避免在每个控制器的所有方法中进行相同的调用?有没有办法将数据参数传递给所有页面的视图? (也许所有页面,当然不包括 /login
表格)
您可以在用户登录后将属性存储在会话中,并从页面访问会话变量。你可以用 @SessionAttributes("countMessages")
注释你的控制器 class ,一旦你将它放入模型中,它就会将你的值存储在会话中。页面访问它的方式与您通过 ${countMessages}
访问模型变量的方式相同。
您也可以显式地使用会话,例如
@RequestMapping(value = "/some/url", method = RequestMethod.GET)
public String somePage(Model model, Principal principal, HttpSession session) {
// Count messages and add to the view
int countMessages = userService.countAllUnreadMessages(principal.getName());
model.addAttribute("countMessages", countMessages);
session.addAttribute("countMessages", countMessages);
// ...
return "some/view";
}
但请注意,会话会回答您问题的这一部分有没有办法将数据参数传递给所有页面的视图?现在只要阅读的消息数你也必须更新会话值,你可以通过简单地再次调用这个控制器方法来做到这一点。
其他答案提供了一种无需显式调用即可自动更新计数的方法,方法是拦截请求或在 @ControllerAdvice
上调用 @ModelAttribute
注释方法,这可能更适合您的问题
您可以使用 controller advice,定义 @ModelAttribute
注释方法,将消息计数添加到模型。
您可以使用拦截器来实现相同的功能。在 Interceptor 中写下你想要一次又一次调用的代码,对于所有你想要排除调用方法的代码,将它映射到排除映射路径中。
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login/**"/>
<bean class="com.test.yourInterceptorClass" />
</mvc:interceptor>
有多种方法可以实现您想要的。 我建议您使用自定义过滤器,它将用作 "decorator",并将您想要的数据添加到请求中。
public class MessagesFilter implements Filter{
@Override
public void destroy() {
// Do nothing
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
int countMessages = userService.countAllUnreadMessages(authentication.getName());
req.addAttribute("countMessages", countMessages);
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// Do nothing
}
}
或
public class MessagesFilter extends GenericFilterBean{
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//Implement this Function to have your filter working
}
请参阅此 answer 以获取适当的示例