Aprendiendo Vaadin #4: Agregando Spring

Gestor de proyectosLlevaba tiempo buscando una forma de poder desarrollar una aplicación RIA sin tener que sufrir una dura curva de aprendizaje, aprovechando mis conocimientos de Java y obteniendo unos resultados suficientemente buenos. De primeras, GWT me pareció una buena opción, pero después descubrí Vaadin, que bajo mi punto de vista va un paso más allá y me convenció mucho más. En esta serie de entradas compartiré mis primeras experiencias con este framework.

En mi anterior post sobre Vaadin mostré cómo crear un proyecto desde cero usando Eclipse, Maven y Tomcat. Creo que un buen siguiente paso sería incorporar Spring a la solución.

Parto desde cero: para este proyecto estoy estrenando Eclipse Kepler en su versión Eclipse IDE for Java Developers. En casos como este (cuando estás aprendiendo o desarrollando proyectos experimentales) recomiendo usar las últimas versiones de las herramientas. En el trabajo ya es otra historia y no siempre es lo mejor estar a la última.

Para crear el proyecto Maven para la versión 7 de Vaadin me guiaré por las recomendaciones de Javi Serrano, un muy buen colega de profesión, que podemos ver en este post de su blog. La solución propuesta consiste, según las propias palabras de Javier, en 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. Por tanto creamos un nuevo proyecto Maven desde Eclipse, y en la pantalla de selección de arquetipo añadimos el arquetipo vaadin-archetype-application a nuestro repositorio Local (este paso no es necesario, es cuestión personal) pulsando “Add Archetype…” y usando esta información:

AddArchetype

Al paquete del proyecto lo he llamado com.dherrerabits.aprendiendovaadin, y al proyecto AprendiendoVaadinAgregandoSpring. El nombre del paquete es relevante pues después modificaremos el archivo web.xml y lo usaremos en él. Una vez generado el proyecto agregamos las dependencias de Spring al pom:

spring-dependency

Ahora modificamos el archivo web.xml sustituyéndolo por el siguiente:

<?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.dherrerabits.aprendiendovaadin.MyVaadinUI</param-value>
    </init-param>
    <init-param>
      <description>Application widgetset</description>
      <param-name>widgetset</param-name>
      <param-value>com.dherrerabits.aprendiendovaadin.AppWidgetSet</param-value>
    </init-param>
    <init-param>
      <description>Vaadin UI Provider</description>
      <param-name>UIProvider</param-name>
      <param-value>com.dherrerabits.aprendiendovaadin.MyUIProvider</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>Vaadin Application Servlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

A continuación creamos el archivo context.xml en la ruta “src/main/webapp/WEB-INF/spring“:

<?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.dherrerabits.aprendiendovaadin" />
</beans>

El siguiente paso, como muy bien nos explica Javi Serrano en su blog, será crear la clase inyectora:

package com.dherrerabits.aprendiendovaadin;

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;
    }
}

A continuación creamos la clase UIProvider a la que llamaremos MyUIProvider:

package com.dherrerabits.aprendiendovaadin;

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;
    }
}

Siguiendo los pasos de Javi, creamos el servicio HelloService:

package com.dherrerabits.aprendiendovaadin;

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!!!";
    }
}

Y a continuación modificamos la clase MyVaadinUI que se creó automáticamente, con el objetivo de que use el servicio recién creado quedando así:

package com.dherrerabits.aprendiendovaadin;

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);
        }
    }
 
}

A continuación, tal como nos indica Javi en su blog, es posible probar la aplicación usando el comando “mvn package jetty:run”. Yo personalmente no soy muy amigo del command prompt y ejecutaré el mismo comando para probar, pero desde eclipse:

jetty-run

Y ya podemos probar usando la URL: http://localhost:8080/AprendiendoVaadinAgregandoSpring

Pues bien, para continuar por donde me había quedado en anteriores posts, ahora incluiré Tomcat en Eclipse (aunque no des-recomiendo en absoluto usar Jetty para desarrollar, es más bien una opción personal). En la distro de Eclipse que he elegido no están incluidas las “Web Tools Platform”, así que las instalaré a continuación:

wtp

No es mi intención explicar aquí cómo instalar Tomcat en Eclipse. Eso ya está más que documentado en la web. Ahora convertimos el proyecto en un proyecto web, tal como expliqué en mi anterior post y finalmente tenemos en marcha un proyecto funcionando con las siguientes tecnologías: Eclipse, Maven, Tomcat, Spring y Vaadin 7.

Llegados a este punto es el momento ideal para generar el correspondiente arquetipo de Maven usando la sentencia mvn archetype:create-from-project. Automáticamente se nos generará un arquetipo a partir del proyecto que hemos creado, y se guardará en target. Para poder usar el arquetipo, deberá estar instalado en nuestro repositorio con lo que ejecutamos un mvn install desde target/generated-sources/archetype.
Ahora ya podemos crear un nuevo proyecto usando el arquetipo, desde Eclipse, File->New->Other…->Maven->Maven Project, en la pantalla de selección de arquetipo será importante pulsar el check Include snapshot archetypes, pues de la forma en la que hemos generado el arquetipo se habrá instalado en versión snapshot, y una vez generado el proyecto mediante Maven, habremos conseguido crear muy fácil y rápidamente un proyecto web eclipse con Maven, Spring y Vaadin 7.

Puedes descargar el código fuente de este ejemplo aquí.

Anuncios

Aprendiendo Vaadin #3: Usando Eclipse, Maven y Tomcat

Gestor de proyectosLlevaba tiempo buscando una forma de poder desarrollar una aplicación RIA sin tener que sufrir una dura curva de aprendizaje, aprovechando mis conocimientos de Java y obteniendo unos resultados suficientemente buenos. De primeras, GWT me pareció una buena opción, pero después descubrí Vaadin, que bajo mi punto de vista va un paso más allá y me convenció mucho más. En esta serie de entradas compartiré mis primeras experiencias con este framework.

En mi anterior post sobre Vaadin expliqué cómo crear un entorno de desarrollo Vaadin usando Eclipse y Maven, y como servidor Jetty. Aunque esta configuración es válida, no me termina de convencer. Me parece mucho más cómodo usar un servidor Tomcat integrado en Eclipse para ejecutar y hacer debug. En la documentación no he encontrado apenas nada al respecto. Para cubrir este hueco, veamos la forma de conseguir esto:

Parto de la suposición de que ya tenemos un servidor Tomcat v6 (ó 7) integrado en Eclipse (Juno o Indigo). Evolucionaremos el proyecto Maven AprendiendoVaadinConMaven. Lo mejor será hacer una copia exacta del proyecto original y llamarlo AprendiendoVaadinConMavenYTomcat. Si hacemos memoria, la estructura del proyecto creado será:

estructura_proyecto

El siguiente paso será convertir el proyecto creado en un proyecto web que podamos añadir al servidor Tomcat desde Eclipse. Para ello, usando el botón derecho del ratón sobre el proyecto entraremos a sus propiedades y accedemos a la opción “Project Facets”, y pulsamos en “Convert to faceted form…”. A continuación seleccionamos “Dynamic Web Module” y la versión 2.4:

facet

En este momento nos aparecerá el mensaje/enlace: Further configuration available…. Es necesario pinchar en él para cambiar la carpeta de contenido por defecto, en lugar de “WebContent” colocaremos “src/main/webapp”:

further-configuration

Tras pulsar OK, ya tenemos el proyecto en formato web y es posible agregarlo al servidor Tomcat integrado en Eclipse, pero en estos momentos, si lo ejecutamos, no funcionará. Para hacerlo funcionar es necesario incluir la dependencias Maven en la sección Deployment Assembly. Para ello volvemos a entrar en las propiedades del proyecto, pulsamos en “Deployment Assembly” y hacemos 2 cosas: primero eliminar “src/test/java” pues no lo vamos a necesitar, y segundo añadir las dependencias de Maven pulsando en Add -> Java Build Path Entries -> Maven Dependencies. Debe quedar así:

deployment-assembly

Y ahora sí, tras actualizar todo y hacer un Build, ya es posible añadir el proyecto web al servidor Tomcat integrado en Eclipse y ejecutar o hacer debug, y ya queda todo listo para usar el mismo ejemplo de los post anteriores, con Maven y el servidor Tomcat integrado en Eclipse.

Puedes descargar el código fuente de este ejemplo aquí.