Votre application Spring MVC standard servira toutes les requêtes par l'intermédiaire d'un fichier de type DispatcherServlet
que vous avez enregistré auprès de votre conteneur de servlets.
Le site DispatcherServlet
examine son ApplicationContext
et, si elle est disponible, la ApplicationContext
enregistré auprès d'un ContextLoaderListener
pour les beans spéciaux dont il a besoin pour configurer sa logique de service de requête. Ces beans sont décrits dans la documentation .
Sans doute le plus important, les haricots de type HandlerMapping
carte
les requêtes entrantes vers les gestionnaires et une liste de pré et post-processeurs (intercepteurs de gestionnaires) en fonction de certains critères dont les détails varient selon HandlerMapping
mise en œuvre. L'implémentation la plus populaire supporte les contrôleurs annotés mais d'autres implémentations existent aussi également.
Le site javadoc de HandlerMapping
décrit en outre comment les implémentations doivent se comporter.
Le site DispatcherServlet
trouve tous les beans de ce type et les enregistre dans un certain ordre (peut être personnalisé). Pendant qu'elle sert une requête, la méthode DispatcherServlet
des boucles à travers ces HandlerMapping
et teste chacun d'entre eux avec getHandler
pour en trouver un qui puisse traiter la demande entrante, représentée par la norme HttpServletRequest
. A partir de 4.3.x, s'il ne trouve pas de il enregistre l'avertissement que vous voyez
Aucune correspondance trouvée pour la requête HTTP avec URI [/some/path]
sur DispatcherServlet
avec le nom SomeName
et soit lance un NoHandlerFoundException
ou commet immédiatement la réponse avec un code d'état 404 Not Found.
Pourquoi le DispatcherServlet
trouver un HandlerMapping
qui pourrait traiter ma demande ?
Les plus courants HandlerMapping
La mise en œuvre est RequestMappingHandlerMapping
qui s'occupe de l'enregistrement @Controller
en tant que gestionnaires (en réalité, leurs @RequestMapping
méthodes annotées). Vous pouvez soit déclarer vous-même un bean de ce type (avec l'option @Bean
ou <bean>
ou un autre mécanisme) ou vous pouvez utiliser les options intégrées . Ce sont :
- Annotez votre
@Configuration
classe avec @EnableWebMvc
.
- Déclarer un
<mvc:annotation-driven />
dans votre configuration XML.
Comme le décrit le lien ci-dessus, ces deux éléments enregistreront une RequestMappingHandlerMapping
(et un tas d'autres choses). Cependant, un HandlerMapping
n'est pas très utile sans un gestionnaire. RequestMappingHandlerMapping
s'attend à ce que @Controller
vous devez donc les déclarer également, par l'intermédiaire de @Bean
dans une configuration Java ou <bean>
dans une configuration XML ou par le biais d'un balayage de composant de @Controller
classes annotées dans l'un ou l'autre. Assurez-vous que ces haricots sont présents.
Si vous obtenez le message d'avertissement et un 404 et que vous avez configuré tous les éléments ci-dessus correctement, alors vous envoyez votre requête à la mauvaise URI qui n'est pas gérée par un système de détection. @RequestMapping
méthode du gestionnaire annoté.
Le site spring-webmvc
La bibliothèque offre d'autres services intégrés HandlerMapping
mises en œuvre. Par exemple, BeanNameUrlHandlerMapping
cartes
des URLs aux beans dont les noms commencent par une barre oblique ("/")
et vous pouvez toujours écrire le vôtre. Évidemment, vous devez vous assurer que la requête que vous envoyez correspond à au moins un des éléments enregistrés. HandlerMapping
les gestionnaires de l'objet.
Si vous n'enregistrez pas implicitement ou explicitement de HandlerMapping
haricots (ou si detectAllHandlerMappings
est true
), le DispatcherServlet
enregistre certains Valeurs par défaut . Ceux-ci sont définis dans DispatcherServlet.properties
dans le même paquet que le DispatcherServlet
classe. Ils sont BeanNameUrlHandlerMapping
et DefaultAnnotationHandlerMapping
(qui est similaire à RequestMappingHandlerMapping
mais déprécié).
Débogage
Spring MVC enregistrera les gestionnaires enregistrés via 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 le message suivant au niveau INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Ceci décrit la cartographie enregistrée. Lorsque vous voyez l'avertissement indiquant 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 la section @RequestMapping
doit correspondre pour que Spring MVC puisse sélectionner le gestionnaire.
Autre HandlerMapping
Les implémentations enregistrent leurs propres déclarations qui devraient donner des indications sur leurs mappings et leurs gestionnaires correspondants.
De même, activez la journalisation de Spring au niveau DEBUG pour voir quels beans Spring enregistre. Il devrait signaler les classes annotées qu'il trouve, les paquets qu'il scanne et les beans qu'il initialise. Si les éléments que vous attendiez ne sont pas présents, revoyez votre code source. ApplicationContext
configuration.
Autres erreurs courantes
A DispatcherServlet
est juste un exemple typique de Java EE Servlet
. Vous l'enregistrez auprès de votre <web.xml>
<servlet-class>
et <servlet-mapping>
ou directement par la déclaration ServletContext#addServlet
dans un WebApplicationInitializer
ou avec tout autre mécanisme utilisé par Spring boot. En tant que tel, vous devez vous appuyer sur le cartographie des urls logique spécifiée dans le Spécification des servlets voir le chapitre 12. Voir aussi
Dans cette optique, une erreur fréquente consiste à enregistrer l'élément DispatcherServlet
avec un mapping url de /*
en renvoyant le nom d'une vue à partir d'un @RequestMapping
et s'attendre à ce qu'une JSP soit rendue. Par exemple, considérons une méthode de gestion 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;
}
on peut s'attendre à ce que la demande soit transmis à vers une ressource JSP au chemin /WEB-INF/jsps/example-view-name.jsp
. Cela ne se produira pas. Au lieu de cela, en supposant que le nom du contexte est Example
le DisaptcherServlet
fera un rapport
Aucune correspondance trouvée pour la requête HTTP avec URI [/Example/WEB-INF/jsps/example-view-name.jsp]
sur DispatcherServlet
avec le nom "dispatcher".
Parce que le DispatcherServlet
est mis en correspondance avec /*
et /*
correspond à tout (sauf aux concordances exactes, qui ont une priorité plus élevée), l'option DispatcherServlet
serait choisi pour gérer le forward
de la JstlView
(renvoyée par la InternalResourceViewResolver
). Dans presque tous les cas, le DispatcherServlet
ne sera pas configuré pour traiter une telle demande .
Au lieu de cela, dans ce cas simpliste, il faut enregistrer le fichier DispatcherServlet
à /
en le marquant comme le servlet par défaut. Le servlet par défaut est le dernier à correspondre à une requête. Cela permettra à votre conteneur de servlets typique de choisir une implémentation de servlet interne, mappée à *.jsp
pour gérer la ressource JSP (par exemple, Tomcat dispose de JspServlet
), avant d'essayer avec le servlet par défaut.
C'est ce que vous voyez dans votre exemple.