2

私の 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 メソッドが呼び出されます。ただし、コンソールの出力によると、インターセプターの posthandle メソッドの前に jsp がレンダリングされていることがわかります。

なぜこのように振る舞うかを理解するのを手伝ってくれる人はいますか?

4

2 に答える 2

2

さらに調査したところ、Spring コンテキスト xml ファイルの構成方法に問題があることがわかりました。2 つのファイルがありました。1 つはアプリケーション コンテキスト用で、もう 1 つは Web コンテキスト用です。最初に、アプリケーション コンテキスト xml で component-scan タグと 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"/>

なぜこれが機能し、以前の構成では機能しなかったのかを理解しようとしています。

于 2013-01-01T20:10:11.373 に答える
0

ビューがレンダラーになった後に postHanlde でセッションを設定したため、これは正常です。したがって、最初のビューにはデータがありません。最初のページをレンダリングした後にセッションに保存されたので、2 ページ目にはデータが表示されます。

コードを preHandle メソッドに記述すれば、思い通りに動作します

于 2013-01-01T12:54:21.770 に答える