Стандартное приложение Spring MVC будет обслуживать все запросы через объект, DispatcherServlet
который вы зарегистрировали в своем контейнере сервлетов.
Он DispatcherServlet
просматривает его ApplicationContext
и, если он доступен, ApplicationContext
зарегистрированный с помощью ContextLoaderListener
специальных bean-компонентов, необходимых для настройки логики обслуживания запросов. Эти bean-компоненты описаны в документации .
Возможно, наиболее важные компоненты типа HandlerMapping
map
входящие запросы к обработчикам и список пре- и постпроцессоров (обработчиков-перехватчиков) на основе некоторых критериев, детали которых зависят от HandlerMapping
реализации. Самая популярная реализация поддерживает аннотированные контроллеры, но существуют и другие реализации.
В javadocHandlerMapping
далее описывается, как должны вести себя реализации.
Он DispatcherServlet
находит все компоненты этого типа и регистрирует их в некотором порядке (можно настроить). Обслуживая запрос, проходит DispatcherServlet
цикл по этим HandlerMapping
объектам и тестирует каждый из них, getHandler
чтобы найти тот, который может обрабатывать входящий запрос, представленный как стандарт HttpServletRequest
. Начиная с 4.3.x, если он не находит ничего , он регистрирует предупреждение, которое вы видите
Отображение не найдено для запроса HTTP с URI [/some/path]
в DispatcherServlet
с именем SomeName
и либо выдает, NoHandlerFoundException
либо немедленно фиксирует ответ с кодом состояния 404 Not Found.
Почему не удалось DispatcherServlet
найти объект HandlerMapping
, способный обработать мой запрос?
Наиболее распространенная HandlerMapping
реализация RequestMappingHandlerMapping
, которая обрабатывает регистрацию @Controller
bean-компонентов как обработчиков (на самом деле их @RequestMapping
аннотированных методов). Вы можете объявить bean-компонент этого типа самостоятельно (с помощью @Bean
или <bean>
или другим механизмом) или использовать встроенные параметры . Это:
- Аннотируйте свой
@Configuration
класс с помощью @EnableWebMvc
.
- Объявите
<mvc:annotation-driven />
член в своей конфигурации XML.
Как описано в приведенной выше ссылке, оба из них будут регистрировать RequestMappingHandlerMapping
bean-компонент (и множество других вещей). Однако HandlerMapping
без обработчика a не очень полезен. RequestMappingHandlerMapping
ожидает некоторых @Controller
bean-компонентов, поэтому вам также необходимо объявить их с помощью @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
не будет настроен для обработки такого запроса .
Вместо этого в этом упрощенном случае вы должны зарегистрировать DispatcherServlet
to /
, пометив его как сервлет по умолчанию. Сервлет по умолчанию - это последнее совпадение для запроса. Это позволит вашему типичному контейнеру сервлета выбрать внутреннюю реализацию сервлета, сопоставленную для *.jsp
обработки ресурса JSP (например, Tomcat JspServlet
), прежде чем пытаться использовать сервлет по умолчанию.
Это то, что вы видите в своем примере.