Your standard Spring MVC application will serve all requests through the DispatcherServlet that you registered in your servlet container.
DispatcherServlet looks at its ApplicationContext and, if available, the ApplicationContext registered in the ContextLoaderListener for special beans, it must set its request servicing logic. These components are described in the documentation .
Perhaps most important, beans like HandlerMapping map
incoming requests to handlers and a list of pre- and post-processors (hook-handlers) based on some criteria, the details of which vary depending on the implementation of HandlerMapping . The most popular implementation supports annotated controllers, but other implementations exist as well.
The HandlerMapping Javadoc further describes how implementations should behave.
DispatcherServlet finds all the beans of this type and registers them in some order (can be configured). While serving the request, the DispatcherServlet goes through these HandlerMapping objects and tests each of them with getHandler to find one that can handle the incoming request, presented as an HttpServletRequest standard. Starting from 4.3.x, if it does not find it , it logs a warning about what you see
No mapping found for HTTP request with URI [/some/path] in DispatcherServlet named SomeName
and either throws a NoHandlerFoundException , or immediately sends a response with a status code 404 "Not found".
Why didnโt DispatcherServlet find a HandlerMapping that could handle my request?
The most common HandlerMapping implementation is RequestMappingHandlerMapping , which handles the registration of @Controller as handlers (actually their annotated @RequestMapping methods). You can either declare a bean of this type yourself (using @Bean or <bean> , or using another mechanism), or use the built-in parameters . It:
- Annotate your
@Configuration class with @EnableWebMvc . - Declare the
<mvc:annotation-driven /> element in your XML configuration.
As described in the link above, both of them will register the RequestMappingHandlerMapping bean (and many other things). However, HandlerMapping not very useful without a handler. RequestMappingHandlerMapping expects some @Controller , so you also need to declare them using the @Bean methods in the Java configuration or the <bean> declarations in the XML configuration or by scanning components of the annotated @Controller classes in both. Make sure these beans are present.
If you receive a warning message and the number 404 and correctly configure all of the above, you send a request for an invalid URI that is not processed by the @RequestMapping detected annotated handler method.
The spring-webmvc offers other built-in implementations of HandlerMapping . For example, BeanNameUrlHandlerMapping maps
from URLs to beans with names starting with a slash ("/")
and you can always write your own. Obviously, you must make sure that the request you send matches at least one of the registered HandlerMapping object HandlerMapping .
If you do not implicitly or explicitly register any HandlerMapping (or if detectAllHandlerMappings is true ), DispatcherServlet register some default values . They are defined in DispatcherServlet.properties in the same package as the DispatcherServlet class. These are BeanNameUrlHandlerMapping and DefaultAnnotationHandlerMapping (which is similar to RequestMappingHandlerMapping , but not recommended).
Debugging
Spring MVC will register handlers registered through RequestMappingHandlerMapping . For example, @Controller as
@Controller public class ExampleController { @RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom") public String example() { return "example-view-name"; } }
will register the next at the INFO level
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
This is a description of the registered display. When you see a warning that the handler was not found, compare the URI in the message with the display specified here. All restrictions specified in @RequestMapping must comply with Spring MVC for selecting a handler.
Other implementations of HandlerMapping register their own statements, which should point to their mappings and corresponding handlers.
Likewise, enable Spring logging at the DEBUG level to see which beans are being registered by Spring. He must report which annotated classes he finds, which packets he scans, and which components he initializes. If you are not expecting, review the ApplicationContext configuration.
Other common mistakes
DispatcherServlet is just a typical Java EE Servlet . You register it in your typical <web.xml> <servlet-class> and <servlet-mapping> declarations, either directly through ServletContext#addServlet in WebApplicationInitializer , or using any other mechanism used by Spring boot. Therefore, you must rely on the URL mapping logic specified in the servlet specification, see chapter 12. See also
- How are servlet URL mappings used in web.xml?
Given this, a common mistake is to register a DispatcherServlet with the display of the URL /* , returning the view name from the @RequestMapping handler @RequestMapping and waiting for the JSP to render. For example, consider a handler method, for example
@RequestMapping(path = "/example", method = RequestMethod.GET) public String example() { return "example-view-name"; }
with InternalResourceViewResolver
@Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; }
you can expect the request to be redirected to the JSP resource along the path /WEB-INF/jsps/example-view-name.jsp . It will not happen. Instead, by accepting the context name Example , the DisaptcherServlet will report
No mapping was found for the HTTP request with the URI [/Example/WEB-INF/jsps/example-view-name.jsp] in the DispatcherServlet named "dispatcher"
Since the DispatcherServlet mapped to /* and /* matches everything (except for exact matches that have a higher priority), a DispatcherServlet will be selected to handle forward from JstlView ( InternalResourceViewResolver returned). In almost every case, the DispatcherServlet will not be configured to handle such a request .
Instead, in this simplified case, you should register the DispatcherServlet in / , marking it as the default servlet. The default servlet is the last match for the request. This will allow your typical servlet container to choose the internal servlet implementation mapped to *.jsp to process the JSP resource (for example, Tomcat has a JspServlet ) before attempting to use the default servlet.
This is what you see in your example.