Java 为什么 Spring MVC 以 404 响应并报告“在 DispatcherServlet 中找不到带有 URI [...] 的 HTTP 请求的映射”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41577234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:30:00  来源:igfitidea点击:

Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?

javaspringspring-mvcservlets

提问by Sotirios Delimanolis

I'm writing a Spring MVC application deployed on Tomcat. See the following minimal, complete, and verifiable example

我正在编写一个部署在 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[] { "/*" };
    }
}

Where SpringServletConfigis

哪里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;
    }
}

Finally, I have a @Controllerin the package com.example.controllers

最后,我@Controller在包里有一个com.example.controllers

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

My application's context name is Example. When I send a request to

我的应用程序的上下文名称是Example. 当我向

http://localhost:8080/Example/home

the application responds with an HTTP Status 404 and logs the following

应用程序响应 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'

I have a JSP resource at /WEB-INF/jsps/index.jspI expected Spring MVC to use my controller to handle the request and forward to the JSP, so why is it responding with a 404?

我有一个 JSP 资源,/WEB-INF/jsps/index.jsp我希望 Spring MVC 使用我的控制器来处理请求并转发到 JSP,那么为什么它以 404 响应?



This is meant to be a canonical post for questions about this warning message.

这是关于此警告消息的问题的规范帖子。

采纳答案by Sotirios Delimanolis

Your standard Spring MVC application will serve all requests through a DispatcherServletthat you've registered with your Servlet container.

您的标准 Spring MVC 应用程序将通过DispatcherServlet您在 Servlet 容器中注册的一个来处理所有请求。

The DispatcherServletlooks at its ApplicationContextand, if available, the ApplicationContextregistered with a ContextLoaderListenerfor special beans it needs to setup its request serving logic. These beans are described in the documentation.

DispatcherServlet在它的外观ApplicationContext,如果可用,ApplicationContext用注册ContextLoaderListener的,它需要建立其请求的服务逻辑特殊豆。这些 bean 在文档中进行了描述

Arguably the most important, beans of type HandlerMappingmap

可以说是最重要的,类型为HandlerMappingmap 的bean

incoming requests to handlers and a list of pre- and post-processors (handler interceptors) based on some criteria the details of which vary by HandlerMappingimplementation. The most popular implementation supports annotated controllers but other implementations exists as well.

对处理程序的传入请求以及基于某些标准的预处理器和后处理器(处理程序拦截器)列表,其细节因HandlerMapping实现而异。最流行的实现支持带注释的控制器,但也存在其他实现。

The javadoc of HandlerMappingfurther describes how implementations must behave.

javadocHandlerMapping进一步描述了实现必须如何表现。

The DispatcherServletfinds all beans of this type and registers them in some order (can be customized). While serving a request, the DispatcherServletloops through these HandlerMappingobjects and tests each of them with getHandlerto find one that can handle the incoming request, represented as the standard HttpServletRequest. As of 4.3.x, if it doesn't find any, it logs the warningthat you see

DispatcherServlet发现这种类型的所有豆类和以某种顺序将它们登记(可定制)。在处理请求时,DispatcherServlet循环遍历这些HandlerMapping对象并测试它们中的每getHandler一个以找到可以处理传入请求的对象,表示为标准HttpServletRequest. 从 4.3.x 开始,如果没有找到任何,它会记录您看到的警告

No mapping found for HTTP request with URI [/some/path]in DispatcherServletwith name SomeName

没有找到映射与URI HTTP请求[/some/path]DispatcherServlet使用的名字SomeName

and eitherthrows a NoHandlerFoundExceptionor immediately commits the response with a 404 Not Found status code.

并且要么抛出一个NoHandlerFoundException或立即提交一个404 Not Found状态码的响应。

Why didn't the DispatcherServletfind a HandlerMappingthat could handle my request?

为什么没有DispatcherServlet找到HandlerMapping可以处理我的请求?

The most common HandlerMappingimplementation is RequestMappingHandlerMapping, which handles registering @Controllerbeans as handlers (really their @RequestMappingannotated methods). You can either declare a bean of this type yourself (with @Beanor <bean>or other mechanism) or you can use the built-in options. These are:

最常见的HandlerMapping实现是RequestMappingHandlerMapping,它将注册@Controllerbean 处理为处理程序(实际上是它们的@RequestMapping注释方法)。您可以自己声明这种类型的 bean(使用@Bean<bean>或其他机制),也可以使用内置 options。这些是:

  1. Annotate your @Configurationclass with @EnableWebMvc.
  2. Declare a <mvc:annotation-driven />member in your XML configuration.
  1. 注释你的@Configuration带班@EnableWebMvc
  2. <mvc:annotation-driven />在您的 XML 配置中声明一个成员。

As the link above describes, both of these will register a RequestMappingHandlerMappingbean (and a bunch of other stuff). However, a HandlerMappingisn't very useful without a handler. RequestMappingHandlerMappingexpects some @Controllerbeans so you need to declare those too, through @Beanmethods in a Java configuration or <bean>declarations in an XML configuration or through component scanning of @Controllerannotated classes in either. Make sure these beans are present.

正如上面的链接所描述的,这两个都将注册一个RequestMappingHandlerMappingbean(和一堆其他东西)。但是,如果HandlerMapping没有处理程序,a不是很有用。RequestMappingHandlerMapping需要一些@Controllerbean,因此您也需要声明这些 bean,通过@BeanJava 配置中的方法或<bean>XML 配置中的声明,或者通过@Controller对任一中带注释的类的组件扫描。确保这些豆子存在。

If you're getting the warning message and a 404 and you've configured all of the above correctly, then you're sending your request to the wrong URI, one that isn't handled by a detected @RequestMappingannotated handler method.

如果您收到警告消息和 404 并且您已正确配置以上所有内容,那么您将请求发送到错误的 URI,该请求未由检测到的带@RequestMapping注释的处理程序方法处理。

The spring-webmvclibrary offers other built-in HandlerMappingimplementations. For example, BeanNameUrlHandlerMappingmaps

spring-webmvc库提供了其他内置HandlerMapping实现。例如,BeanNameUrlHandlerMapping地图

from URLs to beans with names that start with a slash ("/")

从 URL 到名称以斜杠(“/”)开头的 bean

and you can always write your own. Obviously, you'll have to make sure the request you're sending matches at least one of the registered HandlerMappingobject's handlers.

而且你总是可以自己写。显然,您必须确保您发送的请求至少与已注册HandlerMapping对象的处理程序之一匹配。

If you don't implicitly or explicitly register any HandlerMappingbeans (or if detectAllHandlerMappingsis true), the DispatcherServletregisters some defaults. These are defined in DispatcherServlet.propertiesin the same package as the DispatcherServletclass. They are BeanNameUrlHandlerMappingand DefaultAnnotationHandlerMapping(which is similar to RequestMappingHandlerMappingbut deprecated).

如果您不隐式或显式注册任何HandlerMappingbean(或者如果detectAllHandlerMappingstrue),则会DispatcherServlet注册一些默认值。这些定义在DispatcherServlet.propertiesDispatcherServlet类相同的包中。它们是BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping(类似于RequestMappingHandlerMapping但已弃用)。

Debugging

调试

Spring MVC will log handlers registered through RequestMappingHandlerMapping. For example, a @Controllerlike

Spring MVC 将记录通过RequestMappingHandlerMapping. 例如,一个@Controller喜欢

@Controller
public class ExampleController {
    @RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
    public String example() {
        return "example-view-name";
    }
}

will log the following at INFO level

将在 INFO 级别记录以下内容

Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()

This describes the mapping registered. When you see the warning that no handler was found, compare the URI in the message to the mapping listed here. All the restrictions specified in the @RequestMappingmust match for Spring MVC to select the handler.

这描述了注册的映射。当您看到未找到处理程序的警告时,请将消息中的 URI 与此处列出的映射进行比较。@RequestMapping必须匹配 Spring MVC 中指定的所有限制才能选择处理程序。

Other HandlerMappingimplementations log their own statements that should hint to their mappings and their corresponding handlers.

其他HandlerMapping实现记录他们自己的语句,这些语句应该提示它们的映射和相应的处理程序。

Similarly, enable Spring logging at DEBUG level to see which beans Spring registers. It should report which annotated classes it finds, which packages it scans, and which beans it initializes. If the ones you expected aren't present, then review your ApplicationContextconfiguration.

同样,在 DEBUG 级别启用 Spring 日志记录以查看 Spring 注册了哪些 bean。它应该报告它找到了哪些带注释的类,它扫描了哪些包,以及它初始化了哪些 bean。如果您期望的那些不存在,请检查您的ApplicationContext配置。

Other common mistakes

其他常见错误

A DispatcherServletis just a typical Java EE Servlet. You register it with your typical <web.xml><servlet-class>and <servlet-mapping>declaration, or directly through ServletContext#addServletin a WebApplicationInitializer, or with whatever mechanism Spring boot uses. As such, you must rely on the url mappinglogic specified in the Servlet specification, see Chapter 12. See also

ADispatcherServlet只是一个典型的 Java EE Servlet。你可以用你的典型<web.xml><servlet-class><servlet-mapping>声明来注册它,或者直接通过ServletContext#addServleta WebApplicationInitializer,或者使用 Spring boot 使用的任何机制。因此,您必须依赖Servlet 规范中指定的url 映射逻辑,请参阅第 12 章。另请参阅

With that in mind, a common mistake is to register the DispatcherServletwith a url mapping of /*, returning a view name from a @RequestMappinghandler method, and expecting a JSP to be rendered. For example, consider a handler method like

考虑到这一点,一个常见的错误是DispatcherServlet使用 url 映射注册/*,从@RequestMapping处理程序方法返回视图名称,并期望呈现 JSP。例如,考虑一个处理程序方法,如

@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
    return "example-view-name";
}

with an InternalResourceViewResolver

带着 InternalResourceViewResolver

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

you might expect the request to be forwardedto a JSP resource at the path /WEB-INF/jsps/example-view-name.jsp. This won't happen. Instead, assuming a context name of Example, the DisaptcherServletwill report

您可能希望将请求转发到路径上的 JSP 资源/WEB-INF/jsps/example-view-name.jsp。这不会发生。相反,假设上下文名称为ExampleDisaptcherServlet则将报告

No mapping found for HTTP request with URI [/Example/WEB-INF/jsps/example-view-name.jsp]in DispatcherServletwith name 'dispatcher'

没有映射发现HTTP请求的URI与[/Example/WEB-INF/jsps/example-view-name.jsp]DispatcherServlet名为“调度”

Because the DispatcherServletis mapped to /*and /*matches everything (except exact matches, which have higher priority), the DispatcherServletwould be chosen to handle the forwardfrom the JstlView(returned by the InternalResourceViewResolver). In almost every case, the DispatcherServletwill not be configured to handle such a request.

因为DispatcherServlet映射到/*/*匹配所有内容(精确匹配除外,它们具有更高的优先级),所以DispatcherServlet将选择 来处理forward来自JstlView(由 返回InternalResourceViewResolver)。在几乎所有情况下,DispatcherServlet都不会配置来处理这样的请求

Instead, in this simplistic case, you should register the DispatcherServletto /, marking it as the default servlet. The default servlet is the last match for a request. This will allow your typical servlet container to chose an internal Servlet implementation, mapped to *.jsp, to handle the JSP resource (for example, Tomcat has JspServlet), before trying with the default servlet.

相反,在这种简单的情况下,您应该注册DispatcherServletto /,将其标记为默认 servlet。默认 servlet 是请求的最后一个匹配项。这将允许您的典型 servlet 容器在尝试使用默认 servlet 之前选择映射到 的内部 Servlet 实现*.jsp来处理 JSP 资源(例如,Tomcat 具有JspServlet)。

That's what you're seeing in your example.

这就是您在示例中看到的内容。

回答by Anil N.P

I came across another reason for the same error. This could also be due to the class files not generated for your controller.java file. As a result of which the the dispatcher servlet mentioned in web.xml is unable to map it to the appropriate method in the controller class.

我遇到了同样错误的另一个原因。这也可能是由于没有为您的 controller.java 文件生成类文件。因此,web.xml 中提到的调度程序 servlet 无法将其映射到控制器类中的适当方法。

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

In eclipse under Project->select clean ->Build Project.Do give a check if the class file has been generated for the controller file under builds in your workspace.

在 eclipse 下的 Project->select clean ->Build Project.Do 检查是否已经为您工作区中构建下的控制器文件生成了类文件。

回答by RoutesMaps.com

I resolved my issue when in addition to described before:`

除了之前描述的之外,我解决了我的问题:`

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

added tomcat-embed-jasper:

added tomcat-embed-jasper:

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

` from: JSP file not rendering in Spring Boot web application

` 来自:JSP 文件未在 Spring Boot Web 应用程序中呈现

回答by Acapulco

In my case, I was following the Interceptors Spring documentation for version 5.1.2(while using Spring Boot v2.0.4.RELEASE) and the WebConfigclass had the annotation @EnableWebMvc, which seemed to be conflicting with something else in my application that was preventing my static assets from being resolved correctly (i.e. no CSS or JS files were being returned to the client).

就我而言,我正在关注5.1.2 版Interceptors Spring 文档(同时使用Spring Boot v2.0.4.RELEASE)并且WebConfig该类有注释@EnableWebMvc,这似乎与我的应用程序中阻止我静态资产无法正确解析(即没有将 CSS 或 JS 文件返回给客户端)。

After trying a lot of different things, I tried removingthe @EnableWebMvcand it worked!

在尝试了很多不同的事情之后,我尝试删除@EnableWebMvc并且它起作用了!

Edit: Here's the reference documentationthat says you should remove the @EnableWebMvcannotation

编辑:这是参考文档,说明您应该删除@EnableWebMvc注释

Apparently in my case at least, I'm already configuring my Spring application (although not by using web.xmlor any other static file, it's definitely programmatically), so it was a conflict there.

显然,至少在我的情况下,我已经在配置我的 Spring 应用程序(尽管不是通过使用web.xml或任何其他静态文件,它绝对是通过编程方式),所以那里存在冲突。

回答by Roy

For me, I found that my target classes were generated in a folder pattern not same as source. This is possibly in eclipse I add folders for containing my controllers and not add them as packages. So I ended up defining incorrect path in spring config.

对我来说,我发现我的目标类是在与源不同的文件夹模式中生成的。这可能是在 Eclipse 中,我添加了包含我的控制器的文件夹,而不是将它们添加为包。所以我最终在 spring 配置中定义了错误的路径。

My target class was generating classes under app and I was referring to com.happy.app

我的目标类是在 app 下生成类,我指的是 com.happy.app

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

I added packages (not folders) for com.happy.app and moved the files from folders to packages in eclipse and it resolved the issue.

我为 com.happy.app 添加了包(不是文件夹),并将文件从文件夹移动到 eclipse 中的包,它解决了这个问题。

回答by 2rahulsk

Clean your server. Maybe delete the server and add the project once again and Run.

清理你的服务器。也许删除服务器并再次添加项目并运行。

  1. Stop the Tomcat server

  2. Right click the server and select "Clean"

  3. Right click server again and select "Clean Tomcat Work Directory"

  1. 停止Tomcat服务器

  2. 右键单击服务器并选择“清理”

  3. 再次右键单击服务器并选择“清理Tomcat工作目录”

回答by Steve T

In my case, I was playing around with import of secondary java config files into a main java config file. While making secondary config files, I had changed the name of the main config class, but I had failed to update the name in web.xml. So, every time that I had restarted my tomcat server, I was not seeing mapping handlers noted in the Eclipse IDE console, and when I tried to navigate to my home page I was seeing this error:

就我而言,我正在尝试将辅助 java 配置文件导入主 java 配置文件。在制作辅助配置文件时,我更改了主配置类的名称,但未能更新 web.xml 中的名称。所以,每次我重新启动我的 tomcat 服务器时,我都没有在 Eclipse IDE 控制台中看到映射处理程序,当我尝试导航到我的主页时,我看到了这个错误:

Nov 1, 2019 11:00:01 PM org.springframework.web.servlet.PageNotFound noHandlerFound WARNING: No mapping found for HTTP request with URI [/webapp/home/index] in DispatcherServlet with name 'dispatcher'

2019 年 11 月 1 日下午 11:00:01 org.springframework.web.servlet.PageNotFound noHandlerFound 警告:在 DispatcherServlet 中未找到具有 URI [/webapp/home/index] 的 HTTP 请求的映射,名称为“dispatcher”

The fix was to update the web.xml file so that the old name "WebConfig" would be instead "MainConfig", simply renaming it to reflect the latest name of the main java config file (where "MainConfig" is arbitrary and the words "Web" and "Main" used here are not a syntax requirement). MainConfig was important, because it was the file that did the component scan for "WebController", my spring mvc controller class that handles my web requests.

修复方法是更新 web.xml 文件,以便旧名称“WebConfig”改为“MainConfig”,只需将其重命名以反映主 Java 配置文件的最新名称(其中“MainConfig”是任意的,单词“此处使用的 Web”和“Main”不是语法要求)。MainConfig 很重要,因为它是为“WebController”执行组件扫描的文件,我的 spring mvc 控制器类处理我的 Web 请求。

@ComponentScan(basePackageClasses={WebController.class})

web.xml had this:

web.xml 有这个:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.lionheart.fourthed.config.WebConfig
    </param-value>
</init-param>

web.xml file now has:

web.xml 文件现在有:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.lionheart.fourthed.config.MainConfig
    </param-value>
</init-param>

Now I am seeing the mapping in the console window:

现在我在控制台窗口中看到了映射:

INFO: Mapped "{[/home/index],methods=[GET]}" onto public org.springframework.web.servlet.ModelAndView com.lionheart.fourthed.controller.WebController.gotoIndex()

信息:将“{[/home/index],methods=[GET]}”映射到公共 org.springframework.web.servlet.ModelAndView com.lionheart.fourthed.controller.WebController.gotoIndex()

And my web page is loading again.

我的网页又开始加载了。

回答by Thanis Albert

I had same problem as **No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName**

我有同样的问题 **No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName**

After I analyzed for 2 to 4 days I found out the root cause. Class files was not generated after I run the project. I clicked the project tab.

在我分析了 2 到 4 天后,我找到了根本原因。运行项目后未生成类文件。我单击了项目选项卡。

Project-->CloseProject-->OpenProject-->Clean-->Build project

项目-->关闭项目-->打开项目-->清理-->构建项目

Class files for source code have been generated. It solved my problem. To check whether class files have been generated or not, Please check the Build folder in your project folder.

源代码的类文件已经生成。它解决了我的问题。要检查类文件是否已生成,请检查项目文件夹中的 Build 文件夹。

回答by Mark

Try to amend your code with the following change on your config file. Java config is used instead of application.properties. Do not forget to enable configuration in configureDefaultServletHandlingmethod.

尝试通过对配置文件的以下更改来修改您的代码。使用 Java 配置而不是application.properties. 不要忘记在configureDefaultServletHandling方法中启用配置。

WebMvcConfigurerAdapterclass is deprecated, so we use WebMvcConfigurerinterface.

WebMvcConfigurerAdapter不推荐使用类,所以我们使用WebMvcConfigurer接口。

@Configuration
@EnableWebMvc
@ComponentScan
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

I use gradle, your should have the following dependencies in pom.xml:

我使用 gradle,你应该有以下依赖项pom.xml

dependencies {

    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.0.RELEASE'
    compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.0.35'
}