おなじみのコード:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
私の理解では、/*
はhttp://Host:port/context/*
にマップされます。
/
はどうですか?確かに、http://Host:port/context
ルートのみにマップされません。実際、http://Host:port/context/hello
は受け入れますが、http://Host:port/context/hello.jsp
は拒否します。
http://Host:port/context/hello
がどのようにマップされるかを説明できますか?
<url-pattern>/*</url-pattern>
サーブレットの/*
は、デフォルトサーブレットやJSPサーブレットなど、サーブレットコンテナが提供するすべてのサーブレットを含む、他のすべてのサーブレットをオーバーライドします。どのようなリクエストを発行しても、そのサーブレットで終了します。したがって、これはサーブレットの不適切なURLパターンです。通常、 Filter
でのみ/*
を使用します。 FilterChain#doFilter()
を呼び出すことにより、より具体的なURLパターンをリッスンしているサーブレットのいずれかにリクエストを継続させることができます。
<url-pattern>/</url-pattern>
/
は、他のサーブレットをオーバーライドしません。他の登録済みサーブレットと一致しないすべてのリクエストに対して、servletcontainerの組み込みのデフォルトサーブレットのみを置き換えます。これは通常、静的リソース(CSS/JS/image/etc)およびディレクトリリストでのみ呼び出されます。 servletcontainerの組み込みのデフォルトサーブレットは、HTTPキャッシュリクエスト、メディア(オーディオ/ビデオ)ストリーミング、およびファイルダウンロードの再開も処理できます。通常、すべてのタスクを処理する必要があるため、デフォルトのサーブレットをオーバーライドする必要はありません。これは、決して簡単ではありません(JSFユーティリティライブラリ OmniFaces には オープンソース例 )。したがって、これは、サーブレットの不適切なURLパターンでもあります。 JSPページがこのサーブレットにヒットしない理由は、サーブレットコンテナの組み込みJSPサーブレットが呼び出されるためです。これは、デフォルトで、より具体的なURLパターン*.jsp
にすでにマップされています。
<url-pattern></url-pattern>
次に、空の文字列URLパターンもあります。これは、コンテキストルートが要求されたときに呼び出されます。これは、サブフォルダーが要求されたときに呼び出されない <welcome-file>
アプローチとは異なります。これは、 " home page servlet "が必要な場合に実際に探しているURLパターンです。空の文字列URLパターンとスラッシュURLパターン/
が逆の方法で正確に定義されることを直感的に期待していることを認めるだけなので、多くのスターターがこれについて混乱していることを理解できます。しかし、それはそれです。
実際にフロントコントローラーサーブレットを使用する場合は、*.html
、*.do
、/pages/*
などのより具体的なURLパターンにマッピングするのが最適です。 /app/*
など。フロントコントローラーのURLパターンを非表示にし、サーブレットフィルターの助けを借りて、/resources/*
、/static/*
などの一般的なURLパターンの静的リソースをカバーできます。 / *にマップされているフロントコントローラーサーブレットによって静的リソースが処理されるのを防ぐ方法 も参照してください。 Spring MVCには静的リソースサーブレットが組み込まれているため、Springで静的リソースの共通URLパターンを構成する場合は、そのフロントコントローラーを/
にマップできることに注意してください。 Spring MVCで静的コンテンツを処理する方法 も参照してください。
BalusCの答えをマッピングルールと例で補足したいと思います。
サーブレット2.5仕様のマッピングルール:
この例では、3つのサーブレットがあります。 /は、当社がインストールするデフォルトのサーブレットです。 Tomcatは、jspとjspxにサービスを提供する2つのサーブレットをインストールします。したがって、http://Host:port/context/hello
をマップするには
http://Host:port/context/hello.jsp
をマップするには
404
に何時間も苦しんでいたので、おそらくURLもどのようにマッピングされるかを知る必要があります。リクエストを処理するハンドラには2種類あります。 BeanNameUrlHandlerMapping
およびSimpleUrlHandlerMapping
。 servlet-mapping
を定義したとき、SimpleUrlHandlerMapping
を使用しています。知っておく必要があることの1つは、これら2つのハンドラーがalwaysUseFullPath
と呼ばれる共通のプロパティを共有していることで、デフォルトではfalse
です。
ここでfalse
は、SpringがURLをコントローラーにマッピングするために絶対パスを使用しないことを意味します。どういう意味ですか? servlet-mapping
を定義するとき:
<servlet-mapping>
<servlet-name>viewServlet</servlet-name>
<url-pattern>/perfix/*</url-pattern>
</servlet-mapping>
ハンドラーは実際に*
部分を使用してコントローラーを見つけます。たとえば、次のコントローラーは、404
を使用して要求すると、/perfix/api/feature/doSomething
エラーに直面します。
@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
@RequestMapping(value = "/doSomething", method = RequestMethod.GET)
@ResponseBody
public String doSomething(HttpServletRequest request) {
....
}
}
完璧にマッチしていますよね?しかし、なぜ404
。前述のように、alwaysUseFullPath
のデフォルト値はfalseです。つまり、リクエストでは/api/feature/doSomething
のみが対応するコントローラーを見つけるために使用されますが、コントローラーはそのパスを気にしません。 URLを/perfix/perfix/api/feature/doSomething
に変更するか、MyControllerベース@RequestingMapping
からperfix
を削除する必要があります。
キャンディの答えはほとんど正しいと思います。そうでないと思う小さな部分が一つあります。
Host:port/context/hello.jspをマップするには
「/ *」がHost:port/context/helloと一致しない理由は、「/ hello」をファイルではなくパスとして扱うためです(拡張子がないため)。
/*
と/
の本質的な違いは、/*
のマッピングを持つサーブレットが拡張マッピング(*.html
など)のあるサーブレットの前に選択されるのに対し、/
のマッピングを持つサーブレットは拡張マッピングが考慮された後にのみ選択されることです(そして、他の何にも一致しないリクエスト---それは「デフォルトサーブレット」です)。
特に、/*
マッピングの前に、/
マッピングが常に選択されます。いずれかを使用すると、リクエストがコンテナのデフォルトのサーブレットに到達しなくなります。
どちらかは、完全に一致するサーブレットマッピング(/foo/bar
など)と、/*
よりも長いパスマッピング(/foo/*
など)の後にのみ選択されます。空の文字列マッピングは、コンテキストルート(http://Host:port/context/
)と完全に一致することに注意してください。