我正在编写一个部署在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状态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呢?
对于有关此警告消息的问题,这是一个规范的帖子 .
6 回答
您的标准Spring MVC应用程序将通过您在Servlet容器中注册的DispatcherServlet来处理所有请求 .
DispatcherServlet
查看其ApplicationContext
,如果可用的话ApplicationContext
注册了ContextLoaderListener
特殊bean,它需要设置其请求服务逻辑 . These beans are described in the documentation .可以说是最重要的,HandlerMapping类型的bean
javadoc of HandlerMapping进一步描述了实现必须如何表现 .
DispatcherServlet
找到此类型的所有bean并按某种顺序注册它们(可以自定义) . 在提供请求时,DispatcherServlet
循环遍历这些HandlerMapping
对象并使用getHandler测试每个对象,以找到可以处理传入请求的对象,表示为标准HttpServletRequest
. 从4.3.x, if it doesn't find any 开始,你看到logs the warning并且either抛出NoHandlerFoundException或立即使用404 Not Found状态代码提交响应 .
为什么DispatcherServlet没有找到可以处理我的请求的HandlerMapping?
最常见的
HandlerMapping
实现是RequestMappingHandlerMapping,它处理@Controller
bean作为处理程序(实际上是@RequestMapping
注释方法) . 您可以自己声明这种类型的bean(使用@Bean
或<bean>
或其他机制),也可以使用the built-in options . 这些是:使用
@EnableWebMvc
注释@Configuration
类 .在XML配置中声明
<mvc:annotation-driven />
成员 .正如上面的链接描述的那样,这两个都将注册一个
RequestMappingHandlerMapping
bean(以及其他一些东西) . 但是,没有处理程序,HandlerMapping
不是很有用 .RequestMappingHandlerMapping
需要一些@Controller
bean,因此您需要通过Java配置中的@Bean
方法或XML配置中的<bean>
声明或通过组件扫描@Controller
注释类来声明这些bean . Make sure these beans are present.如果您正确配置了上述所有内容, then you're sending your request to the wrong URI ,一个未被检测到的
@RequestMapping
带注释的处理程序方法处理的那个 .spring-webmvc
库提供其他内置HandlerMapping
实现 . 例如,BeanNameUrlHandlerMapping Map而你总是可以自己写 . 显然, you'll have to make sure the request you're sending matches at least one of the registered HandlerMapping object's handlers.
如果您没有隐式或显式注册任何
HandlerMapping
bean(或detectAllHandlerMappings是true
),DispatcherServlet
会注册defaults . 这些在DispatcherServlet.properties中定义在与DispatcherServlet
类相同的包中 . 它们是BeanNameUrlHandlerMapping
和DefaultAnnotationHandlerMapping(类似于RequestMappingHandlerMapping
但已弃用) .调试
Spring MVC将记录通过
RequestMappingHandlerMapping
注册的处理程序 . 例如,@Controller
之类的将在INFO级别记录以下内容
这描述了已注册的映射 . 当您看到没有找到处理程序的警告时,请将消息中的URI与此处列出的映射进行比较 . @RequestMapping中指定的所有限制必须与Spring MVC匹配才能选择处理程序 .
其他
HandlerMapping
实现会记录他们自己的语句,这些语句应该提示他们的映射及其相应的处理程序 .类似地,在DEBUG级别启用Spring日志记录以查看Spring注册的bean . 它应该报告它找到哪些带注释的类,它扫描哪些包,以及它初始化的bean . 如果您预期的那些不存在,然后查看您的
ApplicationContext
配置 .其他常见错误
DispatcherServlet
只是一个典型的Java EE Servlet . 您可以使用典型的<web.xml>
<servlet-class>
和<servlet-mapping>
声明进行注册,也可以直接通过WebApplicationInitializer中的ServletContext#addServlet或Spring引导使用的任何机制进行注册 . 因此,您必须依赖Servlet specification中指定的url映射逻辑,请参阅第12章 . 另请参阅考虑到这一点,一个常见的错误是使用
/*
的url映射注册DispatcherServlet
,从@RequestMapping
处理程序方法返回视图名称,并期望呈现JSP . 例如,考虑一个像这样的处理程序方法用InternalResourceViewResolver
您可能希望请求在路径
/WEB-INF/jsps/example-view-name.jsp
处的JSP资源forwarded . 这不会发生 . 相反,假设上下文名称为Example
,DisaptcherServlet
将报告因为
DispatcherServlet
映射到/*
并且/*
匹配所有内容(具有更高优先级的完全匹配除外),DispatcherServlet
将被选择用于处理JstlViewforward
(由InternalResourceViewResolver
返回) . In almost every case, the DispatcherServlet will not be configured to handle such a request .相反,在这种简单的情况下,您应该将
DispatcherServlet
注册为/
,将其标记为默认servlet . 默认servlet是请求的最后一个匹配项 . 这将允许您的典型servlet容器在尝试使用默认servlet之前选择映射到*.jsp
的内部Servlet实现来处理JSP资源(例如,Tomcat具有JspServlet) .这就是你在你的例子中看到的 .
除了之前描述之外,我解决了我的问题:`
added tomcat-embed-jasper:
`from:JSP file not rendering in Spring Boot web application
我遇到了同样错误的另一个原因 . 这也可能是由于没有为controller.java文件生成类文件 . 因此,web.xml中提到的调度程序servlet无法将其映射到控制器类中的相应方法 .
在Project中的eclipse - > select clean - > Build Project.Do检查是否已在工作区中的构建下为控制器文件生成类文件 .
在我的情况下,我跟随Interceptors Spring documentation for version 5.1.2(使用 Spring Boot v2.0.4.RELEASE 时)和
WebConfig
类有注释@EnableWebMvc
,这似乎与我的应用程序中的其他东西冲突,这阻止了我的静态资产被正确解析(即没有CSS或JS文件被返回给客户端) .在尝试了很多不同的东西之后,我尝试删除
@EnableWebMvc
并且它有效!编辑:Here's the reference documentation表示你应该删除
@EnableWebMvc
注释显然至少在我的情况下,我已经在配置我的Spring应用程序了(虽然不是使用
web.xml
或任何其他静态文件,但它绝对是以编程方式),所以这是一个冲突 .对我来说,我发现我的目标类是在与源不同的文件夹模式中生成的 . 这可能是在eclipse中我添加用于包含我的控制器的文件夹而不是将它们添加为包 . 所以我最终在spring配置中定义了错误的路径 .
我的目标类是在app下生成类,我指的是com.happy.app
我为com.happy.app添加了包(不是文件夹),并将文件从文件夹移动到eclipse中的包,它解决了这个问题 .
清理您的服务器 . 也许删除服务器并再次添加项目并运行 .
停止Tomcat服务器
右键单击服务器并选择“清除”
再次右键单击服务器并选择“清除Tomcat工作目录”