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

新手上路,请多包涵

我正在编写部署在 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 状态 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 响应?


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

原文由 Sotirios Delimanolis 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 865
2 个回答

您的标准 Spring MVC 应用程序将通过 DispatcherServlet 为所有请求提供服务,您已在 Servlet 容器中注册。

The DispatcherServlet looks at its ApplicationContext and, if available, the ApplicationContext registered with a ContextLoaderListener for special beans it needs to setup its request服务逻辑。 这些 bean 在文档中进行了描述

可以说是最重要的,类型为 HandlerMapping map 的 beans

处理程序的传入请求以及基于某些标准的预处理器和后处理器(处理程序拦截器)的列表,其细节因 HandlerMapping 实现而异。最流行的实现支持带注释的控制器,但也存在其他实现。

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

DispatcherServlet 找到所有这种类型的 beans 并按某种顺序(可以自定义)注册它们。在服务请求时, DispatcherServlet 循环遍历这些 HandlerMapping 对象并使用 getHandler 以找到一个可以处理传入请求的代表标准 HttpServletRequest 。从 4.3.x 开始, 如果找不到任何,它会 记录您看到的警告

未找到具有 URI [/some/path]DispatcherServlet 中名称为 SomeName 的 HTTP 请求的映射

并抛出 NoHandlerFoundException 立即提交带有 404 Not Found 状态代码的响应。

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

The most common HandlerMapping implementation is RequestMappingHandlerMapping , which handles registering @Controller beans as handlers (really their @RequestMapping annotated methods).您可以自己声明这种类型的 bean(使用 @Bean<bean> 或其他机制),也可以使用 内置选项。这些是:

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

正如上面的链接所描述的,这两个都将注册一个 RequestMappingHandlerMapping bean(和一堆其他东西)。但是,如果没有处理程序, HandlerMapping 不是很有用。 RequestMappingHandlerMapping expects some @Controller beans so you need to declare those too, through @Bean methods in a Java configuration or <bean> declarations in an XML配置或通过组件扫描 @Controller 中的注释类。 确保存在这些豆子。

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

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

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

你可以随时编写自己的。显然, 您必须确保您发送的请求至少匹配一个已注册的 HandlerMapping 对象的处理程序。

If you don’t implicitly or explicitly register any HandlerMapping beans (or if detectAllHandlerMappings is true ), the DispatcherServlet registers some defaults .这些定义在 DispatcherServlet.propertiesDispatcherServlet 类相同的包中。它们是 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 配置。

其他常见错误

A DispatcherServlet 只是一个典型的 Java EE Servlet 。 You register it with your typical <web.xml> <servlet-class> and <servlet-mapping> declaration, or directly through ServletContext#addServlet in a WebApplicationInitializer ,或者使用 Spring Boot 使用的任何机制。因此,您必须依赖 Servlet 规范 中指定的 url 映射 逻辑,请参阅第 12 章。另请参阅

考虑到这一点,一个常见的错误是使用 DispatcherServlet /* ,从 @RequestMapping b0f 返回视图名称,并期待处理程序方法要呈现的 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;
}

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

未找到具有 URI [/Example/WEB-INF/jsps/example-view-name.jsp]DispatcherServlet 中名为“dispatcher”的 HTTP 请求的映射

Because the DispatcherServlet is mapped to /* and /* matches everything (except exact matches, which have higher priority), the DispatcherServlet would be选择处理来自 forwardJstlView (由 InternalResourceViewResolver 返回)。 在几乎所有情况下, DispatcherServlet 都不会被配置为处理此类请求

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

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

原文由 Sotirios Delimanolis 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

 @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 文件未在 Spring Boot Web 应用程序中呈现

原文由 RoutesMaps.com 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题