为什么Spring MVC用404响应并报告“在DispatcherServlet中找不到带有URI [...]的HTTP请求的映射”?

时间:2017-01-10 19:53:29

标签: java spring spring-mvc servlets

我正在编写一个部署在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?

这是关于此警告消息的问题的规范帖子。

11 个答案:

答案 0 :(得分:82)

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

DispatcherServlet查看其ApplicationContext,如果可用,ApplicationContext注册了ContextLoaderListener特殊bean,需要设置其请求服务逻辑。 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

  

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

either会抛出NoHandlerFoundException或立即使用404 Not Found状态代码提交响应。

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

最常见的HandlerMapping实现是RequestMappingHandlerMapping,它处理@Controller bean作为处理程序(实际上是@RequestMapping注释方法)。您可以自己声明此类型的bean(使用@Bean<bean>或其他机制),也可以使用the built-in options。这些是:

  1. 使用@Configuration
  2. 为您的@EnableWebMvc课程添加注释
  3. 在XML配置中声明<mvc:annotation-driven />成员。
  4. 正如上面的链接所描述的,这两个都将注册一个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(或者如果detectAllHandlerMappingsHandlerMapping),true会注册一些defaults 。这些在DispatcherServlet.propertiesDispatcherServlet类相同的包中定义。它们是DispatcherServletDefaultAnnotationHandlerMapping(与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

    InternalResourceViewResolver

    @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.jspExample将报告

      

    DisaptcherServlet [/Example/WEB-INF/jsps/example-view-name.jsp]中找不到名为&#39;调度程序&#39;

    的URI 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>

` 来自:JSP file not rendering in Spring Boot web application

答案 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)

清洁服务器。也许删除服务器,然后再次添加项目并运行。

  1. 停止Tomcat服务器

  2. 右键单击服务器,然后选择“清理”

  3. 再次右键单击服务器,然后选择“清理Tomcat工作目录”

答案 9 :(得分:-1)

在我的例子中,我已经创建了 Config.java(类)和 config.xml 并且映射是在它们两个中部分完成的。并且由于 config.java 使用 @Configuration annotation ,它被认为是优先级。并且没有考虑 config.xml。 如果有人遇到这样的麻烦,只需删除带有注释的 config.java 并尝试保留 config.xml ,它就可以正常工作。

答案 10 :(得分:-2)

所以问题可以简单到在项目路径中增加一个空格。确保路径中没有空间,我花了很长时间才解决。