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

Why does Spring MVC respond with a 404 and report “No mapping found for HTTP request with URI […] in DispatcherServlet”?

我正在编写一个部署在Tomcat上的SpringMVC应用程序。请参阅以下最小、完整和可验证的示例

1
2
3
4
5
6
7
8
9
10
11
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

1
2
3
4
5
6
7
8
9
10
11
12
@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中。

1
2
3
4
5
6
7
@Controller
public class ExampleController {
    @RequestMapping(path ="/home", method = RequestMethod.GET)
    public String example() {
        return"index";
    }
}

我的应用程序的上下文名称是Example。当我向

1
http://localhost:8080/Example/home

应用程序以HTTP状态404响应,并记录以下内容

1
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资源,我希望SpringMVC使用我的控制器来处理请求并转发到JSP,那么为什么它用404响应呢?

这是关于此警告消息的问题的标准帖子。


您的标准SpringMVC应用程序将通过您在servlet容器中注册的DispatcherServlet来服务所有请求。好的。

DispatcherServlet查看它的ApplicationContext,如果可用,还查看在ContextLoaderListener注册的ApplicationContext对于需要设置其请求服务逻辑的特殊bean。文档中描述了这些bean。好的。

可以说是最重要的,HandlerMapping映射类型的bean好的。

incoming requests to handlers and a list of pre- and post-processors
(handler interceptors) based on some criteria the details of which
vary by HandlerMapping implementation. The most popular implementation
supports annotated controllers but other implementations exists as
well.

Ok.

HandlerMapping的javadoc进一步描述了实现必须如何工作。好的。

DispatcherServlet找到所有这种类型的bean并按某种顺序注册(可以自定义)。在服务请求时,DispatcherServlet循环通过这些HandlerMapping对象,并用getHandler测试每个对象,以找到一个可以处理传入请求的对象,即标准HttpServletRequest。从4.3.x开始,如果找不到,它会记录您看到的警告好的。

No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName

Ok.

或者抛出一个NoHandlerFoundException,或者立即提交一个404未找到状态代码的响应。好的。为什么DispatcherServlet没有找到一个可以处理我请求的HandlerMapping呢?

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

  • @EnableWebMvc注释你的@Configuration类。
  • 在XML配置中声明一个成员。
  • 正如上面的链接所描述的,这两种方法都将注册一个RequestMappingHandlerMappingbean(和一堆其他东西)。但是,如果没有处理程序,HandlerMapping就不是很有用。EDCOX1,16,期望一些EDCOX1,17,bean,所以您也需要声明这些,通过EDCOX1,19个方法在Java配置或EDCOX1,20个声明中的XML配置,或通过组件扫描EDCOX1,17个注释的类。确保这些豆子存在。好的。

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

    spring-webmvc库提供其他内置的HandlerMapping实现。例如,BeanNameUrlHandlerMapping地图好的。< Buff行情>

    从URL到名称以斜杠("/")开头的bean好的。< /块引用>

    你也可以自己写。显然,您必须确保发送的请求至少与注册的HandlerMapping对象的处理程序之一匹配。好的。

    如果您没有隐式或显式注册任何HandlerMappingbean(或者如果detectAllHandlerMappingstruebean),那么DispatcherServlet会注册一些默认值。这些定义在DispatcherServlet.properties中,与DispatcherServlet类位于同一个包中。它们是BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping(与RequestMappingHandlerMapping相似,但已弃用)。好的。调试

    SpringMVC将记录通过RequestMappingHandlerMapping注册的处理程序。例如,类似于@Controller。好的。

    1
    2
    3
    4
    5
    6
    7
    @Controller
    public class ExampleController {
        @RequestMapping(path ="/example", method = RequestMethod.GET, headers ="X-Custom")
        public String example() {
            return"example-view-name";
        }
    }

    将在信息级别记录以下内容好的。

    1
    Mapped"{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()

    这描述了注册的映射。当您看到没有找到处理程序的警告时,请将消息中的URI与此处列出的映射进行比较。@RequestMapping中指定的所有限制必须与弹簧MVC匹配,才能选择处理程序。好的。

    其他HandlerMapping实现会记录它们自己的语句,这些语句应该提示它们的映射和相应的处理程序。好的。

    同样,在调试级别启用Spring日志记录以查看哪些beans Spring寄存器。它应该报告它找到的注释类、它扫描的包以及它初始化的bean。如果您期望的配置不存在,请检查您的ApplicationContext配置。好的。其他常见错误

    一个EDCOX1的4度是一个典型的JavaEE EDCOX1(16)。您可以在典型的声明中注册,也可以直接通过WebApplicationInitializer中的ServletContext#addServlet注册,或者使用弹簧引导使用的任何机制注册。因此,您必须依赖servlet规范中指定的URL映射逻辑,请参见第12章。也见好的。

    • 如何使用web.xml中的servlet URL映射?

    有鉴于此,一个常见的错误是使用/*的URL映射注册DispatcherServlet,从@RequestMapping处理程序方法返回视图名称,并期望呈现JSP。例如,考虑像好的。

    1
    2
    3
    4
    @RequestMapping(path ="/example", method = RequestMethod.GET)
    public String example() {
        return"example-view-name";
    }

    带一个InternalResourceViewResolver。好的。

    1
    2
    3
    4
    5
    6
    7
    @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资源。这不会发生。相反,假设上下文名称为ExampleDisaptcherServlet将报告好的。

    No mapping found for HTTP request with URI [/Example/WEB-INF/jsps/example-view-name.jsp] in DispatcherServlet with name 'dispatcher'

    Ok.

    由于DispatcherServlet映射到/*/*匹配所有内容(精确匹配除外,优先权更高),因此将选择DispatcherServlet处理forwardJstlView返回(由InternalResourceViewResolver返回)。在几乎所有情况下,DispatcherServlet都不会配置为处理这样的请求。好的。

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

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


    除了前面描述的问题外,我还解决了我的问题:`

    1
    2
    3
    4
    5
    6
    7
    @Bean
    public InternalResourceViewResolver resolver() {
        InternalResourceViewResolver vr = new InternalResourceViewResolver();
        vr.setPrefix("/WEB-INF/jsps/");
        vr.setSuffix(".jsp");
        return vr;
    }

    added tomcat-embed-jasper:

    1
    2
    3
    4
    5
    <dependency>
           <groupId>org.apache.tomcat.embed</groupId>
            tomcat-embed-jasper</artifactId>
           <scope>provided</scope>
    </dependency>

    `源:jsp文件未在Spring引导Web应用程序中呈现


    在我的例子中,我遵循5.1.2版的拦截器Spring文档(在使用Spring Boot v2.0.4.release时),并且WebConfig类具有注释@EnableWebMvc,这似乎与我的应用程序中阻止我的静态资产正确解析的其他内容相冲突(即没有CSS或JS文件在返还给客户之前)。

    在尝试了很多不同的事情之后,我尝试移除@EnableWebMvc,但它起作用了!

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

    显然,至少在我的案例中,我已经在配置我的Spring应用程序(虽然不是通过使用web.xml或任何其他静态文件,但它绝对是以编程方式进行的),所以这是一个冲突。


    对于我来说,我发现我的目标类是在一个与源代码不同的文件夹模式中生成的。这可能是在Eclipse中,我添加了包含控制器的文件夹,而不是作为包添加它们。所以我最终在Spring配置中定义了错误的路径。

    我的目标类是在app下生成类,我指的是com.happy.app。

    1
    2
    3
    <context:annotation-config />
    <context:component-scan
        base-package="com.happy.app"></context:component-scan>

    我为com.happy.app添加了包(不是文件夹),并在Eclipse中将文件从文件夹移动到包中,解决了这个问题。


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

    1
    2
    3
    4
    5
    6
    @Controller
    Class Controller{
    @RequestMapping(value="/abc.html")//abc is the requesting page
    public void method()
    {.....}
    }

    在Eclipse的project->clean->build project下,检查是否为工作区builds下的控制器文件生成了类文件。


    清理服务器。可能删除服务器并再次添加项目并运行。

  • 停止Tomcat服务器

  • 右键单击服务器并选择"清理"

  • 再次右键单击服务器并选择"清理Tomcat工作目录"