Pourquoi Spring MVC répond - il avec un 404 et signale "aucune correspondance trouvée pour la requête HTTP avec URI [...] dans DispatcherServlet"?
j'écris une application MVC de printemps, déployée sur Tomcat. Voir exemple minimal, complet et vérifiable :
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[] { "/*" };
}
}
où SpringServletConfig
est
@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;
}
}
enfin, j'ai un @Controller
dans le paquet com.example.controllers
@Controller
public class ExampleController {
@RequestMapping(path = "/home", method = RequestMethod.GET)
public String example() {
return "index";
}
}
le nom de contexte de ma demande est Example
. Quand j'envoie une demande à
http://localhost:8080/Example/home
L'application répond avec un statut HTTP 404 et enregistre ce qui suit
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'
j'ai une ressource JSP à /WEB-INF/jsps/index.jsp
Je m'attendais à ce que Spring MVC utilise mon contrôleur pour traiter la requête et la transmettre au JSP, alors pourquoi répond-il avec un 404?
C'est censé être une représentation canonique de poste pour des questions à propos de ce message d'avertissement.
3 réponses
votre application standard printemps MVC répondra à toutes les demandes par le biais d'un DispatcherServlet
que vous avez enregistré avec votre Servlet container.
le DispatcherServlet
regarde son ApplicationContext
et, si disponible, le ApplicationContext
enregistré avec un ContextLoaderListener
pour les haricots spéciaux dont il a besoin pour configurer sa logique de service de demande. ces haricots sont décrits dans la documentation .
Sans doute le plus important, haricots de type HandlerMapping
carte
demandes reçues aux gestionnaires et une liste des pré-et post-processeurs (gestionnaire d'intercepteurs) en fonction de certains critères, dont les détails varie selon la mise en œuvre
HandlerMapping
. La mise en œuvre la plus populaire prend en charge les contrôleurs annotés mais d'autres implémentations existent comme bien.
le javadoc de HandlerMapping
décrit plus en détail comment les mises en œuvre doivent se comporter.
Le DispatcherServlet
trouve tous les haricots de ce type et les enregistre dans un certain ordre (peut être personnalisé). Lors de la signification d'une requête, les boucles DispatcherServlet
à travers ces objets HandlerMapping
et teste chacun d'eux avec getHandler
pour trouver un qui puisse traiter la requête entrante, représentée comme la norme HttpServletRequest
. Que de 4.3.x, si elle ne trouverez pas de , les journaux de l'avertissement que vous voyez
aucune correspondance trouvée pour les requêtes HTTP avec URI
[/some/path]
dansDispatcherServlet
avec nom de domaine
et soit jette un NoHandlerFoundException
ou immédiatement s'engage la réponse avec un 404 not Found code d'état.
pourquoi le DispatcherServlet
trouver un HandlerMapping
qui pourrait traiter ma demande?
la mise en oeuvre la plus courante HandlerMapping
est RequestMappingHandlerMapping
, qui gère l'enregistrement @Controller
haricots comme handlers (en réalité leur @RequestMapping
méthodes annotées). Vous pouvez soit déclarer un haricot de ce type vous-même (avec @Bean
ou <bean>
ou autre mécanisme) ou vous pouvez utiliser les options intégrées . Ce sont:
- annoter votre classe
@Configuration
avec@EnableWebMvc
. - déclare un membre
<mvc:annotation-driven />
dans votre configuration XML.
comme le lien ci-dessus le décrit, tous les deux enregistreront un haricot RequestMappingHandlerMapping
(et un tas d'autres choses). Cependant, un HandlerMapping
n'est pas très utile sans un gestionnaire. RequestMappingHandlerMapping
s'attend à certains "1519240920 haricots donc vous devez déclarer ceux aussi, à travers @Bean
méthodes dans une configuration Java ou des déclarations <bean>
dans une configuration XML ou par balayage de composants de classes annotées @Controller
dans l'une ou l'autre de ces classes. assurez-vous que ces haricots sont présents.
si vous recevez le message d'avertissement et un 404 et que vous avez configuré tout ce qui précède correctement, alors vous envoyez votre demande à la mauvaise URI , une qui n'est pas traitée par un détecté @RequestMapping
annoté méthode de gestionnaire.
la bibliothèque spring-webmvc
offre d'autres implémentations HandlerMapping
intégrées. Par exemple:, BeanNameUrlHandlerMapping
cartes
de l'Url de haricots avec des noms qui commencent par une barre oblique ("/")
et vous pouvez toujours écrire votre propre. Évidemment, vous devrez vous assurer que la demande que vous envoyez correspond au moins à l'un des inscrits HandlerMapping
handler's handlers.
si vous n'enregistrez pas implicitement ou explicitement des haricots HandlerMapping
(ou si detectAllHandlerMappings
est true
), le DispatcherServlet
enregistre quelque par défaut . Celles-ci sont définies dans DispatcherServlet.properties
dans le même colis que la classe DispatcherServlet
. Ils sont BeanNameUrlHandlerMapping
et DefaultAnnotationHandlerMapping
(qui est similaire à RequestMappingHandlerMapping
mais déprécié).
débogage
printemps MVC logera les conducteurs enregistrés par RequestMappingHandlerMapping
. Par exemple, un @Controller
comme
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
enregistrera ce qui suit au niveau INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
décrit la cartographie enregistrée. Lorsque vous voyez l'avertissement qu'aucun handler n'a été trouvé, comparez L'URI dans le message à la cartographie listée ici. Toutes les restrictions spécifié dans le @RequestMapping
doit correspondre à ressort MVC pour sélectionner le handler.
autres HandlerMapping
implémentations enregistrer leurs propres déclarations qui devraient faire référence à leurs correspondances et leurs manipulateurs correspondants.
dans le même ordre d'idées, permettre la journalisation de printemps au niveau de débugage pour voir quels registres de printemps haricots. Il doit indiquer les classes annotées qu'il trouve, les paquets qu'il scanne, et les haricots qu'il initialise. Si l' ceux que vous attendiez ne sont pas présents, alors passez en revue votre configuration ApplicationContext
.
autres erreurs courantes
A DispatcherServlet
est juste un type Java EE Servlet
. Vous l'enregistrez avec votre déclaration typique <web.xml>
<servlet-class>
et <servlet-mapping>
, ou directement par ServletContext#addServlet
dans un WebApplicationInitializer
, ou avec n'importe quel mécanisme de botte de ressort utiliser. En tant que tel , vous devez vous en remettre à la URL mapping logique spécifiée dans la Servlet spécification , voir Chapitre 12. Voir aussi
avec cela à l'esprit, une erreur courante est d'enregistrer le DispatcherServlet
avec un mappage d'url de /*
, en retournant un nom de vue d'un @RequestMapping
méthode handler, et s'attendre à ce qu'un JSP soit rendu. Par exemple, envisager une méthode de handler comme
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
avec un InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
vous pourriez vous attendre à ce que la demande soit transmise à une ressource de JSP au chemin /WEB-INF/jsps/example-view-name.jsp
. Cela n'arrivera pas. Au lieu de cela, en supposant un nom de contexte de Example
, le DisaptcherServlet
rapportera
Aucune correspondance trouvée pour la requête HTTP avec l'URI
[/Example/WEB-INF/jsps/example-view-name.jsp]
dansDispatcherServlet
avec le nom de "répartiteur"
parce que le DispatcherServlet
correspond à /*
et /*
correspond à tout (sauf les correspondances exactes, qui ont une priorité plus élevée), le DispatcherServlet
serait choisi pour gérer le forward
de la JstlView
(retourné par le InternalResourceViewResolver
). dans presque tous les cas, le DispatcherServlet
ne sera pas configuré pour traiter une telle requête .
au lieu de cela, dans ce cas simpliste, vous devriez enregistrer le DispatcherServlet
à /
, en le marquant comme le servlet par défaut. Le servlet par défaut est la dernière correspondance pour une requête. Cela permettra à votre conteneur de servlet typique de choisir une implémentation de Servlet interne, mappée à *.jsp
, pour gérer la ressource JSP (par exemple, Tomcat a JspServlet
), avant d'essayer avec le servlet par défaut.
C'est ce que vous voyez dans votre exemple.
j'ai résolu mon problème lorsque, en plus de Décrit avant:
@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>
` de: fichier JSP ne rendant pas dans L'application Web de Botte de printemps
je suis tombé sur une autre raison pour la même erreur. Cela pourrait aussi être dû aux fichiers de classe non générés pour votre contrôleur.fichier java. En conséquence de quoi le servlet de régulateur mentionné dans web.xml ne peut pas l'associer à la méthode appropriée dans la classe controller.
@Controller
Class Controller{
@RequestMapping(value="/abc.html")//abc is the requesting page
public void method()
{.....}
}
in eclipse under Project - > select clean - > Build Project.Vérifiez si le fichier de classe a été généré pour le fichier controller sous builds dans votre espace de travail.