为什么Spring MVC用404响应,并报告“在DispatcherServlet中没有find具有URI的HTTP请求的映射”?

我正在编写一个部署在Tomcat上的Spring MVC应用程序。 请参阅以下最小,完整且可validation的示例 :

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并logging下列内容

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

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


这是一个关于这个警告信息的问题的标准post。

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

DispatcherServlet查看它的ApplicationContext ,如果可用的话,查看ApplicationContext注册到一个ContextLoaderListener的特殊bean,它需要设置它的请求服务逻辑。 这些bean在文档中描述 。

可以说是最重要的,types为HandlerMapping bean的映射

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

HandlerMapping的javadoc进一步描述了实现的行为。

DispatcherServlet查找所有这种types的bean,并以某种顺序注册它们(可以自定义)。 在提供请求时, DispatcherServlet遍历这些HandlerMapping对象,并使用getHandlertesting每个对象,以find可处理传入请求的对象,并将其表示为标准的HttpServletRequest 。 从4.3.x开始, 如果没有find ,它会logging你看到的警告

在名为SomeName的DispatcherServlet找不到具有URI [/some/path] HTTP请求的映射

并引发NoHandlerFoundException或立即提交404 Not Found状态代码的响应。

为什么DispatcherServlet找不到可以处理我的请求的HandlerMapping

最常见的HandlerMapping实现是RequestMappingHandlerMapping ,它处理注册@Controller bean作为处理程序(的确是它们的@RequestMapping注释方法)。 您可以自己(使用@Bean<bean>或其他机制)声明此types的bean,也可以使用内置选项 。 这些是:

  1. 使用@EnableWebMvc注释您的@Configuration类。
  2. 在XMLconfiguration中声明一个<mvc:annotation-driven />成员。

正如上面的链接所描述的,这两个都会注册一个RequestMappingHandlerMapping bean(以及其他一些东西)。 但是,如果没有处理程序, HandlerMapping不是很有用。 RequestMappingHandlerMapping需要一些@Controller bean,所以你也需要通过Javaconfiguration中的@Bean方法或者XMLconfiguration中的<bean>声明或者通过@Controller注释类的组件扫描来声明这些<bean>确保这些豆存在。

如果您收到警告消息和404,并且已经正确configuration了上述所有内容, 那么您将请求发送给错误的URI ,而不是由检测到的@RequestMapping注释处理程序方法处理。

spring-webmvc库提供了其他内置的HandlerMapping实现。 例如, BeanNameUrlHandlerMapping映射

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

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

如果您没有显式注册任何HandlerMapping bean(或者detectAllHandlerMappingstrue ),则DispatcherServlet注册一些默认值 。 这些在与DispatcherServlet类相同的包中的DispatcherServlet中定义。 它们是BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping (与RequestMappingHandlerMapping类似,但不赞成使用)。

debugging

Spring MVC将logging通过RequestMappingHandlerMapping注册的处理程序。 例如,一个@Controller

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

将在INFO级别logging以下内容

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

这描述了注册的映射。 当看到没有find处理程序的警告时,将消息中的URI与此处列出的映射进行比较。 所有在@RequestMapping指定的限制都必须匹配Spring MVC来select处理程序。

其他HandlerMapping实现logging他们自己的语句,这些语句应该暗示它们的映射及其相应的处理程序。

同样,在DEBUG级别启用Spring日志logging来查看Spring注册的bean。 它应该报告find哪些注释类,它扫描哪个包,以及它初始化哪些bean。 如果你所期望的不存在,那么检查你的ApplicationContextconfiguration。

其他常见的错误

DispatcherServlet只是一个典型的Java EE Servlet 。 您可以使用典型的<web.xml> <servlet-class><servlet-mapping>声明,或直接通过WebApplicationInitializer ServletContext#addServlet ,或者使用Spring启动使用的任何机制。 因此,您必须依靠Servlet规范中指定的url映射逻辑,参见第12章。另请参见

  • 如何使用web.xml中的Servlet URL映射?

考虑到这一点,一个常见的错误是将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; } 

您可能希望将请求转发到path为/WEB-INF/jsps/example-view-name.jsp的JSP资源。 这不会发生。 相反,假设一个上下文名称为Example ,那么DisaptcherServlet将会报告

在名为“dispatcher”的DispatcherServlet找不到具有URI的HTTP请求的映射[/Example/WEB-INF/jsps/example-view-name.jsp]

由于DispatcherServlet映射到/*/*匹配所有内容(除了具有更高优先级的精确匹配外),因此将selectDispatcherServlet来处理由JstlView (由InternalResourceViewResolver返回)的forward几乎在任何情况下, DispatcherServlet都不会被configuration为处理这样​​的请求

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

这就是你所看到的例子。

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

 @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> 

来自: JSP文件不在Spring Boot web应用程序中呈现

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

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

在Eclipse下的Project-> select clean – > Build Project.Do检查是否生成了在你的工作空间下构build的控制器文件的类文件。