Primeros pasos con Spring Web Flow 2

2
42120

Primeros pasos con Spring Web Flow 2

0. Índice de contenidos.

1. Entorno

Este tutorial está desarrollado usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 2Ghz Intel Core i7 (4 núcleos) 8Gb de RAM
  • Sistema Operativo: Mac OS X 10.7.2 (Lion)
  • Eclipse Indigo (Revisar tutorial de Alex para su instalación)
  • Apache Tomcat 7
  • Versión de java SDK 6 instalada en el sistema
  • Maven3 instalado y configurado en el sistema

2. Introducción

En este tutorial veremos como hacer un ejemplo básico de Spring Web Flow, además de ver a grandes rasgos la arquitectura del framework.

3. Arquitectura. Definiciones

Spring Web Flow nos permite definir flujos de negocio para nuestras aplicaciones web. Un flujo de negocio sigue el proceso de una máquina de estados, en el que siempre hay un estado inicial y un estado final:

Máquina de estados

En la que siempre hay un estado de inicio, un estado fin y estados intermedios.
La transición entre estados se realiza por eventos; Por ejemplo, un evento podría ser enviar un parámetro http get, que desencadenaría una transición, que es el proceso desde el cual se pasa de un estado a otro.

Spring Web Flow sigue la misma semántica, es decir existen definiciones dentro de cada flujo para establecer los estados y las transiciones entre estos.

Las ventajas que representa crear flujos es fundamentalmente la reulización para aplicaciones diferentes pero con procesos de negocio parecidos, simplemente intercambiando la parte de negocio y la parte de vista, podemos realizar rápidamente flujos reutilizables.
Adicionalmente el diseño de flujos de navegación en aplicaciones web pasa a estar centralizado, con lo que la logica de interacción entre las vistas es mucho mas sencilla.

Spring Web Flow utiliza Spring MVC para gestionar las transiones entre las vistas siguiendo la siguiente arquitectura:

Arquitectura

Identificando cada uno de los componentes:

  • DispatcherServlet: servlet que maneja las peticiones de los clientes, incluyendo las peticiones dentro de un flujo.
  • FlowController: controlador de SpringMVC proporcionado por Spring Web Flow (no tenemos que implementarlo), envia las peticiones a FlowExecutor para su ejecución.
  • FlowExecutor: ejecuta los flujos y maneja la lógica de transición entre estados.
  • FlowRegistry: carga, construye y mantiene las definiciones de los flujos. Utiliza FlowBuilderServices para construir flujos.
  • FlowBuilderServices: contenedor simple para los servicios necesitados durante el proceso de construcción del flujo, así como la creación de factorías de vista con el componente ViewFactoryCreator.
  • ViewFactoryCreator: crea factorias de vista. MvcViewFactoryCreator crea factorias de vista de Spring MVC.
  • ViewResolver: mapea los nombres lógicos de vista a los recursos físicos(por ejemplo jsps).

Ahora ya que hemos visto la arquitectura y los elementos básicos que la componen, estamos preparados para comenzar el ejemplo.

4. Creación y configuración de proyecto

Crearemos un nuevo proyecto maven3 con la siguiente estructura:

Estructura de proyecto maven

Ahora crearemos el pom.xml, en el cual nuestro objetivo será crear un paquete WAR para desplegarlo en Tomcat, y definir las dependencias con las librerías necesarias para trabajar con SpringWebFlow:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.autentia</groupId>
	<artifactId>TutorialSWF</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>TutorialSWF</name>
	<url>http://www.autentia.com</url>
	<dependencies>
		<dependency>
			<groupId>org.springframework.webflow</groupId>
			<artifactId>org.springframework.webflow</artifactId>
			<version>2.3.0.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.webflow</groupId>
			<artifactId>org.springframework.faces</artifactId>
			<version>2.3.0.RELEASE</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>TutorialSWF</finalName>
	</build>
	<repositories>
		<repository>
			<id>com.springsource.repository.bundles.release</id>
			<name>SpringSource Enterprise Bundle Repository - SpringSource Releases</name>
			<url>http://repository.springsource.com/maven/bundles/release</url>
		</repository>

		<repository>
			<id>com.springsource.repository.bundles.external</id>
			<name>SpringSource Enterprise Bundle Repository - External Releases</name>
			<url>http://repository.springsource.com/maven/bundles/external</url>
		</repository>
	</repositories>
</project>

El siguiente paso es la configuración de Spring MVC dentro del web.xml, para que atienda todas las peticiones .do:

<?xml version="1.0" encoding="UTF-8"?>  
<web-app xmlns="http://java.sun.com/xml/ns/javaee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
    version="2.5">
	<display-name>Archetype Created Web Application</display-name>
	<servlet>
		<!-- Automáticamente inicializa el contexto spring con el formato servlet-name=nombre-servlet.xml -->
		<servlet-name>prueba</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!--  
		La alternativa de inicialización de spring MVC es mediante un init-param como se describe 
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/prueba-servlet.xml</param-value>
		</init-param>-->
	</servlet>

	<servlet-mapping>
		<servlet-name>prueba</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

Ahora definimos el contexto de spring en nuestro archivo prueba-servlet.xml:

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:webflow="http://www.springframework.org/schema/webflow-config"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/jee 
        http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/webflow-config
        http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
	<mvc:annotation-driven/>
	<context:annotation-config/>
    <context:component-scan base-package="com.autentia"/>
    <!-- Mapea las peticiones de flujo desde el DispatcherServlet al FlowController y seguimos el flujo de declaracion de la arquitectura -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>inicio.do=flowController</value>
        </property>
        <property name="alwaysUseFullPath" value="true"/>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <bean id="flowController" class="org.springframework.webflow.mvc.servlet.FlowController">  
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>  
    <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"/>      
    <!-- Registramos todos nuestros flujos con la dupla id-xml -->
    <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">  
       		<webflow:flow-location id="inicio" path="/WEB-INF/flujos/flujo.xml"/>  
    </webflow:flow-registry>    
    <webflow:flow-builder-services id="flowBuilderServices"  
            view-factory-creator="viewFactoryCreator"/>  
    <bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">  
        <property name="viewResolvers">  
            <list>  
                <ref bean="viewResolver"/>  
            </list>  
        </property>  
    </bean>
    <!-- Mapea a nombres logicos de vista to recursos fisicos -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>   
</beans>

5. Definición de un flujo simple

Trabajaremos con el siguiente flujo, donde existirán los estados básicos de inicio-fin y un estado intermedio. Como eventos de cambio de estado utilizaremos parámetros get.

Flujo ejemplo

6. Creación del flujo

Ahora crearemos el archivo de configuración de nuestro flujo:

<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="inicio">
    <view-state id="inicio" view="inicio">
		<transition on="ok1" to="intermedio"></transition>
	</view-state>
	<view-state id="intermedio" view="medio">
		<transition on="ok2" to="fin"></transition>
	</view-state>
	<end-state id="fin" view="final">
	</end-state>
</flow>

Como podemos ver cada estado contiene dos atributos, uno es el identificador del estado (id) y el otro la vista (view). Recordad que en la configuración del viewresolver mapeamos las rutas virtuales a rutas fisicas, por ejemplo, en el caso de inicio, existirá una jsp en /WEB-INF/jsp/inicio.jsp, lo que aparece en negrita lo establece la congiruación de la que hablamos.

También podemos ver la declaración de las transiciones con dos parámetros, el evento (on), y el id del estado al que nos dirigiremos (to).

7. Creación de las vistas

Una vez definida toda la configuración, pasamos al desarrollo de las tres jsp de vista (una por cada estado):

inicio.jsp
----------
<html>
<body>
<h2>Inicio</h2>
<a href="${flowExecutionUrl}&_eventId=ok1">Pasar al siguiente estado</a>
</body>
</html>
medio.jsp
----------
<html>
<body>
<h2>Intermedio</h2>
<a href="${flowExecutionUrl}&_eventId=ok2">Pasar al siguiente estado</a>
</body>
</html>
final.jsp
----------
<html>
<body>
<h2>Fin Flujo!</h2>
</body>
</html>

8. Resultado

Una vez creados todos los componentes, solo tenemos que abrir la linea de comandos y ejecutar mvn clean package, que nos generará un WAR en el directorio target de nuestro proyecto. Este WAR lo copiamos en la ruta de webapps de Tomcat 7: <TOMCAT-HOME>/webapps

Si todo ha ido correctamente, abriendo en un navegador la url http://localhost:8080/TutorialSWF/inicio.do podremos seguir el siguiente flujo:

Estado inicial

Estado intermedio

Estado final

9. Conclusiones

Con este ejemplo hemos aprendido una forma simple y rápida de crear una aplicación básica basada en SpringWebFlow. Mas adelante en otros tutoriales seguiremos profundizando sobre cada uno de los puntos clave del framework.

Cualquier duda o sugerencia podeis comentarlo.

Saludos.

2 COMENTARIOS

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad