なぜSpring MVCは404で応答し、"No mapping found for HTTP request with URI [....]in DispatcherServlet "というレポートを出すのでしょうか?

java spring spring-mvc servlets


TomcatにデプロイされたSpring MVCアプリケーションを書いています。次の最小限の完全で検証可能な例を参照してください

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { };
    }
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { SpringServletConfig.class };
    }
    protected String[] getServletMappings() {
        return new String[] { "/*" };
    }
}

どこ SpringServletConfig があります

@Configuration
@ComponentScan("com.example.controllers")
@EnableWebMvc
public class SpringServletConfig {
    @Bean
    public InternalResourceViewResolver resolver() {
        InternalResourceViewResolver vr = new InternalResourceViewResolver();
        vr.setPrefix("/WEB-INF/jsps/");
        vr.setSuffix(".jsp");
        return vr;
    }
}

最後に、 com.example.controllers パッケージに @Controller があります

@Controller
public class ExampleController {
    @RequestMapping(path = "/home", method = RequestMethod.GET)
    public String example() {
        return "index";
    }
}

私のアプリケーションのコンテキスト名は Example です。にリクエストを送信したとき

http://localhost:8080/Example/home

アプリケーションはHTTPステータス404で応答し、次のようにログを記録します。

WARN  o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI `[/Example/WEB-INF/jsps/index.jsp]` in `DispatcherServlet` with name 'dispatcher'

/WEB-INF/jsps/index.jsp にJSPリソースがあります。SpringMVCがコントローラーを使用してリクエストを処理し、JSPに転送することを期待しているのに、なぜ404で応答するのですか?


これは、この警告メッセージに関する質問に対する正規の投稿であることを意図しています。





Answer 1 Sotirios Delimanolis


標準のSpring MVCアプリケーションは、サーブレットコンテナーに登録した DispatcherServlet を介してすべてのリクエストを処理します。

DispatcherServlet のは、その時に見える ApplicationContext と、利用可能な場合、 ApplicationContext のはに登録された ContextLoaderListener それはセットアップにロジックを提供するその要求を必要とする特殊な豆のために。これらのBeanはドキュメントで説明されています

間違いなく最も重要なタイプの HandlerMapping マップのBean

ハンドラーへの着信要求、およびいくつかの基準に基づくプリプロセッサーとポストプロセッサー(ハンドラーインターセプター)のリスト。詳細は HandlerMapping 実装によって異なります。最も一般的な実装は注釈付きコントローラーをサポートしますが、他の実装も存在します。

HandlerMapping のjavadocは、実装がどのように動作する必要があるかをさらに説明しています。

DispatcherServlet のは、このタイプのすべてのBeanを検索し、いくつかの順序でそれらを登録する(カスタマイズすることができます)。リクエストを処理している間、 DispatcherServlet はこれらの HandlerMapping オブジェクトをループし、 getHandler を使用してそれぞれをテストし、標準の HttpServletRequest として表される着信リクエストを処理できるオブジェクトを見つけます。4.3.xのとおり、それはいずれも見つからない場合、それは警告ログに記録し、あなたが見ていることを

マッピングはURIを持つHTTPリクエストは見つかりません [/some/path]DispatcherServlet 名somenameのと

そしてどちらかのスロー NoHandlerFoundExceptionか、すぐに404が見つかりませんでしたステータスコードでレスポンスをコミットします。

DispatcherServlet がリクエストを処理できる HandlerMapping を見つけられなかったのはなぜですか?

最も一般的な HandlerMapping 実装は RequestMappingHandlerMapping であり、 @Controller Beanをハンドラーとして登録します(実際には @RequestMapping アノテーション付きメソッド)。このタイプのBeanを自分で宣言する( @Bean または <bean> または他のメカニズムを使用)か、組み込みオプションを使用できます。これらは:

  1. @Configuration クラスに @EnableWebMvc アノテーションを付けます。
  2. XML構成で <mvc:annotation-driven /> メンバーを宣言します。

上記のリンクで説明しているように、これらは両方とも RequestMappingHandlerMapping Bean(および他の束)を登録します。ただし、 HandlerMapping はハンドラーなしではあまり役に立ちません。 RequestMappingHandlerMapping はいくつかの @Controller Beanを想定しているため、Java構成の @Bean メソッドまたはXML構成の <bean> 宣言、またはいずれかの @Controller 注釈付きクラスのコンポーネントスキャンを介して、それらも宣言する必要があります。これらの豆が存在することを確認してください。

警告メッセージと404が表示され、上記のすべてを正しく設定した場合、リクエストを間違ったURI送信します @RequestMapping 、検出された@RequestMappingアノテーション付きハンドラーメソッドによって処理されません。

spring-webmvc 内蔵の他のライブラリの提供 HandlerMapping 実装を。たとえば、 BeanNameUrlHandlerMapping マップ

URL からスラッシュ ("")で始まる名前のビーンへ

いつでも自分で書くことができます。もちろん、送信するリクエストが、登録されている HandlerMapping オブジェクトのハンドラーの少なくとも1つと一致していることを確認する必要があります。

HandlerMapping Beanを暗黙的または明示的に登録しない場合(または、 detectAllHandlerMappings true の場合)、 DispatcherServlet はいくつかのデフォルトを登録します。これらは、 DispatcherServlet クラスと同じパッケージの DispatcherServlet.properties で定義されています。それらは BeanNameUrlHandlerMapping および DefaultAnnotationHandlerMapping RequestMappingHandlerMapping に似ていますが、非推奨です)です。

Debugging

Spring MVCは、 RequestMappingHandlerMapping を通じて登録されたハンドラーをログに記録します。たとえば、 @Controller like

@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をここにリストされているマッピングと比較します。Spring MVCがハンドラーを選択するには、 @RequestMapping 指定されたすべての制限が一致する必要があります。

他の HandlerMapping 実装は、マッピングと対応するハンドラーにヒントを与える独自のステートメントをログに記録します。

同様に、DEBUGレベルでSpringロギングを有効にして、Springが登録するBeanを確認します。見つかった注釈付きクラス、スキャンしたパッケージ、初期化したBeanを報告する必要があります。予期したものが存在しない場合は、 ApplicationContext 構成を確認してください。

その他のよくあるミス

A DispatcherServlet ちょうど典型的なJava EEのある Servlet 。典型的な <web.xml> <servlet-class> および <servlet-mapping> 宣言を使用して、または WebApplicationInitializer ServletContext#addServlet を介して直接、またはSpringブートが使用するメカニズムを使用して登録します。そのため、サーブレット仕様で指定されている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;
}

リクエストがパス /WEB-INF/jsps/example-view-name.jsp の JSPリソースに転送されることを期待するかもしれません。これは起こりません。代わりに、コンテキスト名を Example とすると、 DisaptcherServlet

マッピングはURIを持つHTTPリクエストが見つかりません [/Example/WEB-INF/jsps/example-view-name.jsp]DispatcherServlet 名「ディスパッチャ」は

ので DispatcherServlet のはにマッピングされている /* および /* (高い優先度を持っている完全一致、除いて)一致するすべてのもの、 DispatcherServlet 処理するために選択されるであろう forward から JstlView (によって返さ InternalResourceViewResolver )。ほとんどの場合、 DispatcherServlet はそのようなリクエストを処理するように設定されません

代わりに、この単純なケースでは、 DispatcherServlet/ に登録し、デフォルトのサーブレットとしてマークする必要があります。デフォルトのサーブレットは、リクエストに対する最後の一致です。これにより、デフォルトのサーブレットを試す前に、通常のサーブレットコンテナが *.jsp にマップされた内部サーブレット実装を選択して、JSPリソースを処理することができます(たとえば、Tomcatには JspServlet があります)。

それはあなたの例を見てのことです。




Answer 2 RoutesMaps.com


私の問題を解決したのは、前に説明した:`に加えて

@Bean
public InternalResourceViewResolver resolver() {
    InternalResourceViewResolver vr = new InternalResourceViewResolver();
    vr.setPrefix("/WEB-INF/jsps/");
    vr.setSuffix(".jsp");
    return vr;
}

added tomcat-embed-jasper:

<dependency>
       <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
       <scope>provided</scope>
</dependency>

`from:JSPファイルがSpring Boot Webアプリケーションでレンダリングされない




Answer 3 Acapulco


私の場合、バージョン5.1.2のInterceptors Springのドキュメントに従って(Spring Boot v2.0.4.RELEASEを使用している間)、 WebConfig クラスにアノテーション @EnableWebMvc がありましたが、これはアプリケーションの他の何かと競合しているようです静的アセットが正しく解決されないようにします(つまり、CSSまたはJSファイルがクライアントに返されませんでした)。

多くの異なることを試した後、 @EnableWebMvc削除してみましたが、うまくいきました!

編集: @EnableWebMvc アノテーションを削除する必要があると述べているリファレンスドキュメントは次のとおりです

少なくとも私の場合はどうやら、Springアプリケーションをすでに構成しています( web.xml やその他の静的ファイルを使用するわけではありませんが、それは間違いなくプログラムによるものです)。そのため、競合が発生しました。




Answer 4 Anil N.P


同じエラーが発生する別の理由を見つけました。これは、 controller.java ファイルのクラスファイルが生成されていないことが原因である可能性もあります。その結果、web.xml に記述されているディスパッチャサーブレットが、コントローラクラスの適切なメソッドにマッピングできなくなりました。

@Controller
Class Controller{
@RequestMapping(value="/abc.html")//abc is the requesting page
public void method()
{.....}
}

日食のプロジェクト->クリーンの選択->プロジェクトのビルドの下で、ワークスペースのビルドでコントローラーファイルのクラスファイルが生成されているかどうかを確認してください。




Answer 5 Roy


私の場合、ターゲットクラスはソースとは異なるフォルダパターンで生成されていることがわかりました。これはおそらくeclipseではコントローラを格納するためにフォルダを追加していて、パッケージとしては追加していません。そのため、springの設定で間違ったパスを定義してしまいました。

ターゲットクラスはapp以下のクラスを生成していて、com.happy.appを参照していました。

<context:annotation-config />
<context:component-scan
    base-package="com.happy.app"></context:component-scan> 

com.happy.appにパッケージ(フォルダではなく)を追加し、フォルダからパッケージにファイルを移動させたところ、問題が解決しました。