web-dev-qa-db-ja.com

Spring MVCが404で応答し、「DispatcherServletにURI [...]を持つHTTP要求のマッピングが見つかりません」と報告するのはなぜですか?

私は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;
    }
}

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

@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リソースがあります。Spring MVCはリクエストを処理してJSPに転送するために私のコントローラを使用すると思っていましたが、なぜ404で応答するのでしょうか。


これは、この警告メッセージに関する質問の正規の投稿です。

75

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

DispatcherServletは、そのApplicationContextを調べ、使用可能な場合は、要求処理ロジックをセットアップするために必要な特別なBeanのApplicationContextに登録されているContextLoaderListenerを調べます。 これらのBeanはドキュメントに記載されています

おそらく最も重要な、タイプ HandlerMapping のBean

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

HandlerMappingのjavadoc は、実装の動作方法をさらに説明しています。

DispatcherServletは、このタイプのすべてのBeanを検出し、それらを何らかの順序で登録します(カスタマイズ可能)。リクエストの処理中、DispatcherServletはこれらのHandlerMappingオブジェクトをループし、それぞれを getHandler でテストして、標準のHttpServletRequestとして表される着信リクエストを処理できるオブジェクトを見つけます。 4.3.x現在、見つからない場合、それは 警告をログに記録

SomeNameという名前のDispatcherServletのURI [/some/path]のHTTP要求のマッピングが見つかりません

および eitherNoHandlerFoundException をスローするか、404 Not Foundステータスコードで応答を直ちにコミットします。

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

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

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

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

警告メッセージと404を受け取っていて、上記のすべてを正しく構成している場合、リクエストを間違ったURIに送信している、検出されたものによって処理されないもの@RequestMappingアノテーション付きハンドラーメソッド。

spring-webmvcライブラリは、他の組み込みHandlerMapping実装を提供します。たとえば、 BeanNameUrlHandlerMapping maps

uRLから、スラッシュ(「/」)で始まる名前のBeanへ

いつでも自分で書くことができます。明らかに、送信するリクエストが登録済みのHandlerMappingオブジェクトのハンドラーの少なくとも1つと一致することを確認する必要があります。

HandlerMapping Beanを暗黙的または明示的に登録しない場合(または detectAllHandlerMappingstrueの場合)、DispatcherServletはいくつかの デフォルト を登録します。これらは、DispatcherServletクラスと同じパッケージの DispatcherServlet.properties で定義されています。それらはBeanNameUrlHandlerMappingおよび 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をここにリストされているマッピングと比較します。 @RequestMapping で指定されたすべての制限は、Spring MVCがハンドラーを選択するために一致する必要があります。

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

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

その他のよくある間違い

DispatcherServletは、典型的なJava EE Servlet です。通常の<web.xml><servlet-class>および<servlet-mapping>宣言、または ServletContext#addServlet で直接 WebApplicationInitializer に登録するか、Springブートが使用するメカニズムで登録します。そのため、 サーブレット仕様 で指定されたurl mappingロジックに依存する必要があります。第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リソースへのリクエストは forwarded であると期待するかもしれません。これは起こりません。代わりに、Exampleのコンテキスト名を仮定すると、DisaptcherServlet

名前が「dispatcher」のDispatcherServletのURI [/Example/WEB-INF/jsps/example-view-name.jsp]のHTTP要求のマッピングが見つかりません

DispatcherServlet/*にマップされ、/*はすべてに一致するため(優先順位がより高い完全一致を除く)、- DispatcherServletforwardによって返される)からJstlViewを処理するためにInternalResourceViewResolverが選択されます。 ほとんどの場合、DispatcherServletはそのような要求を処理するように構成されません

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

それはあなたの例で見ているものです。

83

前述したことに加えて、私は自分の問題を解決しました: `

@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: Spring Boot WebアプリケーションでJSPファイルがレンダリングされない

3
RoutesMaps.com

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

いろいろなことを試した後、私は@EnableWebMvcを削除してみましたが、うまくいきました!

編集: これは参考ドキュメントです つまり@EnableWebMvcアノテーションを削除するべきです

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

2
Acapulco

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

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

Eclipseで、プロジェクト - >クリーンの選択 - >プロジェクトのビルドを選択します。クラスファイルが、ワークスペースのビルド中のコントローラファイルに対して生成されているかどうかを確認します。

0
Anil N.P

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

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

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

私はcom.happy.appのパッケージ(フォルダではない)を追加し、ファイルをフォルダからEclipseのパッケージに移動し、問題を解決しました。

0
Roy