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
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
提问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 SpringServletConfig
is
哪里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 @Controller
in 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.jsp
I 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 DispatcherServlet
that you've registered with your Servlet container.
您的标准 Spring MVC 应用程序将通过DispatcherServlet
您在 Servlet 容器中注册的一个来处理所有请求。
The DispatcherServlet
looks at its ApplicationContext
and, if available, the ApplicationContext
registered with a ContextLoaderListener
for 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 HandlerMapping
map
可以说是最重要的,类型为HandlerMapping
map 的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
HandlerMapping
implementation. The most popular implementation supports annotated controllers but other implementations exists as well.
对处理程序的传入请求以及基于某些标准的预处理器和后处理器(处理程序拦截器)列表,其细节因
HandlerMapping
实现而异。最流行的实现支持带注释的控制器,但也存在其他实现。
The javadoc of HandlerMapping
further describes how implementations must behave.
的javadocHandlerMapping
进一步描述了实现必须如何表现。
The DispatcherServlet
finds all beans of this type and registers them in some order (can be customized). While serving a request, the DispatcherServlet
loops through these HandlerMapping
objects and tests each of them with getHandler
to 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]
inDispatcherServlet
with name SomeName
没有找到映射与URI HTTP请求
[/some/path]
中DispatcherServlet
使用的名字SomeName
and eitherthrows a NoHandlerFoundException
or immediately commits the response with a 404 Not Found status code.
并且要么抛出一个NoHandlerFoundException
或立即提交一个404 Not Found状态码的响应。
Why didn't the DispatcherServlet
find a HandlerMapping
that could handle my request?
为什么没有DispatcherServlet
找到HandlerMapping
可以处理我的请求?
The most common HandlerMapping
implementation is RequestMappingHandlerMapping
, which handles registering @Controller
beans as handlers (really their @RequestMapping
annotated methods). You can either declare a bean of this type yourself (with @Bean
or <bean>
or other mechanism) or you can use the built-in options. These are:
最常见的HandlerMapping
实现是RequestMappingHandlerMapping
,它将注册@Controller
bean 处理为处理程序(实际上是它们的@RequestMapping
注释方法)。您可以自己声明这种类型的 bean(使用@Bean
或<bean>
或其他机制),也可以使用内置 options。这些是:
- Annotate your
@Configuration
class with@EnableWebMvc
. - Declare a
<mvc:annotation-driven />
member in your XML configuration.
- 注释你的
@Configuration
带班@EnableWebMvc
。 <mvc:annotation-driven />
在您的 XML 配置中声明一个成员。
As the link above describes, both of these will register a RequestMappingHandlerMapping
bean (and a bunch of other stuff). However, a HandlerMapping
isn't very useful without a handler. RequestMappingHandlerMapping
expects some @Controller
beans so you need to declare those too, through @Bean
methods in a Java configuration or <bean>
declarations in an XML configuration or through component scanning of @Controller
annotated classes in either. Make sure these beans are present.
正如上面的链接所描述的,这两个都将注册一个RequestMappingHandlerMapping
bean(和一堆其他东西)。但是,如果HandlerMapping
没有处理程序,a不是很有用。RequestMappingHandlerMapping
需要一些@Controller
bean,因此您也需要声明这些 bean,通过@Bean
Java 配置中的方法或<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 @RequestMapping
annotated handler method.
如果您收到警告消息和 404 并且您已正确配置以上所有内容,那么您将请求发送到错误的 URI,该请求未由检测到的带@RequestMapping
注释的处理程序方法处理。
The spring-webmvc
library offers other built-in HandlerMapping
implementations. For example, BeanNameUrlHandlerMapping
maps
该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 HandlerMapping
object's handlers.
而且你总是可以自己写。显然,您必须确保您发送的请求至少与已注册HandlerMapping
对象的处理程序之一匹配。
If you don't implicitly or explicitly register any HandlerMapping
beans (or if detectAllHandlerMappings
is true
), the DispatcherServlet
registers some defaults. These are defined in DispatcherServlet.properties
in the same package as the DispatcherServlet
class. They are BeanNameUrlHandlerMapping
and DefaultAnnotationHandlerMapping
(which is similar to RequestMappingHandlerMapping
but deprecated).
如果您不隐式或显式注册任何HandlerMapping
bean(或者如果detectAllHandlerMappings
是true
),则会DispatcherServlet
注册一些默认值。这些定义在DispatcherServlet.properties
与DispatcherServlet
类相同的包中。它们是BeanNameUrlHandlerMapping
和DefaultAnnotationHandlerMapping
(类似于RequestMappingHandlerMapping
但已弃用)。
Debugging
调试
Spring MVC will log handlers registered through RequestMappingHandlerMapping
. For example, a @Controller
like
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 @RequestMapping
must match for Spring MVC to select the handler.
这描述了注册的映射。当您看到未找到处理程序的警告时,请将消息中的 URI 与此处列出的映射进行比较。@RequestMapping
必须匹配 Spring MVC 中指定的所有限制才能选择处理程序。
Other HandlerMapping
implementations 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 ApplicationContext
configuration.
同样,在 DEBUG 级别启用 Spring 日志记录以查看 Spring 注册了哪些 bean。它应该报告它找到了哪些带注释的类,它扫描了哪些包,以及它初始化了哪些 bean。如果您期望的那些不存在,请检查您的ApplicationContext
配置。
Other common mistakes
其他常见错误
A DispatcherServlet
is just a typical Java EE Servlet
. You register it with your typical <web.xml>
<servlet-class>
and <servlet-mapping>
declaration, or directly through ServletContext#addServlet
in 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#addServlet
a WebApplicationInitializer
,或者使用 Spring boot 使用的任何机制。因此,您必须依赖Servlet 规范中指定的url 映射逻辑,请参阅第 12 章。另请参阅
With that in mind, a common mistake is to register the DispatcherServlet
with a url mapping of /*
, returning a view name from a @RequestMapping
handler 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 DisaptcherServlet
will report
您可能希望将请求转发到路径上的 JSP 资源/WEB-INF/jsps/example-view-name.jsp
。这不会发生。相反,假设上下文名称为Example
,DisaptcherServlet
则将报告
No mapping found for HTTP request with URI
[/Example/WEB-INF/jsps/example-view-name.jsp]
inDispatcherServlet
with name 'dispatcher'
没有映射发现HTTP请求的URI与
[/Example/WEB-INF/jsps/example-view-name.jsp]
在DispatcherServlet
名为“调度”
Because the DispatcherServlet
is mapped to /*
and /*
matches everything (except exact matches, which have higher priority), the DispatcherServlet
would be chosen to handle the forward
from the JstlView
(returned by the InternalResourceViewResolver
). In almost every case, the DispatcherServlet
will not be configured to handle such a request.
因为DispatcherServlet
映射到/*
并/*
匹配所有内容(精确匹配除外,它们具有更高的优先级),所以DispatcherServlet
将选择 来处理forward
来自JstlView
(由 返回InternalResourceViewResolver
)。在几乎所有情况下,DispatcherServlet
都不会配置来处理这样的请求。
Instead, in this simplistic case, you should register the DispatcherServlet
to /
, 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.
相反,在这种简单的情况下,您应该注册DispatcherServlet
to /
,将其标记为默认 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
回答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 WebConfig
class 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 @EnableWebMvc
and it worked!
在尝试了很多不同的事情之后,我尝试删除它@EnableWebMvc
并且它起作用了!
Edit: Here's the reference documentationthat says you should remove the @EnableWebMvc
annotation
编辑:这是参考文档,说明您应该删除@EnableWebMvc
注释
Apparently in my case at least, I'm already configuring my Spring application (although not by using web.xml
or 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.
清理你的服务器。也许删除服务器并再次添加项目并运行。
Stop the Tomcat server
Right click the server and select "Clean"
Right click server again and select "Clean Tomcat Work Directory"
停止Tomcat服务器
右键单击服务器并选择“清理”
再次右键单击服务器并选择“清理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 configureDefaultServletHandling
method.
尝试通过对配置文件的以下更改来修改您的代码。使用 Java 配置而不是application.properties
. 不要忘记在configureDefaultServletHandling
方法中启用配置。
WebMvcConfigurerAdapter
class is deprecated, so we useWebMvcConfigurer
interface.
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'
}