为什么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
对象,并使用getHandler
testing每个对象,以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,也可以使用内置选项 。 这些是:
- 使用
@EnableWebMvc
注释您的@Configuration
类。 - 在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(或者detectAllHandlerMappings
为true
),则DispatcherServlet
注册一些默认值 。 这些在与DispatcherServlet
类相同的包中的DispatcherServlet
中定义。 它们是BeanNameUrlHandlerMapping
和DefaultAnnotationHandlerMapping
(与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。 如果你所期望的不存在,那么检查你的ApplicationContext
configuration。
其他常见的错误
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的控制器文件的类文件。