Ваша стандартна програма 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
) перед тим, як спробувати використовувати сервлет за замовчуванням.
Це те, що ви бачите на своєму прикладі.