Spring Web Flows

En esta ocasión, les mostraremos cómo configurar los Spring Web Flows.

Estos son una gran herramienta para esos casos donde una aplicación web debe tomar el control de un flujo, llevando al usuario de la mano paso a paso a través de la aplicación. Un ejemplo clásico sería un proceso de cobro en una tienda virtual.

Spring Web Flow es una extensión de Spring MVC que permite el desarrollo de aplicaciones web basadas en flujos. Esto es posible, gracias a que la definición de una aplicación está separada de las clases y vistas que implementan el comportamiento del flujo.

Proceso de instalación, configuración e implementación:

Instalación

La instalación se la encargamos al Maven. Para ello es necesario tener las siguientes dependencias en nuestro pom.xml:
 
            org.springframework.webflow
            spring-webflow
            2.4.0.BUILD-SNAPSHOT
        
        
            org.springframework
            spring-expression
            4.0.0.WEBSOCKET-SNAPSHOT
        
        
            org.springframework.webflow
            spring-binding
            2.4.0.BUILD-SNAPSHOT
        
        
            org.springframework.webflow
            spring-js
            2.4.0.BUILD-SNAPSHOT
        

Configuración

A continuación, es necesario configurar el namespace en el archivo de configuración de Spring:
 



Una vez hechas estas configuraciones estamos listos para trabajar con los Spring Web Flows.
Ahora, es necesario crear un archivo xml que contendrá todas las definiciones de flujos y las hará disponibles al componente encargado de ejecutar los flujos.

    
        
    

    
        

     
    
    
       
    
    
        
    
    
    
    
        
        
    

Implementación

A continuación, creamos las clases java con las cuales estará interactuando el Web Flow. Solo mostraremos la anotación necesaria de Spring para cada clase:
@Entity(name = "informeProveedorDao")

donde "informeProveedorDao" sería el nombre de la clase a utilizar en la definición de los componentes del flujo (el cual se mostrará más adelante)
La configuración necesaria para la capa "Service" es:
@Service("informeProveedorManager")

donde "informeProveedorManager" sería el nombre de la clase a utilizar en la definición de los componentes del flujo (el cual se mostrará más adelante)
Nota: Hasta aquí se configurara lo necesario para que el flow se comunique bien con las capas necesarias, es tu responsabilidad que el manager (service) tenga una buena conexión con el Dao para el acceso a datos.

Ahora, se muestra el archivo xml que define los flujos. Este archivo contiene diversos componentes que le indican al Spring las distintas partes del flow:


  
      
      


 
   
        

            
        

        
    


 
  


            

        
    
   

  
        


            
        

        
    

        

    
        
    

Finalmente, es necesario crear una clase que extienda a MultiAction. A través de esta implementación podemos tener acceso al flujo en ejecución, las variables y objetos en memoria, y por supuesto comunicarse con la capa Service y Dao.
//Aqui especificamos que el objeto es un coponente de Spring
@Component
//la clase debe de extender de multiaction y el nombre que se le asigna es con el que se mapeara en el flow
public class InformeProveedorAction extends MultiAction {
//este es el metodo que graba un informe, por default el metodo recibira el contexto.
public Event creaInforme(RequestContext context) {
   Usuario usuario = ambiente.obtieneUsuario();
//De esta forma se obtiene el informe del flow       
 InformeProveedor informeProveedor = (InformeProveedor) context.getFlowScope().get("informeProveedor");
        log.debug("informeEmpleadoAction{}", informeProveedor);
        informeProveedor.setEmpleado(usuario);
//aqui se llama al manager y graba el informe
        instance.crea(informeProveedor, usuario);
//se envia el id del informe a la memoria del flow
        context.getFlowScope().put("informeEmpleadoId", informeProveedor.getId());
        return success();}

   public Event crearDetalle(RequestContext context) throws AutorizacionCCPlInvalidoException, IOException {
// Como se grabaran archivos declaro una lista de tipo MultipartFiles y una lista de Strign de los nombres
        List files = new ArrayList<>();
        List fileNames = new ArrayList();
// Obtendo el detalle 
        InformeProveedorDetalle informeProveedorDetalle = (InformeProveedorDetalle) context.getFlowScope().get("informeProveedorDetalle");
//se agregan los archivos del detalle a la lista
        files.add(informeProveedorDetalle.getFile());
        files.add(informeProveedorDetalle.getFile2());
// se obtiene el id del informe para asignarselo al detalle
        Long id = (Long) context.getFlowScope().get("informeEmpleadoId");
        InformeProveedor informeProveedor = instance.obtiene(id);
        informeProveedorDetalle.setInformeProveedor(informeProveedor);
        log.debug("informeProveedorDetalleAction{}", informeProveedorDetalle);
//se crea el el detalle
        detalleManager.crea(informeProveedorDetalle, usuario);
//para guardar los archivos se usa la fecha por eso se declara el calendar
        Calendar calendar = GregorianCalendar.getInstance();
        int año = calendar.get(Calendar.YEAR);
        int mes = calendar.get(Calendar.MONTH);
        int dia = calendar.get(Calendar.DATE);
        String nombre = context.getExternalContext().getCurrentUser().getName();
//se guardan los archivos
        if (null != files && files.size() > 0) {
            for (MultipartFile multipartFile : files) {
                String fileName = multipartFile.getOriginalFilename();
                fileNames.add(fileName);
                String uploadDir = "/home/facturas/" + año + "/" + mes + "/" + dia + "/" + nombre + "/" + multipartFile.getOriginalFilename();
                File dirPath = new File(uploadDir);
                if (!dirPath.exists()) {
                    dirPath.mkdirs();
                }
                multipartFile.transferTo(new File("/home/facturas/" + año + "/" + mes + "/" + dia + "/" + nombre + "/" + multipartFile.getOriginalFilename()));
                if (multipartFile.getOriginalFilename().contains(".pdf")) {
                    informeProveedorDetalle.setPathPDF("/home/facturas/" + año + "/" + mes + "/" + dia + "/" + nombre + "/" + multipartFile.getOriginalFilename());
                    informeProveedorDetalle.setNombrePDF(multipartFile.getOriginalFilename());
                }
                if (multipartFile.getOriginalFilename().contains(".xml")) {
                    informeProveedorDetalle.setPathXMl("/home/facturas/" + año + "/" + mes + "/" + dia + "/" + nombre + "/" + multipartFile.getOriginalFilename());
                    informeProveedorDetalle.setNombreXMl(multipartFile.getOriginalFilename());
                }
            }
        }
        return success();

    }
// termina el multiaction
}
Finalmente, es necesario conocer cómo se configuran los flows en el jsp.
Para que Spring reconozca y ejecute el flow basta con escribir el nombre de las carpetas donde está guardado el archivo xml que define los flows.
Para este caso en particular, es necesario escribir: /facturas/empleado justo después del nombre del contexto. Es decir, http://locahost:8080/MiWebFlow/facturas/empleado.

En cuanto Spring detecta que se ha ingresado a un Web Flow, ejecuta el primer componente definido en el archivo xml


mostrándose por consiguiente el contenido del jsp 'informeProveedor/lista.jsp'.
Una vez que el flujo ha iniciado, los jsp's indican cuál es el siguiente paso a ejecutar en el flujo con la siguiente instrucción:

En el caso de de link:
Nuevo Informe

En el caso de un submit:


...


donde 'nuevoInformeProveedor' es el nombre de un componente 'view-state' definido en el archivo xml.

Referencias

  1.  http://duckranger.com/2010/12/display-a-generated-pdf-from-within-spring-webflow/
  2.  http://www.springbyexample.org/examples/spring-web-flow-subflow-webapp.html
  3.  http://docs.spring.io/spring-webflow/docs/2.3.2.RELEASE/reference/htmlsingle/spring-webflow-reference.html#el-variables
  4.  http://xpadro.blogspot.mx/2013/04/communication-in-spring-webflow-2.html
  5.  http://docs.spring.io/spring-webflow/docs/2.3.2.RELEASE/reference/htmlsingle/spring-webflow-reference.html#el-variables
Publicado por: Samuel Martínez Serafín. Alumno de Ingeniería en Sistemas Computacionales, el 27 de Noviembre de 2013.
Editado por: Ing. Omar O. Soto Romero. Líder de Proyectos.

Comentarios

Entradas populares de este blog

Batch File como Servicio de Windows

Cómo crear archivos XML en Java con JAXB

Ejecutando Jetty como un Servicio en Windows Server 2012