web-dev-qa-db-ja.com

web.xmlのサーブレットURLマッピングはどのように使用されますか?

コンテンツを含むweb.xmlファイルがあります。

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>

リクエストしてみた

.../path/test/abc 
.../path/test

両方のリクエストはServlet2によって処理されます。どうして?

[〜#〜] update [〜#〜]

皆さん、助けてくれてありがとう。動作はサーブレットマッピング宣言の順序に依存することに気付きました。私はこのweb.xmlを試しました

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet3</servlet-name>
    <servlet-class>org.mycompany.test3</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet4</servlet-name>
    <servlet-class>org.mycompany.test4</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet3</servlet-name>
    <url-pattern>/path/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet4</servlet-name>
    <url-pattern>/path</url-pattern>
</servlet-mapping>

結果:

.../path/test/abc - servlet2
.../path/test/ - servlet2
.../path/test - servlet2

.../path/abc - servlet3
.../path/ - servlet4
.../path - servlet4
22
wfr

Servlet 3.0 specification から、これはWebコンテナがリクエストを受信した後にサーブレットを見つけなければならない方法です(強調鉱山):

サーブレットへのマッピングに使用されるパスは、リクエストオブジェクトからのリクエストURLからコンテキストパスとパスパラメータを引いたものです。以下のURLパスマッピングルールが順番に使用されます。 最初に成功した一致が使用され、それ以上の一致は試行されません

  1. コンテナは、リクエストのパスがサーブレットのパスに完全に一致することを試みます。一致すると、サーブレットが選択されます。
  2. コンテナは再帰的に最長のパス接頭辞を一致させようとします。これは、パスセパレーターとして「/」文字を使用して、一度に1つのディレクトリずつパスツリーをステップダウンすることによって行われます。最長一致により、選択されたサーブレットが決まります。
  3. URLパスの最後のセグメントに拡張子(.jspなど)が含まれている場合、サーブレットコンテナは、その拡張子のリクエストを処理するサーブレットと一致しようとします。拡張機能は、最後の「。」文字の後の最後のセグメントの一部として定義されます。
  4. 前の3つのルールのいずれでもサーブレットが一致しない場合、コンテナは要求されたリソースに適したコンテンツを提供しようとします。 「デフォルト」サーブレットがアプリケーションに定義されている場合、それが使用されます。多くのコンテナは、コンテンツを提供するための暗黙的なデフォルトサーブレットを提供します。

コンテナでは、大文字と小文字を区別する文字列比較を一致に使用する必要があります。

マッピングの仕様も確認する必要があります(以下を参照)。

Webアプリケーションデプロイメント記述子では、次の構文を使用してマッピングを定義します。

  • ‘/’文字で始まり、‘/*’サフィックスで終わる文字列がパスマッピングに使用されます。

  • ‘*.’プレフィックスで始まる文字列は、拡張マッピングとして使用されます。

  • 空の文字列("")は、アプリケーションのコンテキストルート、つまりhttp://Host:port/<contextroot>/という形式のリクエストに正確にマッピングされる特別なURLパターンです。この場合、パス情報は’/’であり、サーブレットパスとコンテキストパスは空の文字列(““)です。

  • ’/’文字のみを含む文字列は、アプリケーションの「デフォルト」サーブレットを示します。この場合、サーブレットパスはリクエストURIからコンテキストパスを引いたものであり、パス情報はnullです。

  • 他のすべての文字列は、完全一致のみに使用されます

ここで例を見てみましょう。次の一連のマッピングを検討してください。

パスパターンサーブレット
/foo/bar/* servlet1 
/baz/* servlet2 
/catalog servlet3 
 *。bop servlet4 

次の動作が発生します。

着信パスサーブレット処理リクエスト
/foo/bar/index.html servlet1 
/foo/bar/index.bop servlet1 
/baz servlet2 
 /baz/index.html servlet2 
/catalog servlet3 
/catalog/index.html「デフォルト」サーブレット
/catalog/racecar.bop servlet4 
/index .bop servlet4 

/catalog/index.htmlおよび/catalog/racecar.bopの場合、“/catalog”にマップされたサーブレットは、一致が正確ではないため使用されないことに注意してください。

今あなたの問題に来ています:)

/path/testは、マッピングの仕様の5番目のポイントに属します。つまり、/path/testで終わるパスのみがservlet1をターゲットにします。

ただし、/path/test/*は、同じ仕様の最初のポイントに該当します。この意味は:

.../path/testservlet1によって処理され、

.../path/test/abcservlet2によって処理されます

テストアプリケーションで確認されました。

49

パスが競合しています。

両方のパスの意味は同じで、「/ *」は違いはありません。どうやらパスを試すと、最後の一致(servlet2)が実行されます。

通常、次のように、サーブレット名のパスを入力します。

/path/test/servlet1
/path/test/servlet2
1
Terry