標準のSpringMVCアプリケーションはDispatcherServlet、サーブレットコンテナに登録したを介してすべてのリクエストを処理します。
をDispatcherServlet見て、ApplicationContext可能な場合ApplicationContextはContextLoaderListener、特別なBeanに登録されており、要求処理ロジックをセットアップする必要があります。これらのBeanについては、ドキュメントで説明されています。
おそらく最も重要な、タイプHandlerMappingマップのBean
ハンドラーへの着信要求と、HandlerMapping実装によって詳細が異なるいくつかの基準に基づくプリプロセッサーとポストプロセッサー(ハンドラーインターセプター)のリスト。最も一般的な実装は注釈付きコントローラーをサポートしますが、他の実装も存在します。
のjavadocは、HandlerMapping実装がどのように動作する必要があるかをさらに説明しています。
DispatcherServletこのタイプのすべてのBeanを検索し、いくつかの順序でそれらを登録する(カスタマイズすることができます)。リクエストを処理している間、DispatcherServletこれらのHandlerMappingオブジェクトをループし、それぞれをテストしgetHandlerて、標準として表される着信リクエストを処理できるオブジェクトを見つけますHttpServletRequest。4.3.xのとおり、それはいずれも見つからない場合、それは警告ログに記録し、あなたが見ていることを
SomeNameという名前のURI[/some/path]をDispatcherServlet持つHTTPリクエストのマッピングが見つかりません
そしてどちらか投げるNoHandlerFoundExceptionか、すぐに404が見つかりませんでしたステータスコードでレスポンスをコミットします。
リクエストを処理できるがDispatcherServlet見つからなかったのはなぜHandlerMappingですか?
最も一般的なHandlerMapping実装はですRequestMappingHandlerMapping。これは、@ControllerBeanをハンドラー(実際には@RequestMappingアノテーション付きメソッド)として登録することを処理します。このタイプのBeanを(@Beanまたは<bean>または他のメカニズムを使用して)自分で宣言するか、組み込みオプションを使用することができます。これらは:
@Configurationクラスに@EnableWebMvc。で注釈を付けます。
<mvc:annotation-driven />XML構成でメンバーを宣言します。
上記のリンクで説明されているように、これらは両方ともRequestMappingHandlerMappingBean(および他の多くのもの)を登録します。ただし、aHandlerMappingはハンドラーなしではあまり役に立ちません。RequestMappingHandlerMapping一部の@ControllerBeanを想定しているため@Bean、Java構成のメソッド<bean>、XML構成の宣言、または@Controllerいずれかの注釈付きクラスのコンポーネントスキャンを通じて、それらも宣言する必要があります。これらのBeanが存在することを確認してください。
警告メッセージと404が表示され、上記のすべてを正しく構成した場合は、検出された@RequestMappingアノテーション付きハンドラーメソッドによって処理されない間違ったURIにリクエストを送信しています。
spring-webmvc内蔵された他のライブラリの提供HandlerMappingの実装。たとえば、BeanNameUrlHandlerMapping地図
URLからスラッシュ( "/")で始まる名前のBeanへ
そして、あなたはいつでもあなた自身を書くことができます。明らかに、送信するリクエストが、登録されたHandlerMappingオブジェクトのハンドラーの少なくとも1つと一致することを確認する必要があります。
あなたが暗黙的または明示的に登録していない場合はHandlerMapping豆(または場合detectAllHandlerMappingsであるがtrue)、DispatcherServletいくつかのレジスタのデフォルトを。これらはDispatcherServlet.properties、DispatcherServletクラスと同じパッケージで定義されています。それらはBeanNameUrlHandlerMappingandですDefaultAnnotationHandlerMapping(これは類似してRequestMappingHandlerMappingいますが非推奨です)。
デバッグ
Spring MVCは、を介して登録されたハンドラーをログに記録しますRequestMappingHandlerMapping。例えば、@Controllerのような
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
INFOレベルで以下をログに記録します
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
登録されているマッピングについて説明します。ハンドラーが見つからなかったという警告が表示されたら、メッセージ内のURIをここにリストされているマッピングと比較します。@RequestMappingSpring MVCがハンドラーを選択するには、で指定されたすべての制限が一致する必要があります。
他のHandlerMapping実装は、マッピングと対応するハンドラーを示唆する独自のステートメントをログに記録します。
同様に、DEBUGレベルでSpringロギングを有効にして、Springが登録するBeanを確認します。検出した注釈付きクラス、スキャンするパッケージ、および初期化するBeanを報告する必要があります。期待したものが存在しない場合は、ApplicationContext構成を確認してください。
その他のよくある間違い
ADispatcherServletは典型的なJavaEEServletです。あなたの典型的なとあなたはそれを登録<web.xml> <servlet-class>し、<servlet-mapping>宣言、または直接通じServletContext#addServletでWebApplicationInitializer、または任意のメカニズム春ブーツ用途に。そのため、サーブレット仕様で指定されているURLマッピングロジックに依存する必要があります。第12章を参照してください。
そのことを念頭に置いて、よくある間違いはDispatcherServlet、のURLマッピングを登録/*し、@RequestMappingハンドラーメソッドからビュー名を返し、JSPがレンダリングされることを期待することです。たとえば、次のようなハンドラメソッドについて考えてみます。
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
と InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
リクエストがパスのJSPリソースに転送されることを期待するかもしれません/WEB-INF/jsps/example-view-name.jsp。これは起こりません。代わりに、のコンテキスト名を想定しExample、DisaptcherServlet報告します
'dispatcher'という名前のURI[/Example/WEB-INF/jsps/example-view-name.jsp]をDispatcherServlet持つHTTPリクエストのマッピングが見つかりません
ためDispatcherServletにマッピングされる/*と/*(より高い優先度を有する完全一致、除く)すべて一致、DispatcherServlet処理するために選択されるであろうforwardからJstlView(によって返されますInternalResourceViewResolver)。ほとんどの場合、はDispatcherServletそのような要求を処理するように構成されていません。
代わりに、この単純なケースでは、DispatcherServlettoを登録して/、デフォルトのサーブレットとしてマークする必要があります。デフォルトのサーブレットは、リクエストの最後の一致です。これにより、通常のサーブレットコンテナは、デフォルトのサーブレットを試す前に、にマップされた内部サーブレット実装を選択して*.jsp、JSPリソース(たとえば、Tomcatが持っているJspServlet)を処理できるようになります。
それはあなたがあなたの例で見ているものです。