sirve requestmapping que para mvc modelo modelandview formulario español ejemplo arquitectura spring spring-mvc spring-annotations

requestmapping - spring mvc español



ApplicationContext no encuentra controladores para el contexto del servlet (3)

Tengo una aplicación web Spring con una applicationContext.xml y una configuración dispatcher-servlet.xml. Definí <context:component-scan /> en applicationContext.xml, pero cuando ejecuto mi aplicación los Controladores no se encuentran a menos que también agregue <context:component-scan /> al dispatcher-servlet.xml. Estoy usando el mismo paquete base en ambos, así que ese no es el problema.

Estoy confundido porque pensé que applicationContext.xml era un elemento primario de dispatcher-servlet.xml. ¿No bastaría con <context:component-scan /> en applicationContext.xml?

web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>

EDITAR: También estoy usando mvc: anotación-driven en el dispatcher-servlet.xml, que se supone que recoge Controladores (¿pensé?).

EDIT 2: Aquí están los archivos de configuración. Eliminé varias configuraciones de Spring Security y OAuth de applicationContext.xml (por razones de seguridad y, de todos modos, probablemente no sean relevantes).

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <context:component-scan base-package="bar.foo"/> <context:property-placeholder location="classpath:my.properties" /> <bean class="bar.foo.ServicesConfig" /> </beans>

dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <context:component-scan base-package="bar.foo.controller" /> <mvc:annotation-driven/> <mvc:default-servlet-handler /> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> <property name="order" value="2" /> </bean> <bean id="contentViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> <map> <entry key="json" value="application/json" /> </map> </property> <property name="defaultViews"> <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" /> </property> <property name="order" value="1" /> </bean> </beans>

EDIT 3: Bien, esto es interesante. Mis servicios y clases de dao están en un proyecto diferente (JAR) al que hago referencia desde el proyecto web. Estoy usando una configuración basada en Java y haciendo referencia a ella desde la aplicaciónContext.xml:

<bean class="bar.foo.config.ServicesConfig" />

Entonces, esto significa que solo hay anotaciones de Controlador en mi proyecto web (donde se encuentra applicationContext.xml). En retrospectiva, eliminar el contexto: componente-scan de mi applicationContext.xml no debería tener ningún efecto, ya que no hay anotaciones, excepto para @Controller (FIX to EDIT: hay algunas @Autowired annotations). Pero, cuando elimino el contexto: componente-scan de applicationContext.xml, dice que los Controladores (que se encuentran en la exploración del servlet del distribuidor) no pueden encontrar mis clases de servicio. ¿No debería ser suficiente la referencia a ServicesConfig? Aquí está la clase ServicesConfig para referencias: tiene su propia exploración de componente para los Servicios, que son un paquete diferente de lo que la aplicaciónContext.xml estaba escaneando.

@Configuration @ComponentScan({ "some.other.package", "another.package" }) @ImportResource({ "classpath:commonBeans.xml" }) @PropertySource({ "classpath:services.properties", "classpath:misc.properties" }) public class ServicesConfig { // Bean definitions // }

SOLUCIÓN:

Cuando eliminé el contexto: componente-escaneo desde mi contexto raíz, los Controladores no recogían los beans de los servicios de autowired. Esto se debió a que el contexto raíz hace referencia a mis servicios Bean de configuración basada en Java, pero no tenía la configuración de contexto raíz para buscar Componentes. Por lo tanto, cuando agrego escaneo de componentes al contexto raíz (applicationContext.xml) todo funciona. Esto es lo que tengo ahora:

applicationContext.xml:

<bean class="bar.foo.config.ServicesConfig" /> <context:component-scan base-package="bar.foo.config" />

dispatcher-servlet.xml:

<context:component-scan base-package="bar.foo.controller" />

Tengo la configuración de contexto web para recoger el Controlador, el Autocableado y cualquier otra anotación en el paquete del controlador. No estoy seguro de si esto es una buena práctica o no.


En nuestras aplicaciones definimos en el dispatcher-servlet.xml

Creo que es donde se supone que debe estar, más que en applicationContext.xml

Esta sección de la documentación de Spring debe proporcionar más información:

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html

Como se puede ver en uno de los diagramas de la sección 16.2, el servlet despachador se encuentra sobre el applicationContext en la jerarquía de contexto.


Tiene razón: hay dos contextos de aplicación diferentes, el contexto de la aplicación raíz cargado por ContextLoaderListener (en el punto en que se inicializa el ServletContext) y el contexto web (cargado por DispatcherServlet), el contexto de la aplicación raíz es el principal de la Web contexto.

Ahora, dado que estos son dos contextos de aplicación diferentes, actúan de manera diferente: si define component-scan de component-scan para sus servicios en el contexto de la aplicación, entonces todos los beans para los servicios se crean aquí.

Cuando su servlet Dispatcher se carga, comenzará a crear el Contexto Web, en algún momento (impulsado por <mvc:annotation-driven/> creará un mapeo para los métodos de su uri''s handler, obtendrá la lista de beans en la aplicación contexto (que será el contexto de la aplicación web, no el contexto de la aplicación raíz) y dado que no ha definido un component-scan aquí, los beans relacionados con el controlador no se encontrarán y las asignaciones no se crearán, esa es la razón por la que tiene para definir un escaneo de componente también en el contexto de los servlets de despachador.

Una buena práctica es excluir los beans relacionados con el Controlador en el contexto de la aplicación Root:

<context:component-scan base-package="package"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/> </context:component-scan>

y solo uno relacionado con el controlador en el contexto de la aplicación web:

<context:component-scan base-package="package" use-default-filters="false"> <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" /> </context:component-scan>


Tuve el mismo problema y después de comparar mi código web.xml con este tutorial lo cambié y funcionó. aquí está mi archivo web.xml :

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/business-config.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

context-param y listener fueron lo que me perdí.

Espero que te ayude.