La tua applicazione Spring MVC standard servirà tutte le richieste tramite un DispatcherServlet
che hai registrato con il tuo contenitore Servlet.
Le DispatcherServlet
guarda il suo ApplicationContext
e, se disponibile, il ApplicationContext
registrati con una ContextLoaderListener
per 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 HandlerMapping
mappa 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 HandlerMapping
dell'implementazione. L'implementazione più popolare supporta controller annotati ma esistono anche altre implementazioni.
Il javadoc diHandlerMapping
descrive ulteriormente come devono comportarsi le implementazioni.
La DispatcherServlet
trova tutti i fagioli di questo tipo e li registra in un ordine (personalizzabile). Mentre serve una richiesta, il DispatcherServlet
loop passa attraverso questi HandlerMapping
oggetti e testa ciascuno di essi getHandler
per 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 DispatcherServlet
con nome SomeName
e sia getta una NoHandlerFoundException
o immediatamente impegna la risposta con un codice di stato 404 Not Found.
Perché non ho DispatcherServlet
trovato un in HandlerMapping
grado di gestire la mia richiesta?
L' HandlerMapping
implementazione più comune è RequestMappingHandlerMapping
, che gestisce la registrazione dei @Controller
bean come gestori (in realtà i loro @RequestMapping
metodi annotati). Puoi dichiarare tu stesso un bean di questo tipo (con @Bean
o <bean>
o un altro meccanismo) oppure puoi usare le opzioni integrate . Questi sono:
- Annota la tua
@Configuration
classe con @EnableWebMvc
.
- Dichiara un
<mvc:annotation-driven />
membro nella tua configurazione XML.
Come descritto nel collegamento sopra, entrambi registreranno un RequestMappingHandlerMapping
bean (e un mucchio di altre cose). Tuttavia, a HandlerMapping
non è molto utile senza un gestore. RequestMappingHandlerMapping
si aspetta alcuni @Controller
bean quindi è necessario dichiararli anche tramite @Bean
metodi in una configurazione Java o <bean>
dichiarazioni in una configurazione XML o tramite la scansione dei componenti delle @Controller
classi 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 @RequestMapping
metodo del gestore annotato rilevato .
La spring-webmvc
libreria offre altre HandlerMapping
implementazioni integrate . Ad esempio, BeanNameUrlHandlerMapping
mappe
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 HandlerMapping
gestori dell'oggetto registrato .
Se non registri implicitamente o esplicitamente alcun HandlerMapping
bean (o se lo detectAllHandlerMappings
è true
), DispatcherServlet
registra alcuni valori predefiniti . Questi sono definiti nello DispatcherServlet.properties
stesso pacchetto della DispatcherServlet
classe. Sono BeanNameUrlHandlerMapping
e DefaultAnnotationHandlerMapping
(che è simile a RequestMappingHandlerMapping
ma deprecato).
Debug
Spring MVC registrerà i gestori registrati tramite RequestMappingHandlerMapping
. Ad esempio, un @Controller
like
@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 @RequestMapping
devono corrispondere affinché Spring MVC selezioni il gestore.
Altre HandlerMapping
implementazioni 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 ApplicationContext
configurazione.
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#addServlet
in 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 DispatcherServlet
con una mappatura URL /*
, restituendo un nome di visualizzazione da un @RequestMapping
metodo 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
, DisaptcherServlet
riporterà
Nessun mapping trovato per la richiesta HTTP con URI [/Example/WEB-INF/jsps/example-view-name.jsp]
in DispatcherServlet
con il nome 'dispatcher'
Poiché DispatcherServlet
è mappato a /*
e /*
corrisponde a tutto (tranne le corrispondenze esatte, che hanno una priorità più alta), DispatcherServlet
verrebbe scelto di gestire il forward
da JstlView
(restituito da InternalResourceViewResolver
). In quasi tutti i casi, DispatcherServlet
non sarà configurato per gestire tale richiesta .
Invece, in questo caso semplicistico, dovresti registrare il DispatcherServlet
to /
, 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.