Twoja standardowa aplikacja Spring MVC będzie obsługiwać wszystkie żądania za pośrednictwem DispatcherServlet
konta zarejestrowanego w kontenerze serwletów.
Te DispatcherServlet
spojrzenia na jego ApplicationContext
oraz, jeśli jest dostępny, ApplicationContext
zarejestrowany w ContextLoaderListener
specjalnych ziaren potrzebnych do konfiguracji jego wniosek służąc logicznego. Te ziarna są opisane w dokumentacji .
Chyba najważniejsza, fasolowa HandlerMapping
mapa typu
przychodzące żądania do osób obsługujących oraz lista pre- i postprocesorów (przechwytywaczy obsługi) w oparciu o pewne kryteria, których szczegóły różnią się w zależności od HandlerMapping
implementacji. Najpopularniejsza implementacja obsługuje kontrolery z adnotacjami, ale istnieją również inne implementacje.
Dokument javadoc ofHandlerMapping
dalej opisuje, jak muszą zachowywać się implementacje.
DispatcherServlet
Wyszukuje wszystkie ziarna tego typu i rejestruje je w jakimś celu (można dostosować). Obsługując żądanie, DispatcherServlet
pętle przechodzą przez te HandlerMapping
obiekty i testują każdy z nich, getHandler
aby znaleźć taki, który może obsłużyć przychodzące żądanie, reprezentowane jako standard HttpServletRequest
. Od wersji 4.3.x, jeśli nie znajdzie żadnego , rejestruje ostrzeżenie , które widzisz
Nie znaleziono mapowania dla żądania HTTP z identyfikatorem URI [/some/path]
w DispatcherServlet
nazwie SomeName
i albo zgłasza, NoHandlerFoundException
albo natychmiast zatwierdza odpowiedź z kodem stanu 404 Not Found.
Dlaczego nie DispatcherServlet
znaleziono elementu, HandlerMapping
który mógłby obsłużyć moją prośbę?
Najpowszechniejszą HandlerMapping
implementacją jest RequestMappingHandlerMapping
, która obsługuje rejestrowanie @Controller
fasoli jako programów obsługi (tak naprawdę ich @RequestMapping
metody z adnotacjami). Możesz samodzielnie zadeklarować ziarno tego typu (za pomocą @Bean
lub <bean>
lub innego mechanizmu) lub skorzystać z wbudowanych opcji . To są:
- Dodaj adnotację do swojej
@Configuration
klasy za pomocą @EnableWebMvc
.
- Zadeklaruj
<mvc:annotation-driven />
członka w konfiguracji XML.
Jak opisuje powyższy link, oba zarejestrują RequestMappingHandlerMapping
fasolę (i kilka innych rzeczy). Jednak HandlerMapping
nie jest zbyt przydatny bez programu obsługi. RequestMappingHandlerMapping
oczekuje niektórych komponentów @Controller
bean, więc musisz je również zadeklarować za pomocą @Bean
metod w konfiguracji Java lub <bean>
deklaracji w konfiguracji XML lub przez skanowanie komponentów @Controller
klas z adnotacjami w obu. Upewnij się, że te ziarna są obecne.
Jeśli otrzymujesz komunikat ostrzegawczy i 404, a wszystkie powyższe elementy zostały poprawnie skonfigurowane, to wysyłasz żądanie do niewłaściwego identyfikatora URI , który nie jest obsługiwany przez wykrytą @RequestMapping
metodę obsługi z adnotacjami.
Do spring-webmvc
oferty Biblioteka Inne wbudowane w HandlerMapping
implementacji. Na przykład BeanNameUrlHandlerMapping
mapy
od adresów URL do fasoli z nazwami zaczynającymi się od ukośnika („/”)
i zawsze możesz napisać własne. Oczywiście musisz się upewnić, że wysyłane żądanie pasuje do co najmniej jednego z HandlerMapping
modułów obsługi zarejestrowanego obiektu.
Jeśli nie zarejestrujesz niejawnie lub jawnie żadnych HandlerMapping
ziaren (lub jeśli detectAllHandlerMappings
tak true
), DispatcherServlet
zarejestruje niektóre wartości domyślne . Są one zdefiniowane w DispatcherServlet.properties
tym samym pakiecie co DispatcherServlet
klasa. Są BeanNameUrlHandlerMapping
i DefaultAnnotationHandlerMapping
(co jest podobne do, RequestMappingHandlerMapping
ale przestarzałe).
Debugowanie
Spring MVC będzie rejestrować programy obsługi zarejestrowane za pośrednictwem RequestMappingHandlerMapping
. Na przykład @Controller
polubienie
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
zarejestruje następujące informacje na poziomie INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Opisuje zarejestrowane mapowanie. Gdy zobaczysz ostrzeżenie, że nie znaleziono programu obsługi, porównaj identyfikator URI w komunikacie z mapowaniem wymienionym tutaj. Wszystkie ograniczenia określone w pliku @RequestMapping
muszą być zgodne, aby Spring MVC wybrał procedurę obsługi.
Inne HandlerMapping
implementacje rejestrują własne instrukcje, które powinny wskazywać na ich mapowania i odpowiadające im funkcje obsługi.
Podobnie, włącz rejestrowanie Springa na poziomie DEBUG, aby zobaczyć, które ziarna rejestruje Spring. Powinien raportować, które klasy z adnotacjami znajdzie, które pakiety skanuje i które fasole inicjuje. Jeśli nie ma tych, których się spodziewałeś, sprawdź swoją ApplicationContext
konfigurację.
Inne typowe błędy
A DispatcherServlet
to po prostu typowy Java EE Servlet
. Rejestrujesz to za pomocą typowego <web.xml>
<servlet-class>
i <servlet-mapping>
deklaracji, lub bezpośrednio przez ServletContext#addServlet
a WebApplicationInitializer
, lub z jakimkolwiek mechanizmem używanym przez Spring boot. W związku z tym musisz polegać na logice odwzorowywania adresów URL określonej w specyfikacji serwletu , patrz Rozdział 12. Zobacz także
Mając to na uwadze, częstym błędem jest rejestrowanie DispatcherServlet
adresu URL z mapowaniem adresu /*
, zwracanie nazwy widoku z @RequestMapping
metody obsługi i oczekiwanie na renderowanie strony JSP. Na przykład rozważmy metodę obsługi, taką jak
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
z InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
można oczekiwać, że żądanie zostanie przekazane do zasobu JSP w ścieżce /WEB-INF/jsps/example-view-name.jsp
. To się nie stanie. Zamiast tego, zakładając nazwę kontekstu Example
, DisaptcherServlet
raport zgłosi
Nie znaleziono mapowanie żądania HTTP z URI [/Example/WEB-INF/jsps/example-view-name.jsp]
w DispatcherServlet
o nazwie „dyspozytora”
Ponieważ DispatcherServlet
jest odwzorowany na /*
i /*
dopasowuje wszystko (z wyjątkiem dokładnych dopasowań, które mają wyższy priorytet), DispatcherServlet
zostanie wybrany do obsługi forward
z JstlView
(zwróconego przez InternalResourceViewResolver
). W prawie każdym przypadku DispatcherServlet
nie zostanie skonfigurowany do obsługi takiego żądania .
Zamiast tego, w tym uproszczonym przypadku, powinieneś zarejestrować DispatcherServlet
to /
, oznaczając go jako domyślny serwlet. Domyślnym serwletem jest ostatnie dopasowanie dla żądania. Umożliwi to typowemu kontenerowi serwletów wybranie wewnętrznej implementacji serwletu, odwzorowanej na *.jsp
, do obsługi zasobu JSP (na przykład Tomcat JspServlet
), przed próbą z domyślnym serwletem.
To właśnie widzisz na swoim przykładzie.