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


91

我正在编写部署在Tomcat上的Spring MVC应用程序。请参见以下最小,完整和可验证的示例

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期望Spring MVC拥有一个JSP资源,以使用我的控制器来处理请求并转发给JSP,所以为什么它会响应404?


这旨在成为有关此警告消息问题的规范帖子。

Answers:


100

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

DispatcherServlet查看其ApplicationContext(如果有的话)并向其ApplicationContext注册以注册ContextLoaderListener特殊豆,它需要设置其请求服务逻辑。这些bean在文档中进行了描述

可以说是最重要的HandlerMappingmap类型的bean

根据某些条件向处理程序传入的请求以及一系列预处理程序和后处理程序(处理程序拦截器),具体标准因HandlerMapping实现而异。最受欢迎的实现支持带注释的控制器,但也存在其他实现。

javadocHandlerMapping进一步描述了实现必须如何表现。

DispatcherServlet发现这种类型的所有豆类和以某种顺序将它们登记(可定制)。在处理请求时,DispatcherServlet循环遍历这些HandlerMapping对象并对其进行测试,getHandler以找到可以处理传入请求的对象(表示为standard)HttpServletRequest。从4.3.x版本开始,如果找不到任何内容,它将记录您看到的警告

没有找到映射与URI HTTP请求[/some/path]DispatcherServlet使用的名字SomeName

并且要么抛出一个NoHandlerFoundException或立即提交一个404 Not Found状态码的响应。

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

最常见的HandlerMapping实现是RequestMappingHandlerMapping,该实现将@ControllerBean注册为处理程序(实际上是其带@RequestMapping注释的方法)。您可以自己声明这种类型的bean(使用@Bean<bean>或其他机制),也可以使用内置的options。这些是:

  1. 使用注释您的@Configuration班级@EnableWebMvc
  2. <mvc:annotation-driven />在您的XML配置中声明一个成员。

正如上面的链接所描述的,这两个都将注册一个RequestMappingHandlerMappingbean(以及其他一些东西)。但是,如果HandlerMapping没有处理程序,a并不是很有用。RequestMappingHandlerMapping期望有一些@Controllerbean,因此您也需要通过@BeanJava配置中的方法或<bean>XML配置中的声明,或者通过@Controller对任一类中带注释的类的组件扫描来声明它们。确保这些豆存在。

如果您收到警告消息和404,并且已经正确配置了上述所有内容,那么您会将请求发送到错误的URI该错误未由检测到的带@RequestMapping注释的处理程序方法处理。

spring-webmvc库提供了其他内置的HandlerMapping实现。例如,BeanNameUrlHandlerMapping地图

从URL到名称以斜杠(“ /”)开头的bean

而且您总是可以自己编写。显然,您必须确保要发送的请求至少与注册HandlerMapping对象的处理程序之一匹配。

如果您没有隐式或显式注册任何HandlerMappingbean(或detectAllHandlerMappingsis true),则DispatcherServlet注册一些defaults。这些DispatcherServlet.properties在与DispatcherServlet类相同的包中定义。它们是BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping(类似于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配置,请检查您的配置。

其他常见错误

ADispatcherServlet只是典型的Java EE Servlet。你与你的典型进行注册<web.xml> <servlet-class><servlet-mapping>申报,或直接通过ServletContext#addServlet在一个WebApplicationInitializer或与任何机构弹簧开机使用。因此,您必须依赖Servlet规范中指定的url映射逻辑,请参阅第12章。另请参见

考虑到这一点,一个常见的错误是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;
}

您可能希望将请求转发到该路径处的JSP资源/WEB-INF/jsps/example-view-name.jsp。这不会发生。相反,假设上下文名称为ExampleDisaptcherServlet则将报告

没有映射发现HTTP请求的URI与[/Example/WEB-INF/jsps/example-view-name.jsp]DispatcherServlet名为“调度”

由于DispatcherServlet被映射到/*/*匹配的一切(除了精确匹配,其具有更高的优先级),则DispatcherServlet将被选择以处理forward来自JstlView(通过返回InternalResourceViewResolver)。在几乎每种情况下,DispatcherServlet都不会配置来处理此类请求

相反,在这种简单的情况下,您应该将DispatcherServletto注册为/,将其标记为默认servlet。默认servlet是请求的最后一个匹配项。这将允许您的典型servlet容器在尝试使用默认servlet之前,选择一个内部Servlet实现,该实现映射到*.jsp,以处理JSP资源(例如Tomcat具有JspServlet)。

这就是您在示例中看到的。


使用@ EnableWebMvc,dispatcherServlet已注册到/。“您可能希望将请求转发到路径/WEB-INF/jsps/example-view-name.jsp的JSP资源。这不会发生。” 您如何使其工作,以便将其转发到该路径上的JSP资源?基本上这就是问的问题。
Tor

@Tor本身@EnableWebMvc在带@Configuration注释的类上不会执行此操作。它所做的就是将许多默认的Spring MVC处理程序/适配器bean添加到应用程序上下文中。注册DispatcherServlet服务/是一个完全独立的过程,该过程可以通过我在“其他常见错误”部分中介绍的多种方式来完成。我回答您下面引用两段的问题
Sotirios Delimanolis

5

除了上述内容,我还解决了我的问题:

@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>

来自:Spring Boot Web应用程序中未呈现的JSP文件


2

就我而言,我遵循的是Interceptors Spring文档5.1.2版(使用Spring Boot v2.0.4.RELEASE时),并且WebConfig该类具有批注@EnableWebMvc,这似乎与我的应用程序中的其他内容冲突,从而阻止了我的静态操作。资产无法正确解析(即没有CSS或JS文件返回给客户端)。

在尝试了许多不同的操作之后,我尝试删除@EnableWebMvc并且它起作用了!

编辑:这是参考文档,说您应该删除@EnableWebMvc注释

至少就我而言,显然,我已经在配置Spring应用程序(尽管没有使用web.xml任何其他静态文件,但绝对是通过编程方式进行的),因此这是一个冲突。


1

尝试通过对配置文件进行以下更改来修改代码。使用Java config代替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'
}

0

我遇到了另一个导致相同错误的原因。这也可能是由于未为controller.java文件生成的类文件。结果,web.xml中提到的调度程序servlet无法将其映射到控制器类中的适当方法。

@Controller
Class Controller{
@RequestMapping(value="/abc.html")//abc is the requesting page
public void method()
{.....}
}

在Eclipse中的Project->选择clean-> Build Project下。检查工作区中builds下是否为控制器文件生成了类文件。


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中的软件包,它解决了该问题。


0

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

  1. 停止Tomcat服务器

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

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


0

就我而言,我正在尝试将辅助Java配置文件导入到主要Java配置文件中。在制作辅助配置文件时,我已经更改了主配置类的名称,但是未能更新web.xml中的名称。因此,每次重新启动tomcat服务器时,都不会在Eclipse IDE控制台中看到映射处理程序,并且当我尝试导航至主页时,我看到了此错误:

2019年11月1日11:00:01 PM org.springframework.web.servlet.PageNotFound noHandlerFound警告:在DispatcherServlet中找不到名称为'dispatcher'的URI [/ webapp / home / index]的HTTP请求的映射

解决方法是更新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()

而且我的网页正在重新加载。


-1

我有同样的问题 **No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName**

经过2到4天的分析,我找到了根本原因。我运行项目后未生成类文件。我单击了项目选项卡。

项目->关闭项目->打开项目->清理->构建项目

源代码的类文件已生成。它解决了我的问题。要检查是否已生成类文件,请检查项目文件夹中的Build文件夹。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.