我正在编写部署在Tomcat上的Spring MVC应用程序。请参阅以下minimal, complete, and verifiable example
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;
}
}
最后,我在包
@Controller
中有一个com.example.controllers
@Controller
public class ExampleController {
@RequestMapping(path = "/home", method = RequestMethod.GET)
public String example() {
return "index";
}
}
我的应用程序的上下文名称为
Example
。当我发送请求给http://localhost:8080/Example/home
该应用程序以HTTP Status 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响应?这旨在成为有关此警告消息问题的规范帖子。
最佳答案
您的标准Spring MVC应用程序将通过您在Servlet容器中注册的DispatcherServlet
满足所有请求。DispatcherServlet
会查看其ApplicationContext
,如果有的话,还会向ApplicationContext
注册以查找特殊bean的ContextLoaderListener
,它需要设置其请求服务逻辑。 These beans are described in the documentation。
可以说是最重要的HandlerMapping
类型的bean
向处理程序的传入请求以及预处理程序和后处理程序的列表
(处理程序拦截器)基于某些标准
因HandlerMapping
实现而异。最受欢迎的实施
支持带注释的控制器,但存在其他实现
好。
javadoc of HandlerMapping
进一步描述了实现必须如何表现。DispatcherServlet
查找所有此类型的bean,并按一定顺序注册它们(可以自定义)。在处理请求时,DispatcherServlet
循环遍历这些HandlerMapping
对象,并使用getHandler
测试它们中的每个对象,以找到可以处理传入请求的对象,以标准HttpServletRequest
表示。从4.3.x版本开始,如果找不到任何内容,则会显示logs the warning
在名称为SomeName的[/some/path]
中找不到URI为DispatcherServlet
的HTTP请求的映射
并且either抛出NoHandlerFoundException
或立即使用404 Not Found状态代码提交响应。DispatcherServlet
为什么没有找到可以处理我的请求的HandlerMapping
?
最常见的HandlerMapping
实现是RequestMappingHandlerMapping
,该实现将@Controller
bean注册为处理程序(实际上是其@RequestMapping
注释的方法)。您可以自己声明这种类型的bean(使用@Bean
或<bean>
或其他机制),也可以使用the built-in options。这些是:
用@Configuration
注释@EnableWebMvc
类。
在您的XML配置中声明一个<mvc:annotation-driven />
成员。
正如上面的链接所描述的,这两个都将注册一个RequestMappingHandlerMapping
bean(以及其他一些东西)。但是,没有处理程序的HandlerMapping
不是很有用。 RequestMappingHandlerMapping
需要一些@Controller
bean,因此您也需要通过Java配置中的@Bean
方法或XML配置中的<bean>
声明,或者通过对其中任一带有@Controller
注释的类的组件扫描来声明它们。确保这些豆存在。
如果您收到警告消息和404,并且已经正确配置了上述所有内容,那么您会将请求发送到错误的URI,而该URI未被检测到的带有@RequestMapping
注释的处理程序方法处理。spring-webmvc
库提供了其他内置的HandlerMapping
实现。例如,BeanNameUrlHandlerMapping
映射
从URL到名称以斜杠(“ /”)开头的bean
而且您总是可以自己编写。显然,您必须确保要发送的请求至少与已注册的HandlerMapping
对象的处理程序之一匹配。
如果您没有隐式或显式注册任何HandlerMapping
bean(或者如果detectAllHandlerMappings
是true
),则DispatcherServlet
注册一些defaults。这些在DispatcherServlet.properties
中与DispatcherServlet
类放在同一包中定义。它们是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 boot使用的任何机制来注册它。因此,您必须依赖Servlet specification中指定的url映射逻辑,请参见第12章。另请参见How are Servlet url mappings in web.xml used?
考虑到这一点,一个常见的错误是使用
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”的
[/Example/WEB-INF/jsps/example-view-name.jsp]
中找不到URI为DispatcherServlet
的HTTP请求的映射由于
DispatcherServlet
映射到/*
并且/*
匹配所有内容(精确匹配除外,它们具有更高的优先级),因此将选择DispatcherServlet
来处理forward
中的JstlView
(由InternalResourceViewResolver
)。在几乎每种情况下,DispatcherServlet
都不会配置为处理此类请求。相反,在这种简单的情况下,应将
DispatcherServlet
注册到/
,将其标记为默认servlet。默认servlet是请求的最后一个匹配项。这将允许您的典型Servlet容器在尝试使用默认Servlet之前,选择一个内部Servlet实现(映射到*.jsp
)来处理JSP资源(例如,Tomcat具有JspServlet
)。这就是您在示例中看到的。
关于java - 为什么Spring MVC会以404响应并报告“在DispatcherServlet中未找到带有URI […]的HTTP请求的映射”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35357742/