Почему Spring MVC отвечает 404 и сообщает «Нет сопоставления для HTTP-запроса с URI в DispatcherServlet»?

Я пишу приложение Spring MVC, развернутое на Tomcat. См. Следующий минимальный, полный и проверяемый пример :

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class[] getRootConfigClasses() { return new Class[] { }; } protected Class[] getServletConfigClasses() { return new Class[] { SpringServletConfig.class }; } protected String[] getServletMappings() { return new String[] { "/*" }; } } 

Где SpringServletConfig является

 @Configuration @ComponentScan("com.example.controllers") @EnableWebMvc public class SpringServletConfig { @Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; } } 

Наконец, у меня есть @Controller в пакете com.example.controllers

 @Controller public class ExampleController { @RequestMapping(path = "/home", method = RequestMethod.GET) public String example() { return "index"; } } 

Контекстное имя моего приложения – Example . Когда я отправлю запрос на

 http://localhost:8080/Example/home 

приложение отвечает HTTP-статусом 404 и регистрирует следующие

 WARN osweb.servlet.PageNotFound - No mapping found for HTTP request with URI `[/Example/WEB-INF/jsps/index.jsp]` in `DispatcherServlet` with name 'dispatcher' 

У меня есть ресурс JSP в /WEB-INF/jsps/index.jsp Я ожидал, что Spring MVC будет использовать мой controller для обработки запроса и пересылки в JSP, так почему он отвечает 404?


Это должно быть каноническим сообщением для вопросов об этом предупреждающем сообщении.

Ваше стандартное приложение Spring MVC будет обслуживать все запросы через DispatcherServlet который вы зарегистрировали в своем контейнере Servlet.

DispatcherServlet просматривает свой ApplicationContext и, если доступен, ApplicationContext зарегистрированный с помощью ContextLoaderListener для специальных компонентов, ему необходимо настроить свою логику обслуживания запросов. Эти компоненты описаны в документации .

Вероятно, самые важные, бобы типа HandlerMapping map

входящие запросы обработчикам и список пред- и постпроцессоров (обработчиков-обработчиков) на основе некоторых критериев, детали которых зависят от реализации HandlerMapping . Наиболее популярная реализация поддерживает аннотированные controllerы, но существуют и другие реализации.

В javadoc HandlerMapping далее описывается, как должны выполняться реализации.

DispatcherServlet находит все бобы этого типа и регистрирует их в некотором порядке (может быть настроен). Во время обслуживания запроса DispatcherServlet проходит через эти объекты getHandler и проверяет каждый из них с помощью getHandler чтобы найти тот, который может обрабатывать входящий запрос, представленный как стандартный HttpServletRequest . Начиная с версии 4.3.x, если он не найден, он регистрирует предупреждение, которое вы видите

Не найдено сопоставления для HTTP-запроса с URI [/some/path] в DispatcherServlet с именем SomeName

и либо выбрасывает NoHandlerFoundException либо немедленно передает ответ с кодом статуса 404 Not Found.

Почему DispatcherServlet нашел HandlerMapping который мог бы обрабатывать мой запрос?

Наиболее распространенной реализацией @Controller является RequestMappingHandlerMapping , которая обрабатывает регистрацию @Controller beans как обработчиков (на самом деле их аннотированные методы @RequestMapping ). Вы можете либо объявить компонент этого типа самостоятельно (с помощью @Bean или или другого механизма), либо вы можете использовать встроенные параметры . Эти:

  1. Аннотируйте свой class @EnableWebMvc с помощью @EnableWebMvc .
  2. Объявите член в вашей конфигурации XML.

Как описано выше, оба из них будут регистрировать компонент RequestMappingHandlerMapping (и множество других вещей). Однако HandlerMapping не очень полезен без обработчика. RequestMappingHandlerMapping ожидает некоторые компоненты @Controller поэтому вам нужно также объявить их с помощью методов @Bean в конфигурации Java или объявлениях в конфигурации XML или через компонентное сканирование аннотированных classов @Controller . Убедитесь, что эти компоненты присутствуют.

Если вы получаете предупреждение и 404, и вы правильно настроили все вышеперечисленное, то вы отправляете свой запрос на неправильный URI , который не обрабатывается обнаруженным @RequestMapping аннотированного обработчика @RequestMapping .

Библиотека spring-webmvc предлагает другие встроенные реализации HandlerMapping . Например, Карты BeanNameUrlHandlerMapping

от URL-адресов до bean-компонентов с именами, начинающимися с косой черты (“/”)

и вы всегда можете написать свой собственный. Очевидно, вам нужно будет убедиться, что отправляемый запрос соответствует хотя бы одному из обработчиков обработчика HandlerMapping.

Если вы не неявно или явно не регистрируете какие-либо detectAllHandlerMappings (или если detectAllHandlerMappings true ), DispatcherServlet регистрирует некоторые значения по умолчанию . Они определены в DispatcherServlet.properties в том же пакете, что и class DispatcherServlet . Это BeanNameUrlHandlerMapping и DefaultAnnotationHandlerMapping (что похоже на RequestMappingHandlerMapping но устарело).

отладка

Spring MVC будет регистрировать обработчики, зарегистрированные через RequestMappingHandlerMapping . Например, @Controller like

 @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 должны соответствовать Spring MVC для выбора обработчика.

Другие реализации HandlerMapping регистрируют свои собственные утверждения, которые должны намекать на их сопоставления и соответствующие обработчики.

Аналогичным образом включите ведение журнала Spring на уровне DEBUG, чтобы увидеть, какие регистры Spring Spring регистры. Он должен сообщать, какие аннотированные classы он находит, какие пакеты сканирует и какие компоненты он инициализирует. Если те, которых вы ожидали, отсутствуют, просмотрите конфигурацию ApplicationContext .

Другие распространенные ошибки

DispatcherServlet – это просто типичный Servlet Java EE. Вы регистрируете его с помощью типичного объявления и или напрямую через ServletContext#addServlet в WebApplicationInitializer или с любым механизмом загрузки Spring. Таким образом, вы должны полагаться на логику отображения URL, указанную в спецификации Servlet , см. Главу 12. См. Также

  • Как используются сопоставления url сервлета в web.xml?

Имея это в виду, распространенной ошибкой является регистрация DispatcherServlet с отображением url /* , возrotationм имени представления из @RequestMapping обработчика @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 с именем ‘dispatcher’

Поскольку DispatcherServlet сопоставляется с /* и /* соответствует всем (кроме точных совпадений, которые имеют более высокий приоритет), DispatcherServlet будет выбран для обработки forward из JstlView (возвращенного JstlView InternalResourceViewResolver ). Почти в каждом случае DispatcherServlet не будет настроен для обработки такого запроса .

Вместо этого в этом упрощенном случае вы должны зарегистрировать DispatcherServlet в / , обозначив его как сервлет по умолчанию. Сервлет по умолчанию является последним совпадением для запроса. Это позволит вашему типичному контейнеру сервлетов выбрать внутреннюю реализацию сервлета, сопоставленную с *.jsp , для обработки ресурса JSP (например, Tomcat имеет JspServlet ), прежде чем пытаться использовать сервлет по умолчанию.

Это то, что вы видите в своем примере.

Я разрешил свою проблему, когда в дополнение к описанному ранее:

 @Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver vr = new InternalResourceViewResolver(); vr.setPrefix("/WEB-INF/jsps/"); vr.setSuffix(".jsp"); return vr; } 

added tomcat-embed-jasper:

  org.apache.tomcat.embed tomcat-embed-jasper provided  при  org.apache.tomcat.embed tomcat-embed-jasper provided  ,  org.apache.tomcat.embed tomcat-embed-jasper provided  

`from: JSP-файл не отображается в веб-приложении Spring Boot

Я столкнулся с другой причиной такой же ошибки. Это также может быть связано с файлами classов, не сгенерированными для вашего файла controller.java. В результате чего сервлет диспетчера, упомянутый в web.xml, не может сопоставить его с соответствующим методом в classе controllerа.

 @Controller Class Controller{ @RequestMapping(value="/abc.html")//abc is the requesting page public void method() {.....} } 

В eclipse в Project-> select clean -> Build Project. Дайте проверку, если файл classа был сгенерирован для файла controllerа в строках в вашей рабочей области.

  • Как я могу захватить вывод команды как String с Commons Exec?
  • Кнопка «Отменить назад», чтобы действовать как кнопка «домой»
  • Конкретный способ написания новых classов DialogPreference?
  • Регистрация кнопки гарнитуры с помощью BroadcastReceiver на Android
  • XML-документ для строки?
  • Android с длинным касанием
  • getSearchForm возвращает значение null при использовании UserSearch в XMPP с помощью aSmack
  • Android Microsoft Office Library (.doc, .docx, .xls, .ppt и т. Д.)
  • Упорядочение аргументов String.equals ()
  • Volley - отправка запроса POST с использованием JSONArrayRequest
  • Как читать текстовый файл в Android?
  • Давайте будем гением компьютера.