java - Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"? -
i'm writing spring mvc application, deployed on tomcat. see following minimal, complete, , 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[] { "/*" }; } }
where 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; } }
finally, have @controller
in package com.example.controllers
@controller public class examplecontroller { @requestmapping(path = "/home", method = requestmethod.get) public string example() { return "index"; } }
my application's context name example
. when send request to
http://localhost:8080/example/home
the application responds http status 404 , logs following
warn o.s.web.servlet.pagenotfound - no mapping found http request uri `[/example/web-inf/jsps/index.jsp]` in `dispatcherservlet` name 'dispatcher'
i have jsp resource @ /web-inf/jsps/index.jsp
expected spring mvc use controller handle request , forward jsp, why responding 404?
this meant canonical post questions warning message.
your standard spring mvc application serve requests through dispatcherservlet
you've registered servlet container.
the dispatcherservlet
looks @ applicationcontext
and, if available, applicationcontext
registered contextloaderlistener
special beans needs setup request serving logic. these beans described in documentation.
arguably important, beans of type handlermapping
map
incoming requests handlers , list of pre- , post-processors (handler interceptors) based on criteria details of vary
handlermapping
implementation. popular implementation supports annotated controllers other implementations exists well.
the javadoc of handlermapping
further describes how implementations must behave.
the dispatcherservlet
finds beans of type , registers them in order (can customized). while serving request, dispatcherservlet
loops through these handlermapping
objects , tests each of them gethandler
find 1 can handle incoming request, represented standard httpservletrequest
. of 4.3.x, if doesn't find any, logs warning see
no mapping found http request uri
[/some/path]
indispatcherservlet
name somename
and either throws nohandlerfoundexception
or commits response 404 not found status code.
why didn't dispatcherservlet
find handlermapping
handle request?
the common handlermapping
implementation requestmappinghandlermapping
, handles registering @controller
beans handlers (really @requestmapping
annotated methods). can either declare bean of type (with @bean
or <bean>
or other mechanism) or can use the built-in options. these are:
- annotate
@configuration
class@enablewebmvc
. - declare
<mvc:annotation-driven />
member in xml configuration.
as link above describes, both of these register requestmappinghandlermapping
bean (and bunch of other stuff). however, handlermapping
isn't useful without handler. requestmappinghandlermapping
expects @controller
beans need declare too, through @bean
methods in java configuration or <bean>
declarations in xml configuration or through component scanning of @controller
annotated classes in either. make sure these beans present.
if you're getting warning message , 404 , you've configured of above correctly, then you're sending request wrong uri, 1 isn't handled detected @requestmapping
annotated handler method.
the spring-webmvc
library offers other built-in handlermapping
implementations. example, beannameurlhandlermapping
maps
from urls beans names start slash ("/")
and can write own. obviously, you'll have make sure request you're sending matches @ least 1 of registered handlermapping
object's handlers.
if don't explicitly register handlermapping
beans (or if detectallhandlermappings
true
), dispatcherservlet
registers defaults. these defined in dispatcherservlet.properties
in same package dispatcherservlet
class. beannameurlhandlermapping
, defaultannotationhandlermapping
(which similar requestmappinghandlermapping
deprecated).
debugging
spring mvc log handlers registered through requestmappinghandlermapping
. example, @controller
like
@controller public class examplecontroller { @requestmapping(path = "/example", method = requestmethod.get, headers = "x-custom") public string example() { return "example-view-name"; } }
will log following @ info level
mapped "{[/example],methods=[get],headers=[x-custom]}" onto public java.lang.string com.spring.servlet.examplecontroller.example()
this describes mapping registered. when see warning no handler found, compare uri in message mapping listed here. restrictions specified in @requestmapping
must match spring mvc select handler.
other handlermapping
implementations log own statements should hint mappings , corresponding handlers.
similarly, enable spring logging @ debug level see beans spring registers. should report annotated classes finds, packages scans, , beans initializes. if ones expected aren't present, review applicationcontext
configuration.
other common mistakes
a dispatcherservlet
typical java ee servlet
. register typical <web.xml>
<servlet-class>
, <servlet-mapping>
declaration, or directly through servletcontext#addservlet
in webapplicationinitializer
, or whatever mechanism spring boot uses. such, must rely on url mapping logic specified in servlet specification, see chapter 12. see also
with in mind, common mistake register dispatcherservlet
url mapping of /*
, returning view name @requestmapping
handler method, , expecting jsp rendered. example, consider handler method like
@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 might expect request forwarded jsp resource @ path /web-inf/jsps/example-view-name.jsp
. won't happen. instead, assuming context name of example
, disaptcherservlet
report
no mapping found http request uri
[/example/web-inf/jsps/example-view-name.jsp]
indispatcherservlet
name 'dispatcher'
because dispatcherservlet
mapped /*
, /*
matches (except exact matches, have higher priority), dispatcherservlet
chosen handle forward
jstlview
(returned internalresourceviewresolver
). in every case, dispatcherservlet
not configured handle such request.
instead, in simplistic case, should register dispatcherservlet
/
, marking default servlet. default servlet last match request. allow typical servlet container chose internal servlet implementation, mapped *.jsp
, handle jsp resource (for example, tomcat has jspservlet
), before trying default servlet.
that's you're seeing in example.
Comments
Post a Comment