【问题标题】:Do the same operation in all controllers with Spring MVC使用 Spring MVC 在所有控制器中执行相同的操作
【发布时间】:2015-07-05 22:27:37
【问题描述】:

问题很简单:一旦用户在我的 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 表单)

【问题讨论】:

    标签: spring hibernate jsp spring-mvc authentication


    【解决方案1】:

    您可以在用户登录后将属性存储在会话中,并从页面访问会话变量。您可以使用 @SessionAttributes("countMessages") 注释您的控制器类,一旦您将其放入模型中,它也会将您的值存储在会话中。 Pages 将通过${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 注释方法,这可能更适合您的问题

    【讨论】:

    • 几个相关的问题。第一:如何将初始计数添加到会话中?会话在 CustomUserDetailsS​​ervice 类中可用吗? 2nd:当用户阅读消息时,新的计数将在控制器中重新计算。我应该使用哪种方式来更新countMessages 会话属性?
    • 我已经编辑了一个答案,但我的答案只为您提供了在任何页面中都可用的值。如果您需要自动维护计数,而无需显式调用控制器而不是其他答案似乎更合适
    【解决方案2】:

    有多种方法可以实现您想要的。 我建议您使用自定义过滤器,它将用作“装饰器”,并将您想要的数据添加到请求中。

    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 以获取适当的示例

    【讨论】:

      【解决方案3】:

      您可以使用拦截器来实现相同的功能。在 Interceptor 中编写您想要一次又一次调用的代码,并为所有您想要排除方法映射调用的人在排除映射路径中编写它。

      <mvc:interceptor>
          <mvc:mapping path="/**"/>
          <mvc:exclude-mapping path="/login/**"/>
          <bean class="com.test.yourInterceptorClass" />
      </mvc:interceptor>
      

      【讨论】:

      • 您的回答对我有用。我接受你的回答,但我希望你改进它,包括我的userService 调用并将结果添加到 YourInterceptorClass preHandle() 方法中的request。不是为了我,而是为了未来的访客,如果你让我高兴的话;)
      【解决方案4】:

      您可以使用controller advice,定义一个@ModelAttribute 注释方法,将消息计数添加到模型中。

      【讨论】:

        猜你喜欢
        • 2010-11-23
        • 1970-01-01
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多