Почему 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
- Задание полей в LinearLayout программно
- Как изменить стиль TextView во время выполнения
- Завершение программы Java
- Упреждающий базовый аут с HttpUrlConnection?
- Java / Android - Как распечатать полную трассировку стека?
@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?
Это должно быть каноническим сообщением для вопросов об этом предупреждающем сообщении.
- Что означает «| =»? (оператор равных труб)
- Исходные ресурсы по сравнению с базой данных SQLite
- Как запустить программу Java из командной строки в Windows?
- как разобрать JSONArray в android
- Время соединения истекло. Зачем?
- Можно ли использовать Java 8 для разработки Android?
- Центральное сообщение в диалоговом окне андроида
- Разбор JSON для JSON для JSON в JSONObject
Ваше стандартное приложение 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
или
или другого механизма), либо вы можете использовать встроенные параметры . Эти:
- Аннотируйте свой class
@EnableWebMvc
с помощью@EnableWebMvc
. - Объявите член
в вашей конфигурации 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а в строках в вашей рабочей области.