Ваша стандартна програма Spring MVC буде обслуговувати всі запити через DispatcherServletте, що ви зареєстрували у своєму контейнері Servlet.
Переглядає DispatcherServletсвою ApplicationContextта, якщо вона доступна, ApplicationContextзареєстровану ContextLoaderListenerдля спеціального бобу, який йому потрібен для налаштування логіки обслуговування запитів. Ці боби описані в документації .
Мабуть, найважливіше, боби типу HandlerMappingкарти
вхідні запити до обробників та список попереднього та післяпроцесора (перехоплювачі обробників) на основі деяких критеріїв, деталі яких різняться залежно від HandlerMappingреалізації. Найпопулярніша реалізація підтримує анотовані контролери, але існують і інші реалізації.
Javadoc вHandlerMapping подальшому описує , як повинні поводитися реалізації.
DispatcherServletЗнаходять все боби цього типу і реєструють їх у певному порядку (можна налаштувати). Під час обслуговування запиту DispatcherServletциклічно переглядає ці HandlerMappingоб’єкти та тестує кожен із них, getHandlerщоб знайти той, який може обробляти вхідний запит, представлений як стандарт HttpServletRequest. Починаючи з 4.3.x, якщо він не знаходить жодного , він реєструє попередження, яке ви бачите
Не знайдено зіставлення для запиту HTTP з URI [/some/path] на DispatcherServletім’я SomeName
і будь-який кидає NoHandlerFoundExceptionабо відразу робить відповідь з 404 не найден кодом статусу.
Чому не DispatcherServlet знахідка не HandlerMappingмогла впоратися з моїм запитом?
Найпоширеніша HandlerMappingреалізація RequestMappingHandlerMapping, яка обробляє реєстрацію @Controllerбобів як обробників (насправді їх @RequestMappingанотовані методи). Ви можете або оголосити боб цього типу самостійно (з @Beanабо <bean>або іншим механізмом) , або ви можете використовувати вбудовані в налаштуваннях . Це:
- Анотуйте свої
@Configuration клас за допомогою @EnableWebMvc.
- Заявіть a
<mvc:annotation-driven /> учасника у вашій конфігурації XML.
Як описано в посиланні вище, обидва вони реєструють RequestMappingHandlerMappingбоб (і купу інших речей). Однак HandlerMappingбез обробника a не дуже корисний. RequestMappingHandlerMappingочікує декількох компонентів, @Controllerтому вам також потрібно оголосити їх за допомогою @Beanметодів у конфігурації Java або <bean>оголошень у конфігурації XML або за допомогою сканування компонентів @Controllerанотованих класів в будь-якому з них. Переконайтесь, що ці боби присутні.
Якщо ви отримуєте попереджувальне повідомлення та 404, і ви все правильно вказали все вище, тоді ви надсилаєте свій запит на неправильний URI , той, який не обробляється виявленим @RequestMappingанотованим методом обробника.
У spring-webmvcбібліотеці пропонує інші вбудовані HandlerMappingреалізації. Наприклад,BeanNameUrlHandlerMapping карти
від URL-адрес до компонентів з іменами, які починаються косою рисою ("/")
і ви завжди можете написати своє. Очевидно, вам доведеться переконатися, що запит, який ви надсилаєте, відповідає принаймні одному із зареєстрованихHandlerMapping обробників об’єкта.
Якщо ви неявно або явно не реєструєте будь-які HandlerMappingкомпоненти (або якщо detectAllHandlerMappingsє true), DispatcherServletреєструються деякі значення за замовчуванням . Вони визначені в DispatcherServlet.propertiesтому ж пакеті, що і DispatcherServletклас. Вони є BeanNameUrlHandlerMappingіDefaultAnnotationHandlerMapping (що схоже на, RequestMappingHandlerMappingале застаріле).
Налагодження
Spring MVC реєструватиме обробники, зареєстровані через RequestMappingHandlerMapping. Наприклад, @Controllerлайк
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
буде реєструвати наступне на рівні INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Це описує зареєстроване відображення. Коли ви побачите попередження про те, що не знайдено жодного обробника, порівняйте URI у повідомленні із переліченим тут відображенням. Всі обмеження, зазначені в@RequestMapping must, повинні збігатися з Spring MVC для вибору обробника.
Інший HandlerMapping реалізації реєструють власні оператори, які повинні натякати на їх відображення та відповідні обробники.
Подібним чином увімкніть весняний журнал на рівні DEBUG, щоб побачити, які компоненти Spring реєструються. Він повинен повідомляти, які анотовані класи він знаходить, які пакети сканує та які компоненти ініціалізує. Якщо тих, яких ви очікували, немає, перегляньте свою ApplicationContextконфігурацію.
Інші поширені помилки
A DispatcherServlet- це лише типовий Java EE Servlet. Ви реєструєте його за допомогою типового тексту <web.xml> <servlet-class>та <servlet-mapping>декларації, або безпосередньо ServletContext#addServletв a WebApplicationInitializer, або за допомогою будь-якого механізму, який використовує Spring boot. Таким чином, ви повинні покладатися на логіку відображення URL-адрес, зазначену в специфікації сервлету , див. Главу 12. Див. Також
Маючи це на увазі, типовою помилкою є реєстрація за DispatcherServletдопомогою відображення URL-адреси /*, повернення імені подання з @RequestMappingметоду обробника та очікування відображення JSP. Наприклад, розглянемо такий метод обробника, як
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
за допомогою InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
Ви можете очікувати, що запит буде переадресовано до ресурсу JSP за цим шляхом /WEB-INF/jsps/example-view-name.jsp. Цього не станеться. Натомість, припускаючи ім'я контексту Example,DisaptcherServlet повідомить
Не знайдено зіставлення для запиту HTTP з URI [/Example/WEB-INF/jsps/example-view-name.jsp]в DispatcherServletназві 'диспетчер'
Оскільки the DispatcherServletвідображається /*і /*відповідає усьому (крім точних збігів, які мають вищий пріоритет), DispatcherServletбуде вибрано, щоб обробляти forwardіз JstlView(повертається InternalResourceViewResolver).Майже у кожному випадку, пристрій DispatcherServletне буде налаштовано на обробку такого запиту .
Натомість у цьому спрощеному випадку вам слід зареєструвати DispatcherServletдо /, позначивши його як сервлет за замовчуванням. Сервлет за замовчуванням - це остання відповідність запиту. Це дозволить типовому контейнеру сервлетів обрати внутрішню реалізацію сервлету, зіставлену з ним *.jsp, для обробки ресурсу JSP (наприклад, Tomcat маєJspServlet ) перед тим, як спробувати використовувати сервлет за замовчуванням.
Це те, що ви бачите на своєму прикладі.