4

複数のコントローラー クラスと DefaultAnnotationHandlerMapping を使用する場合、Spring Portlet MVC 3.1 を使用すると問題が発生します。

バックグラウンド

  • Render & Action フェーズのアノテーションを備えた Spring Portlet MVC 3.1 を使用しています。
  • JBoss EPP 5.1.1 を使用しています

問題

  • パラメータを使用したポートレット レンダリング リクエストの場合、ポートレットで正しくないページがレンダリングされる

原因

  • Spring ポートレット MVC は、正しいアノテーションを持つ予想されるメソッドとは異なる @RenderMapping のメソッドを使用しています

テクニカル分析

  1. すべてのコントローラーには @RenderMapping および @ActionMapping アノテーションが含まれており、ポートレット URL で設定されたパラメーターに基づいて予期されるメソッドが確実に呼び出されるようにするための「params」引数があります。デフォルトのレンダリングには、「params」引数のない @RenderMapping アノテーションを持つメソッドがあり、リクエストにパラメーターが含まれていない場合に空の JSP をレンダリングするために使用します。

  2. あなたの本の第 7 章と第 8 章を読んだことから、Dispatcher Portlet が着信要求の適切なハンドラー マッピングを取得し、それを構成済みのコントローラー Bean の適切なメソッドに送信しようとすることがわかりました。私たちの想定では、デフォルトの @RenderMapping アノテーション (パラメーターなし) は、特定のリクエストパラメーターに一致するアノテーションを持つコントローラーに他のメソッドがないことを確認した後にのみ呼び出されると想定していました。

  3. ただし、この仮定が正しくないことを認識するためにデバッグを行いました。DefaultAnnotationHandlerMapping は、コントローラー Bean で使用可能なアノテーションのリストを事前定義された順序でトラバースするように見えます。これは、デフォルトの @RenderMapping アノテーション (パラメーターなし) を持つコントローラー Bean がリストの前に表示される場合、リストのさらに下にある正しいメソッドではなく、デフォルトの @RenderMapping アノテーション (パラメーターなし) を持つメソッドが呼び出されることを意味します。 .

明らかなエラー

Windows環境で開発し、Linux環境にデプロイしています。Windows では、ハンドラーがコントローラー Bean をアルファベット順に循環することがわかります。そのため、最初に、'Z' に最も近い Bean 名を持つパラメーターなしで @RenderMapping アノテーション付きメソッドをコントローラーに追加することで問題を解決しました。

ただし、Linux では、コントローラー Bean が別の順序で検出されるようです。問題を強調するために、以下に Spring ログを添付しました。no params @RenderMapping アノテーションは YourDetailsController にあり、Windows のログでわかるように、リストの最後に表示されますが、Linux では表示されません。つまり、リスト内の YourDetailsController の後に表示されるコントローラーの 1 つにアクセスしようとすると、代わりに YourDetailsController の no params アノテーションが常にヒットすることになります。

質問

  1. 私たちの仮定は間違っていますか?
  2. 私たちの診断は期待される行動を反映していますか? それとも、Spring Portlet MVC のバグですか?
  3. ハンドラーマッピング Bean リストを形成するためにスキャンされた注釈を取得する別の方法はありますか?
  4. (注釈の代わりに) xml 構成を使用すると、問題が解決しますか?
  5. 複数のハンドラー マッピングと順序を定義して、デフォルトのハンドラー マッピングがディスパッチャー ポートレットによって使用される最後のハンドラー マッピングになるようにすることはできますか?

この問題に関するご意見やアドバイスをいただければ幸いです。

4

5 に答える 5

1

私は最近この問題に悩まされていたので、見つけた情報に基づいて追加情報を追加すると思いました.

私の場合、より具体的に注釈が付けられたコントローラー/アクション(やなど)があったとしても、デフォルトのコントローラー(空と@Controller注釈@ActionMapping付き)が常に呼び出されていました。私のケースをさらに奇妙にしたのは、Tomcat/Pluto では正常に機能したが、WAS/WebSphere Portal Server では機能しなかったことです。@Controller(XXXX)@ActionMapping(YYYY)

結局のところ、Spring の 3.1.x で導入されたバグがあり、これはアノテーション ハンドラーが適切にソートされていないことを意味します。https://jira.springsource.org/browse/SPR-9303および https://jira.springsource.org/browse/SPR-9605を参照してください。どうやら、これは 3.1.3 で修正されています。

私にとって大きな謎は、Tomcat では機能するのに、WebSphere では機能しないのはなぜかということでした。根本的な原因は、Pluto (2.0.3) が Sun JRE 1.6.0 を使用しているのに対し、WebSphere は IBM JRE 1.5.0 を使用していることです。2 つの JRE には異なる実装がありCollections.sort()、それらが等しいことを報告する配列要素 (つまり、compareTo()関数の結果) を並べ替えると、異なる出力順序になります。上記の Spring のバグ (一部のハンドラーが等しくない場合に等しいと報告される) のため、2 つの JRE 間でハンドラーの順序付けが非決定論的であったことを意味します。

したがって、私の場合、IBM JRE はたまたまデフォルトのコントローラーを最初の要素として配置したため、毎回それが選択されます。「等しい」ハンドラーの順序付けに影響を与えることができる 1 つの方法 (「等しい」は、Spring のバグによる危険な定義です) は、Spring によって検出される順序を変更することです。これは、並べ替えへの入力の順序に影響します。ルーティーン。そのため、上記の投稿によると、コントローラーをコンポーネント スキャンから XML 構成に明示的にリストされるように移動することが機能します。私の場合、デフォルトのコントローラのパッケージをコンポーネント スキャンの最後のエントリにするだけで十分でした。XML構成に移動する必要はありませんでした。

とにかく、これが何が起こっているのかをもう少し明らかにするのに役立つことを願っています.

于 2012-07-31T23:03:53.103 に答える
1

マイク。まったく同じ問題が発生しています。JDK 7、Spring 3.1.1.RELEASE、および Hibernate 4.1.3.Final を使用しています。Linux (Fedora) で開発し、Linux (Fedora および SL) にデプロイしています。

ピース (コントローラー) が一度に 1 つずつ動作していることは確かでしたが、一緒にレンダリング要求への呼び出しがランダムに無視されたため、行き詰まりました。何かを変更すると、レンダリング要求で再び動作するようになることがありますが、すべてが一緒に動作することはありませんでした。

Walter が提案したように、独自のパッケージにデフォルトのレンダリング リクエストのみを含むコントローラーを分離したとき、デフォルトのレンダリング リクエストのみを (削除/表示リクエストを含める前に) 残し、ポートレットの XML 構成内のコントローラーのスキャンを分離しました。他の後にデフォルトコントローラーをスキャンすると、突然すべてが魅力的に機能します。

このバグがSpringトラッカーにあるかどうかを確認するのは興味深いでしょう...

于 2012-07-11T13:46:42.467 に答える
0

Ashish Sarin から受け取った応答:

こんにちはマイク、

プロジェクトであなたがフォローしているのとまったく同じシナリオをテストしていませんが、コントローラーを定義するための正しいアプローチのようには見えないと言えます。コントローラーが @RenderMapping および @ActionMapping アノテーションのみを使用する場合、開発者は受信ポートレット要求の処理を担当する正確なコントローラーを見つけるのが難しい場合があります。タイプ レベルで @RequestMapping を使用してポートレット リクエストを特定のコントローラにマップし、リクエスト パラメータを使用してリクエストをコントローラ内の特定のメソッドにさらに絞り込むことをお勧めします。

このアプローチでまだ問題が発生している場合はお知らせください。

于 2012-05-04T09:30:28.960 に答える
0

context:component-scan (nnn-portlet.xml 内) を使用して、コントローラーのデフォルトのレンダリング マッピングをポートレット間で分割します。

于 2013-09-19T09:34:20.880 に答える
0

マイク、あなたの説明は、私たちが直面している問題とまったく同じです。Windows では、同じ回避策を実装し (コントローラーの前に Z を付けたデフォルトのレンダリングを付けました)、それで解決しました。Linux 環境の同じコードには、あなたと同じ問題があります。選択されていない方法として注文されたタイムスタンプの問題のように見えましたが、そのルートに行く運はありませんでした。

これは春のバグだと思いました。

ここでのアプローチは問題ないと思います。さまざまな機能を処理するさまざまなコントローラーが必要ですが、デフォルトのコントローラーが必要です。

今のところ、回避策が1つ見つかりました。コンポーネントスキャンに含まれないように、デフォルトのレンダリング方法のコントローラーを別のパッケージに移動しました。

そのコントローラーを (portletname-portlet.xml ファイルで) component-scan 行の後に手動で追加するので、それが最後のコントローラーとして追加されます。

于 2012-05-07T15:30:00.577 に答える