Стандартное приложение Spring MVC будет обслуживать все запросы через объект, DispatcherServletкоторый вы зарегистрировали в своем контейнере сервлетов.
Он DispatcherServletпросматривает его ApplicationContextи, если он доступен, ApplicationContextзарегистрированный с помощью ContextLoaderListenerспециальных bean-компонентов, необходимых для настройки логики обслуживания запросов. Эти bean-компоненты описаны в документации .
Возможно, наиболее важные компоненты типа HandlerMappingmap
входящие запросы к обработчикам и список пре- и постпроцессоров (обработчиков-перехватчиков) на основе некоторых критериев, детали которых зависят от HandlerMappingреализации. Самая популярная реализация поддерживает аннотированные контроллеры, но существуют и другие реализации.
В javadocHandlerMapping далее описывается, как должны вести себя реализации.
Он DispatcherServletнаходит все компоненты этого типа и регистрирует их в некотором порядке (можно настроить). Обслуживая запрос, проходит DispatcherServletцикл по этим HandlerMappingобъектам и тестирует каждый из них, getHandlerчтобы найти тот, который может обрабатывать входящий запрос, представленный как стандарт HttpServletRequest. Начиная с 4.3.x, если он не находит ничего , он регистрирует предупреждение, которое вы видите
Отображение не найдено для запроса HTTP с URI [/some/path]в DispatcherServletс именем SomeName
и либо выдает, NoHandlerFoundExceptionлибо немедленно фиксирует ответ с кодом состояния 404 Not Found.
Почему не удалось DispatcherServletнайти объект HandlerMapping, способный обработать мой запрос?
Наиболее распространенная HandlerMappingреализация RequestMappingHandlerMapping, которая обрабатывает регистрацию @Controllerbean-компонентов как обработчиков (на самом деле их @RequestMappingаннотированных методов). Вы можете объявить bean-компонент этого типа самостоятельно (с помощью @Beanили <bean>или другим механизмом) или использовать встроенные параметры . Это:
- Аннотируйте свой
@Configurationкласс с помощью @EnableWebMvc.
- Объявите
<mvc:annotation-driven />член в своей конфигурации XML.
Как описано в приведенной выше ссылке, оба из них будут регистрировать RequestMappingHandlerMappingbean-компонент (и множество других вещей). Однако HandlerMappingбез обработчика a не очень полезен. RequestMappingHandlerMappingожидает некоторых @Controllerbean-компонентов, поэтому вам также необходимо объявить их с помощью @Beanметодов в конфигурации Java или <bean>объявлений в конфигурации XML, или путем сканирования компонентов @Controllerаннотированных классов в любом из них. Убедитесь, что эти бобы присутствуют.
Если вы получаете предупреждающее сообщение и ошибку 404 и правильно настроили все вышеперечисленное, то вы отправляете свой запрос на неправильный URI , который не обрабатывается обнаруженным @RequestMappingметодом аннотированного обработчика.
В spring-webmvcбиблиотеке предлагает другие встроенные HandlerMappingреализации. Например, BeanNameUrlHandlerMappingкарты
от URL до beans с именами, начинающимися с косой черты ("/")
и вы всегда можете написать свой собственный. Очевидно, вам нужно будет убедиться, что отправляемый вами запрос соответствует хотя бы одному из 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";
}
}
будет регистрировать следующее на уровне ИНФОРМАЦИИ
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Это описывает зарегистрированное отображение. Когда вы видите предупреждение о том, что обработчик не найден, сравните URI в сообщении с отображением, указанным здесь. Все ограничения, указанные в файле, @RequestMappingдолжны совпадать с Spring MVC для выбора обработчика.
Другие HandlerMappingреализации записывают свои собственные операторы, которые должны указывать на их сопоставления и соответствующие обработчики.
Точно так же включите ведение журнала Spring на уровне DEBUG, чтобы увидеть, какие компоненты Spring регистрируются. Он должен сообщать, какие аннотированные классы он находит, какие пакеты сканирует и какие компоненты инициализирует. Если те, которые вы ожидали, отсутствуют, проверьте свою ApplicationContextконфигурацию.
Другие распространенные ошибки
A DispatcherServlet- это просто типичный Java EE Servlet. Вы регистрируете его с вашей типичным <web.xml> <servlet-class>и <servlet-mapping>декларацией, или непосредственно через ServletContext#addServletв WebApplicationInitializer, или с каким - либо механизмом Spring загрузочного использованием. Таким образом, вы должны полагаться на логику сопоставления 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с именем «диспетчером»
Поскольку DispatcherServletсопоставлен /*и /*соответствует всему (кроме точных совпадений, которые имеют более высокий приоритет), DispatcherServletбудет выбран для обработки forwardиз JstlView(возвращенного InternalResourceViewResolver). Практически в каждом случае DispatcherServletне будет настроен для обработки такого запроса .
Вместо этого в этом упрощенном случае вы должны зарегистрировать DispatcherServletto /, пометив его как сервлет по умолчанию. Сервлет по умолчанию - это последнее совпадение для запроса. Это позволит вашему типичному контейнеру сервлета выбрать внутреннюю реализацию сервлета, сопоставленную для *.jspобработки ресурса JSP (например, Tomcat JspServlet), прежде чем пытаться использовать сервлет по умолчанию.
Это то, что вы видите в своем примере.