Profundizando un poquito más en la integración de estos dos frameworks que tanto me gustan, he visto que hay otras maneras de hacerlo, que además creo que son bastante más simples que la que se ha implementado en el arquetipo, lo cual me obliga a cambiarlo...
La solución pasa por usar una clase "Inyectora", una serie de escuchadores y parámetros de contexto en el archivo web.xml y una configuración mínima de spring que permita el "Autowiring" de las dependencias de modo transparente, ahora bien, esta integración es ligeramente diferente entre las dos últimas versiones mayores disponibles de Vaadin, en este primer post me centraré en la integración de la versión 6 de Vaadin.
Para la realización de esta integración, seguiremos los siguientes pasos:
- Creación del proyecto maven:
mvn archetype:generate \ -DarchetypeGroupId=com.vaadin \ -DarchetypeArtifactId=vaadin-archetype-clean \ -DarchetypeVersion=LATEST \ -DgroupId=com.javiserrano \ -DartifactId=vaadin6.spring \ -Dversion=1.0-SNAPSHOT \ -Dpackaging=war - Adición de las dependencias de spring al archivo pom generado en la ejecución del punto anterior:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.2.2.RELEASE</version> </dependency>
- Modificación del archivo web.xml generado por el arquetipo añadiendo desde la linea 9 a la 22 ambas incluidas, quedando de la siguiente manera:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Vaadin Web Application</display-name> <context-param> <description>Vaadin production mode</description> <param-name>productionMode</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/context.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <servlet> <servlet-name>Vaadin Application Servlet</servlet-name> <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class> <init-param> <description>Vaadin application class to start</description> <param-name>application</param-name> <param-value>com.javiserrano.MyVaadinApplication</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Vaadin Application Servlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> - Debemos crear el archivo context.xml en la carpeta src/main/webapp/WEB-INF/spring con el siguiente contenido:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:annotation-config /> <context:component-scan base-package="com.javiserrano" /> </beans> - Ahora toca la creación de la clase "Inyectora", que quedará así:
package com.javiserrano; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.support.WebApplicationContextUtils; import com.vaadin.Application; public class Inject { static Application application; static ApplicationContext applicationContext; public static void inject( Object object ) { if ( applicationContext == null ) { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); HttpSession session = request.getSession( false ); applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext( session.getServletContext() ); } AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory(); beanFactory.autowireBeanProperties( object, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false ); } } - Ahora vamos a crear la ventana principal con el siguiente contenido:
package com.javiserrano; import org.springframework.beans.factory.annotation.Autowired; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Window; import com.vaadin.ui.Button.ClickListener; @SuppressWarnings ( "serial" ) public class MyWindow extends Window implements ClickListener { @Autowired HelloService helloService; public MyWindow(String caption) { super(caption); Inject.inject(this); Button button= new Button("Click me!", (Button.ClickListener)this); addComponent(button); } public void buttonClick(ClickEvent event){ if (helloService != null){ showNotification("The injected service says", helloService.sayHello(), Notification.TYPE_HUMANIZED_MESSAGE); } } } - Ahora vamos a crear el servicio HelloService con el siguiente contenido:
package com.javiserrano; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; @Service @Scope("prototype") public class HelloService { public String sayHello() { return "Hello Vaadiners from a Spring Service!!!"; } }NOTA: Es importante que todo aquello que queramos inyectar vía Spring tenga las anotaciones @Service o @Component para que Spring sea capaz de detectarlas e inyectarlas automáticamente.
- Ahora toca modificar la clase principal, MyVaadinApplication, creada automáticamente por el arquetipo para que quede de la siguiente forma:
package com.javiserrano; import com.vaadin.Application; /** * The Application's "main" class */ @SuppressWarnings("serial") public class MyVaadinApplication extends Application { private MyWindow window; @Override public void init() { window = new MyWindow("My Vaadin + Spring Application"); setMainWindow(window); } } - Por último, probamos la aplicación ejecutando en un terminal:
mvn clean install jetty:run
Abrimos un navegador web y navegamos a http://localhost:8080/vaadin6.spring
Espero que os simplifique la integración de estos dos frameworks, como me la ha simplificado a mi.
Como siempre, un saludo y a disfrutar!
2 comentarios:
Genial post. Gracias!
Gracias a ti David!
Publiqué también la integración para la versión 7... creo que es mucho más limpia.
Un saludo!
Publicar un comentario