14 may. 2013

Integración Vaadin con Spring (Parte 2)

En la entrada de ayer comentaba como integrar Vaadin con Spring, hoy toca lo mismo, pero con la versión 7 de Vaadin.

Al igual que con Vaadin 6 hay que seguir una serie de pasos previos, pero son un poco diferentes gracias a la existencia de la clase UIProvider, así que comencemos con los pasos para conseguir esta integración:


  1. Creación del proyecto maven:
    mvn archetype:generate \
        -DarchetypeGroupId=com.vaadin \
        -DarchetypeArtifactId=vaadin-archetype-application \
        -DarchetypeVersion=7.0.5 \
        -DgroupId=com.javiserrano \
        -DartifactId=vaadin7.spring \
        -Dversion=1.0-SNAPSHOT \
        -Dpackaging=war
    
  2. 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>
    
  3. Modificación del archivo web.xml generado por el arquetipo sustituyéndolo por el siguiente, o bien añadiendo desde la linea 9 a la 18 ambas incluidas y desde la 32 a la 36 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.server.VaadinServlet</servlet-class>
        <init-param>
          <description>Vaadin UI to display</description>
          <param-name>UI</param-name>
          <param-value>com.javiserrano.MyVaadinUI</param-value>
        </init-param>
        <init-param>
          <description>Application widgetset</description>
          <param-name>widgetset</param-name>
          <param-value>com.javiserrano.AppWidgetSet</param-value>
        </init-param>
        <init-param>
          <description>Vaadin UI Provider</description>
          <param-name>UIProvider</param-name>
          <param-value>com.javiserrano.MyUIProvider</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
    
  4. 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>
    
  5. Ahora toca la creación de la clase "Inyectora", que quedará así:
    package com.javiserrano;
    
    import javax.servlet.ServletContext;
    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.WebApplicationContext;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    public class Inject {
    
        public static void inject( Object component )
        {
            ApplicationContext context = getApplicationContext();
            AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
            beanFactory.autowireBeanProperties( component, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false );
        }
    
        private static ApplicationContext getApplicationContext()
        {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            HttpSession session = request.getSession( false );
            ServletContext servletContext = session.getServletContext();
            WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext( servletContext );
            return context;
        }
    }
    
  6. Ahora vamos a crear el UIProvider con el siguiente contenido:
    package com.javiserrano;
    
    import com.vaadin.server.UIClassSelectionEvent;
    import com.vaadin.server.UICreateEvent;
    import com.vaadin.server.UIProvider;
    import com.vaadin.ui.UI;
    
    @SuppressWarnings("serial")
    public class MyUIProvider extends UIProvider {
    
        @Override
        public Class getUIClass(UIClassSelectionEvent event) {
            return MyVaadinUI.class;
        }
    
        @Override
        public UI createInstance(UICreateEvent event) {
            UI instance = super.createInstance(event);
            Inject.inject(instance);
            return instance;
        }
    }
    
  7. 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.
  8. Ahora toca modificar la clase principal, MyVaadinUI, creada automáticamente por el arquetipo para que quede de la siguiente forma:
    package com.javiserrano;
    
    import org.springframework.beans.factory.annotation.Autowired;
    
    import com.vaadin.server.VaadinRequest;
    import com.vaadin.ui.Button;
    import com.vaadin.ui.Button.ClickEvent;
    import com.vaadin.ui.Button.ClickListener;
    import com.vaadin.ui.Notification;
    import com.vaadin.ui.Notification.Type;
    import com.vaadin.ui.UI;
    import com.vaadin.ui.VerticalLayout;
    
    /**
     * The Application's "main" class
     */
    @SuppressWarnings("serial")
    public class MyVaadinUI extends UI implements ClickListener{
        
        @Autowired
        HelloService helloService;
    
        @Override
        protected void init(VaadinRequest request) {
            final VerticalLayout layout = new VerticalLayout();
            layout.setMargin(true);
            setContent(layout);
            Button button = new Button("Click Me");
            button.addClickListener((Button.ClickListener) this);
            layout.addComponent(button);
        }
        
        public void buttonClick(ClickEvent event){
            if (helloService != null){
                Notification.show("The injected service says", helloService.sayHello(), Type.HUMANIZED_MESSAGE);
            }
        }
    
    }
    
  9. Por último, probamos la aplicación ejecutando en un terminal:
    mvn package jetty:run
    
    Abrimos un navegador web y navegamos a http://localhost:8080/vaadin7.spring
Los fuentes los podéis descargar haciendo click en ... vaadin7.spring.zip

Como siempre, un saludo y a disfrutar!

1 comentario:

David Herrera dijo...

Hola Javi, gracias por tu post. Hago referencia a él en la última entrada de mi blog: http://dherrerabits.wordpress.com/2013/07/13/aprendiendo-vaadin-4-agregando-spring/

Me ha resultado muy útil. Gracias y saludos!