La tua applicazione Spring MVC standard servirà tutte le richieste tramite un DispatcherServletche hai registrato con il tuo contenitore Servlet.
Le DispatcherServletguarda il suo ApplicationContexte, se disponibile, il ApplicationContextregistrati con una ContextLoaderListenerper i fagioli speciali di cui ha bisogno per impostare la sua richiesta logica di servire. Questi bean sono descritti nella documentazione .
Probabilmente il più importante, i fagioli della HandlerMappingmappa dei tipi
richieste in arrivo ai gestori e un elenco di pre e post processori (handler interceptor) in base ad alcuni criteri i cui dettagli variano a seconda HandlerMappingdell'implementazione. L'implementazione più popolare supporta controller annotati ma esistono anche altre implementazioni.
Il javadoc diHandlerMapping descrive ulteriormente come devono comportarsi le implementazioni.
La DispatcherServlettrova tutti i fagioli di questo tipo e li registra in un ordine (personalizzabile). Mentre serve una richiesta, il DispatcherServletloop passa attraverso questi HandlerMappingoggetti e testa ciascuno di essi getHandlerper trovarne uno in grado di gestire la richiesta in arrivo, rappresentata come standard HttpServletRequest. A partire da 4.3.x, se non ne trova , registra l'avviso che vedi
Nessun mapping trovato per la richiesta HTTP con URI [/some/path]in DispatcherServletcon nome SomeName
e sia getta una NoHandlerFoundExceptiono immediatamente impegna la risposta con un codice di stato 404 Not Found.
Perché non ho DispatcherServlettrovato un in HandlerMappinggrado di gestire la mia richiesta?
L' HandlerMappingimplementazione più comune è RequestMappingHandlerMapping, che gestisce la registrazione dei @Controllerbean come gestori (in realtà i loro @RequestMappingmetodi annotati). Puoi dichiarare tu stesso un bean di questo tipo (con @Beano <bean>o un altro meccanismo) oppure puoi usare le opzioni integrate . Questi sono:
- Annota la tua
@Configurationclasse con @EnableWebMvc.
- Dichiara un
<mvc:annotation-driven />membro nella tua configurazione XML.
Come descritto nel collegamento sopra, entrambi registreranno un RequestMappingHandlerMappingbean (e un mucchio di altre cose). Tuttavia, a HandlerMappingnon è molto utile senza un gestore. RequestMappingHandlerMappingsi aspetta alcuni @Controllerbean quindi è necessario dichiararli anche tramite @Beanmetodi in una configurazione Java o <bean>dichiarazioni in una configurazione XML o tramite la scansione dei componenti delle @Controllerclassi annotate in entrambe. Assicurati che questi fagioli siano presenti.
Se ricevi il messaggio di avviso e un 404 e hai configurato tutto quanto sopra correttamente, stai inviando la tua richiesta all'URI sbagliato , uno che non è gestito da un @RequestMappingmetodo del gestore annotato rilevato .
La spring-webmvclibreria offre altre HandlerMappingimplementazioni integrate . Ad esempio, BeanNameUrlHandlerMappingmappe
dagli URL ai bean con nomi che iniziano con una barra ("/")
e puoi sempre scrivere il tuo. Ovviamente, dovrai assicurarti che la richiesta che stai inviando corrisponda ad almeno uno dei HandlerMappinggestori dell'oggetto registrato .
Se non registri implicitamente o esplicitamente alcun HandlerMappingbean (o se lo detectAllHandlerMappingsè true), DispatcherServletregistra alcuni valori predefiniti . Questi sono definiti nello DispatcherServlet.propertiesstesso pacchetto della DispatcherServletclasse. Sono BeanNameUrlHandlerMappinge DefaultAnnotationHandlerMapping(che è simile a RequestMappingHandlerMappingma deprecato).
Debug
Spring MVC registrerà i gestori registrati tramite RequestMappingHandlerMapping. Ad esempio, un @Controllerlike
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
registrerà quanto segue a livello di INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Descrive la mappatura registrata. Quando viene visualizzato l'avviso che non è stato trovato alcun gestore, confronta l'URI nel messaggio con la mappatura elencata qui. Tutte le restrizioni specificate in @RequestMappingdevono corrispondere affinché Spring MVC selezioni il gestore.
Altre HandlerMappingimplementazioni registrano le proprie istruzioni che dovrebbero suggerire le loro mappature e i loro gestori corrispondenti.
Allo stesso modo, abilitare la registrazione Spring a livello DEBUG per vedere quali bean Spring registra. Dovrebbe riportare quali classi annotate trova, quali pacchetti analizza e quali bean inizializza. Se quelli che ti aspettavi non sono presenti, controlla la tua ApplicationContextconfigurazione.
Altri errori comuni
A DispatcherServletè solo un tipico Java EE Servlet. Lo registri con la tua tipica dichiarazione <web.xml> <servlet-class>e <servlet-mapping>, o direttamente attraverso ServletContext#addServletin a WebApplicationInitializer, o con qualsiasi meccanismo che usi Spring boot. Pertanto, è necessario fare affidamento sulla logica di mappatura URL specificata nella specifica Servlet , vedere il Capitolo 12. Vedere anche
Con questo in mente, un errore comune è registrare DispatcherServletcon una mappatura URL /*, restituendo un nome di visualizzazione da un @RequestMappingmetodo gestore e aspettandosi che venga eseguito il rendering di un JSP. Ad esempio, considera un metodo di gestione come
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
con un InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
potresti aspettarti che la richiesta venga inoltrata a una risorsa JSP nel percorso /WEB-INF/jsps/example-view-name.jsp. Non succederà. Invece, assumendo un nome di contesto di Example, DisaptcherServletriporterà
Nessun mapping trovato per la richiesta HTTP con URI [/Example/WEB-INF/jsps/example-view-name.jsp]in DispatcherServletcon il nome 'dispatcher'
Poiché DispatcherServletè mappato a /*e /*corrisponde a tutto (tranne le corrispondenze esatte, che hanno una priorità più alta), DispatcherServletverrebbe scelto di gestire il forwardda JstlView(restituito da InternalResourceViewResolver). In quasi tutti i casi, DispatcherServletnon sarà configurato per gestire tale richiesta .
Invece, in questo caso semplicistico, dovresti registrare il DispatcherServletto /, contrassegnandolo come servlet predefinito. Il servlet predefinito è l'ultima corrispondenza per una richiesta. Ciò consentirà al proprio contenitore servlet tipico di scegliere un'implementazione servlet interna, mappata *.jsp, per gestire la risorsa JSP (ad esempio, Tomcat ha JspServlet), prima di provare con il servlet predefinito.
Questo è quello che vedi nel tuo esempio.