【问题标题】:Why is HandlerInterceptorAdapter postHandle method getting invoked after page is rendered为什么在呈现页面后调用 HandlerInterceptorAdapter postHandle 方法
【发布时间】:2012-12-30 16:53:24
【问题描述】:

我的 Spring MVC Web 应用程序在页面顶部有一个导航菜单,其中包含指向项目列表的链接。从数据库中检索项目列表。此菜单对应用程序中的所有页面通用。目前,在每个控制器中,我检索并存储会话中的项目列表(如果尚未在会话中),以便它在每个页面上都可用。它工作正常,但我觉得应该有更好的方法来做到这一点。为了避免这种冗余,我现在尝试使用 HandlerInterceptorAdapter。我能够让它工作,但并不完美。第一次加载页面时,我没有看到我在会话中设置的对象。但是,如果我刷新页面,我确实会在会话中看到该对象。

我以这种方式创建了我的拦截器:

public class MyHandlerInterceptor extends HandlerInterceptorAdapter {
  private MyService myService;

  //Constructor
  public MyHandlerInterceptor(MyService myService) {
        this.myService = myService;
  }

  //Overridden method
  public void postHandle(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler, 
                         ModelAndView modelAndView) throws Exception {
    System.out.println("In posthandle...");

    if (request.getSession().getAttribute("items") == null) {
      request.getSession().setAttribute("items", myService.getCategories());
    }
  }
}

我声明了拦截器:

<mvc:interceptors>
  <bean class="com.gyanify.webapp.interceptors.MyHandlerInterceptor"
        autowire="constructor"/>
</mvc:interceptors>

我正在检查对象是否在 jsp 呈现时设置在会话中:

...
Session Attributes <br/>
<%
    System.out.println("Printing from the jsp...");
    Enumeration keys = session.getAttributeNames();
    while (keys.hasMoreElements())
    {
      String key = (String)keys.nextElement();
      out.println(key + ": " + session.getValue(key) + "<br>");
    }
%>
...

这样,当我第一次加载页面时,我会在控制台中看到以下打印:

...
Returning view....(this is printed from the controller)
Printing from the jsp...
In posthandle...
...

我的理解是在页面渲染之前调用了posthandle方法。但是,根据控制台上的输出,我看到jsp是在拦截器的posthandle方法之前渲染的。

谁能帮我理解它为什么会这样?

【问题讨论】:

    标签: java jsp spring-mvc interceptor


    【解决方案1】:

    经过进一步调查,我发现问题出在我配置 spring 上下文 xml 文件的方式上。我有两个文件——一个用于应用程序上下文,另一个用于 Web 上下文。最初我在应用程序上下文 xml 中定义了组件扫描和 mv:annotation-driven 标签:

    <context:component-scan base-package="com.webapp" />
    <mvc:annotation-driven validator="validator"/>
    

    并在 web 上下文 xml 中定义了我的拦截器。

    在调试模式下,我看到拦截器在处理请求后被映射到上下文。

    为了使其工作,我将应用程序上下文中的配置更改为以下内容:

    <context:component-scan base-package="com.webapp">
      <context:exclude-filter type="regex" expression="com\.webapp\.controllers\.*"/>
    </context:component-scan>
    

    并将以下内容添加到 Web 上下文 xml:

    <context:component-scan base-package="com.webapp.controllers" />
    <mvc:annotation-driven validator="validator"/>
    

    我仍在试图理解为什么这有效,而早期的配置却没有。

    【讨论】:

      【解决方案2】:

      这是正常的,因为您在视图渲染器之后在 postHanlde 中设置了会话。所以第一个视图没有数据,在第二个页面上,因为它是在渲染第一个页面后保存在会话中的,你可以看到它。

      在 preHandle 方法中编写你的代码,它会按照你的意愿工作

      【讨论】:

      • 我试过了,但没有解决问题。我最终能够让它工作(请参阅我添加的答案)。
      猜你喜欢
      • 2015-03-17
      • 2020-10-09
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多