Votre application Spring MVC standard servira toutes les demandes via un DispatcherServletque vous avez enregistré avec votre conteneur Servlet.
Le DispatcherServletregarde son ApplicationContextet, si disponible, le ApplicationContextenregistré avec un ContextLoaderListenerpour les beans spéciaux dont il a besoin pour configurer sa logique de traitement de demande. Ces beans sont décrits dans la documentation .
Sans doute le type de HandlerMappingcarte le plus important
les demandes entrantes aux gestionnaires et une liste de pré et post-processeurs (intercepteurs de gestionnaires) basée sur certains critères dont les détails varient selon l' HandlerMappingimplémentation. L'implémentation la plus populaire prend en charge les contrôleurs annotés, mais d'autres implémentations existent également.
Le javadoc deHandlerMapping décrit plus en détail comment les implémentations doivent se comporter.
Le DispatcherServletrecherche tous les beans de ce type et les enregistre dans un certain ordre (peut être personnalisé). Tout en traitant une requête, le DispatcherServletparcourt ces HandlerMappingobjets et teste chacun d'eux avec getHandlerpour trouver celui qui peut gérer la requête entrante, représentée comme le standard HttpServletRequest. À partir de 4.3.x, s'il n'en trouve aucun , il enregistre l'avertissement que vous voyez
Aucune correspondance trouvée pour la requête HTTP avec l' URI [/some/path]en DispatcherServletavec le nom UnNom
et soit lancers francs un NoHandlerFoundExceptionou engage immédiatement la réponse avec un code d'état 404 Not Found.
Pourquoi la DispatcherServletrecherche n'a-t-elle pas HandlerMappingpu traiter ma demande?
L' HandlerMappingimplémentation la plus courante est RequestMappingHandlerMapping, qui gère l'enregistrement des @Controllerbeans en tant que gestionnaires (en fait leurs @RequestMappingméthodes annotées). Vous pouvez soit déclarer vous-même un bean de ce type (avec @Beanou <bean>ou un autre mécanisme), soit utiliser les options intégrées . Ceux-ci sont:
- Annotez votre
@Configurationclasse avec @EnableWebMvc.
- Déclarez un
<mvc:annotation-driven />membre dans votre configuration XML.
Comme le lien ci-dessus le décrit, les deux enregistreront un RequestMappingHandlerMappingbean (et un tas d'autres choses). Cependant, a HandlerMappingn'est pas très utile sans gestionnaire. RequestMappingHandlerMappingattend des @Controllerbeans, vous devez donc les déclarer également, via des @Beanméthodes dans une configuration Java ou des <bean>déclarations dans une configuration XML ou via l'analyse des composants des @Controllerclasses annotées dans l'un ou l'autre. 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, vous envoyez votre demande au mauvais URI , qui n'est pas géré par une @RequestMappingméthode de gestionnaire annotée détectée .
La spring-webmvcbibliothèque propose d'autres HandlerMappingimplémentations intégrées . Par exemple, des BeanNameUrlHandlerMappingcartes
des URL aux beans dont les noms commencent par une barre oblique ("/")
et vous pouvez toujours écrire le vôtre. De toute évidence, vous devrez vous assurer que la requête que vous envoyez correspond à au moins un des HandlerMappinggestionnaires de l' objet enregistré .
Si vous n'enregistrez pas implicitement ou explicitement de HandlerMappingbeans (ou si detectAllHandlerMappingsc'est le cas true), les valeurs par défaut sontDispatcherServlet enregistrées . Ceux-ci sont définis dans le même package que la classe. Ils sont et (qui est similaire mais obsolète).DispatcherServlet.propertiesDispatcherServletBeanNameUrlHandlerMappingDefaultAnnotationHandlerMappingRequestMappingHandlerMapping
Débogage
Spring MVC enregistrera les gestionnaires enregistrés via RequestMappingHandlerMapping. Par exemple, un @Controllerlike
@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()
Ceci décrit le mappage enregistré. Lorsque vous voyez l'avertissement qu'aucun gestionnaire n'a été trouvé, comparez l'URI dans le message au mappage répertorié ici. Toutes les restrictions spécifiées dans @RequestMappingdoivent correspondre pour que Spring MVC sélectionne le gestionnaire.
D'autres HandlerMappingimplémentations consignent leurs propres instructions qui devraient faire allusion à leurs mappages et à leurs gestionnaires correspondants.
De même, activez la journalisation Spring au niveau DEBUG pour voir quels beans Spring enregistre. Il doit indiquer les classes annotées qu'il trouve, les packages qu'il analyse et les beans qu'il initialise. Si ceux que vous attendiez ne sont pas présents, vérifiez votre ApplicationContextconfiguration.
Autres erreurs courantes
A DispatcherServletest juste un Java EE typique Servlet. Vous l'enregistrez avec votre déclaration typique <web.xml> <servlet-class>et <servlet-mapping>, ou directement via ServletContext#addServletun WebApplicationInitializer, ou avec n'importe quel mécanisme utilisé par Spring boot. En tant que tel, vous devez vous fier à la logique de mappage d'URL spécifiée dans la spécification du servlet , voir le chapitre 12. Voir aussi
Dans cet esprit, une erreur courante consiste à enregistrer le DispatcherServletavec un mappage d'URL de /*, à renvoyer un nom de vue à partir d'une @RequestMappingméthode de gestionnaire et à s'attendre à ce qu'une JSP soit rendue. Par exemple, considérons une méthode de gestionnaire 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 pouvez vous attendre à ce que la demande soit transmise à une ressource JSP sur le 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 DisaptcherServletrapportera
Aucun mappage trouvé pour la requête HTTP avec l' URI [/Example/WEB-INF/jsps/example-view-name.jsp]en DispatcherServletavec le nom « dispatcher »
Étant donné que le DispatcherServletest mappé vers /*et /*correspond à tout (sauf les correspondances exactes, qui ont une priorité plus élevée), le DispatcherServletserait choisi pour gérer le forwarddepuis le JstlView(renvoyé par le InternalResourceViewResolver). Dans presque tous les cas, le DispatcherServletne sera pas configuré pour gérer une telle demande .
Au lieu de cela, dans ce cas simpliste, vous devez enregistrer le DispatcherServletto /, le marquant comme 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 sur *.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.