我正在编写一个部署在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?
这是关于此警告消息的问题的规范帖子。
答案 0 :(得分:82)
您的标准Spring MVC应用程序将通过您在Servlet容器中注册的DispatcherServlet
来处理所有请求。
DispatcherServlet
查看其ApplicationContext
,如果可用,ApplicationContext
注册了ContextLoaderListener
特殊bean,需要设置其请求服务逻辑。 These beans are described in the documentation
可以说是最重要的HandlerMapping
地图
对处理程序的传入请求以及预处理器和后处理器列表 (处理程序拦截器)基于某些标准的详细信息 因
HandlerMapping
实施而异。最流行的实现 支持带注释的控制器,但其他实现存在 好。
javadoc of HandlerMapping
进一步描述了实现必须如何表现。
DispatcherServlet
找到此类型的所有bean并按某种顺序注册它们(可以自定义)。在提供请求时,DispatcherServlet
会循环遍历这些HandlerMapping
个对象,并使用getHandler
对每个对象进行测试,以找到可以处理传入请求的对象,表示为标准HttpServletRequest
。从4.3.x开始,如果找不到任何,则会看到logs the warning
[/some/path]
中名为SomeName的URIDispatcherServlet
的HTTP请求找不到映射
和either会抛出NoHandlerFoundException
或立即使用404 Not Found状态代码提交响应。
DispatcherServlet
找不到可以处理我请求的HandlerMapping
?最常见的HandlerMapping
实现是RequestMappingHandlerMapping
,它处理@Controller
bean作为处理程序(实际上是@RequestMapping
注释方法)。您可以自己声明此类型的bean(使用@Bean
或<bean>
或其他机制),也可以使用the built-in options。这些是:
@Configuration
。@EnableWebMvc
课程添加注释
<mvc:annotation-driven />
成员。正如上面的链接所描述的,这两个都将注册一个RequestMappingHandlerMapping
bean(以及其他一些东西)。但是,HandlerMapping
在没有处理程序的情况下非常有用。 RequestMappingHandlerMapping
需要一些@Controller
bean,因此您需要通过Java配置中的@Bean
方法或XML配置中的<bean>
声明或{{{{}的组件扫描来声明这些bean。 1}}两个带注释的类。 确保这些bean存在。
如果您收到了警告消息和404,并且您已正确配置了上述所有内容,则会将您的请求发送到错误的URI ,一个未被检测到的@Controller
带注释的处理程序方法处理的。
@RequestMapping
库提供了其他内置spring-webmvc
实现。例如,BeanNameUrlHandlerMapping
地图
从URL到名称以斜杠开头的bean(&#34; /&#34;)
你可以随时自己写。显然,您必须确保您发送的请求与至少一个已注册的HandlerMapping
对象的处理程序匹配。
如果您没有隐式或明确地注册任何HandlerMapping
bean(或者如果detectAllHandlerMappings
为HandlerMapping
),true
会注册一些defaults 。这些在DispatcherServlet.properties
与DispatcherServlet
类相同的包中定义。它们是DispatcherServlet
和DefaultAnnotationHandlerMapping
(与BeanNameUrlHandlerMapping
类似,但已弃用)。
Spring MVC将记录通过RequestMappingHandlerMapping
注册的处理程序。例如,RequestMappingHandlerMapping
喜欢
@Controller
将在INFO级别记录以下内容
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
这描述了已注册的映射。当您看到没有找到处理程序的警告时,请将消息中的URI与此处列出的映射进行比较。 @RequestMapping
中指定的所有限制必须与Spring MVC匹配才能选择处理程序。
其他Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
实现会记录他们自己的语句,这些语句应该提示他们的映射及其相应的处理程序。
同样,在DEBUG级别启用Spring日志记录以查看Spring注册的bean。它应该报告它找到哪些带注释的类,它扫描哪些包,以及它初始化的bean。如果您预期的不存在,请查看您的HandlerMapping
配置。
ApplicationContext
只是典型的Java EE Servlet
。您可以使用典型的DispatcherServlet
<web.xml>
和<servlet-class>
声明进行注册,也可以直接通过ServletContext#addServlet
中的WebApplicationInitializer
或Spring引导使用的任何机制进行注册。因此,您必须依赖Servlet specification中指定的 url mapping 逻辑,请参阅第12章。另请参阅
考虑到这一点,一个常见的错误是使用<servlet-mapping>
的url映射注册DispatcherServlet
,从/*
处理程序方法返回视图名称,并期望JSP到被渲染。例如,考虑像
@RequestMapping
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
您可能希望请求forwarded到路径@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
的JSP资源。这不会发生。相反,假设上下文名称为/WEB-INF/jsps/example-view-name.jsp
,Example
将报告
在
的URIDisaptcherServlet
[/Example/WEB-INF/jsps/example-view-name.jsp]
中找不到名为&#39;调度程序&#39;DispatcherServlet
的HTTP请求的映射
由于DispatcherServlet
已映射到/*
且/*
与所有内容匹配(完全匹配,优先级较高),因此会选择DispatcherServlet
来处理forward
来自JstlView
的{1}}(由InternalResourceViewResolver
返回)。 几乎在所有情况下,DispatcherServlet
都不会配置为处理此类请求。
相反,在这种简单的情况下,您应该将DispatcherServlet
注册到/
,将其标记为默认的servlet。默认servlet是请求的最后一个匹配项。这将允许您的典型servlet容器在尝试使用默认servlet之前选择映射到*.jsp
的内部Servlet实现来处理JSP资源(例如,Tomcat具有JspServlet
)。
这就是你在例子中看到的内容。
答案 1 :(得分:3)
除了之前描述的内容之外,我解决了我的问题:`
@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>
答案 2 :(得分:2)
就我而言,我遵循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
或任何其他静态文件,但肯定是通过编程方式进行的),因此在那里存在冲突。
答案 3 :(得分:1)
尝试通过对配置文件进行以下更改来修改代码。使用Java配置而不是application.properties
。
不要忘记以configureDefaultServletHandling
方法启用配置。
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();
}
}
我使用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'
}
答案 4 :(得分:0)
我遇到了同样错误的另一个原因。这也可能是由于没有为controller.java文件生成类文件。因此,web.xml中提到的调度程序servlet无法将其映射到控制器类中的相应方法。
@Controller
Class Controller{
@RequestMapping(value="/abc.html")//abc is the requesting page
public void method()
{.....}
}
在Project下的eclipse-&gt;选择clean - &gt; Build Project.Do检查是否已在工作区中的构建下为控制器文件生成类文件。
答案 5 :(得分:0)
对我来说,我发现我的目标类是通过与源文件不同的文件夹模式生成的。这可能是在Eclipse中,我添加了用于包含控制器的文件夹,而不是将它们添加为软件包。因此,我最终在spring config中定义了错误的路径。
我的目标类是在app下生成类,我指的是com.happy.app
<context:annotation-config />
<context:component-scan
base-package="com.happy.app"></context:component-scan>
我为com.happy.app添加了软件包(不是文件夹),并将文件从文件夹移到了eclipse中的软件包,这解决了问题。
答案 6 :(得分:0)
就我而言,我正在尝试将辅助Java配置文件导入到主要Java配置文件中。在制作辅助配置文件时,我已经更改了主要配置类的名称,但是未能更新web.xml中的名称。因此,每次重新启动tomcat服务器时,都不会在Eclipse IDE控制台中看到映射处理程序,并且当我尝试导航至主页时,我看到此错误:
2019年11月1日11:00:01 org.springframework.web.servlet.PageNotFound noHandlerFound警告:找不到带有URI的HTTP请求的映射 [/ webapp / home / index]在DispatcherServlet中,名称为“ dispatcher”
修复程序是更新web.xml文件,以便将旧名称“ WebConfig”改为“ MainConfig”,只需将其重命名以反映主Java配置文件的最新名称(其中“ MainConfig”是任意的,这里使用的“ Web”和“ Main”一词不是语法要求。 MainConfig很重要,因为它是对组件进行扫描以处理“ WebController”的文件,该文件是处理我的Web请求的spring mvc控制器类。
@ComponentScan(basePackageClasses={WebController.class})
web.xml具有此功能:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.lionheart.fourthed.config.WebConfig
</param-value>
</init-param>
web.xml文件现在具有:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.lionheart.fourthed.config.MainConfig
</param-value>
</init-param>
现在我在控制台窗口中看到映射:
INFO:将“ {[/ home / index],methods = [GET]}”映射到公共 org.springframework.web.servlet.ModelAndView com.lionheart.fourthed.controller.WebController.gotoIndex()
然后我的网页再次加载。
答案 7 :(得分:0)
我和**No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName**
分析2至4天后,我找到了根本原因。我运行项目后未生成类文件。我单击了项目选项卡。
Project-> CloseProject-> OpenProject-> Clean-> Build project
已生成源代码的类文件。它解决了我的问题。要检查是否已生成类文件,请检查项目文件夹中的Build文件夹。
答案 8 :(得分:-1)
清洁服务器。也许删除服务器,然后再次添加项目并运行。
停止Tomcat服务器
右键单击服务器,然后选择“清理”
再次右键单击服务器,然后选择“清理Tomcat工作目录”
答案 9 :(得分:-1)
在我的例子中,我已经创建了 Config.java(类)和 config.xml 并且映射是在它们两个中部分完成的。并且由于 config.java 使用 @Configuration annotation ,它被认为是优先级。并且没有考虑 config.xml。 如果有人遇到这样的麻烦,只需删除带有注释的 config.java 并尝试保留 config.xml ,它就可以正常工作。
答案 10 :(得分:-2)
所以问题可以简单到在项目路径中增加一个空格。确保路径中没有空间,我花了很长时间才解决。