Spring WebFlow - Parte 2

Con anterioridad se ha explicado como configurar los WebFlows en Spring.
Si aun no haz configurado Spring para usar WebFlows te recomendamos ver el post Spring Web Flows. En este post veremos los diferentes estados de los Web Flows y las variables para usar correctamente los Web flows en Spring.

Estados y etiquetas


Empecemos con los estados. Los Web Flows tienen 3 estados principales:

* view-state
* action-state
* end-state

El view-state, es donde mostraremos una vista al usuario, en esta vista, el usuario tendra las opciones que nosotros querramos ofrecerle. Este estado tiene 3 atributos, "id" sera el nombre del estado, "view" la direccion del jsp que se utilizara en esta vista, "model" en caso que le pasemos un objeto a este estado, o que vayamos a llenar algun objeto.

El action-state, es un estado en el cual el flow ejecutara cierto metodo. Este metodo puede ser ya sea para traer datos de la base de datos, llenar un objeto, validar algo, etc, lo que ustedes quieran hacer. Solamente tiene el atributo id.

El end-state, es un estado donde se termina el flow. Con este estado le decimos a Spring, que este ciclo ya fue terminado y puede empezar un nuevo ciclo.

Todos los estados pueden utilizar las siguientes etiquetas.

La etiqueta evaluate expression, permite correr cualquier metodo.

La etiqueta "transition on", con esta etiqueta le decimos al flow a que estado se va a dirigir al momento que el estado actual devuelva un succes, o que el usuario realice determinada accion. Este estado puede contener otra etiqueta llamada evaluate expression, donde le decimos que corra determinado metodo antes de efectuar la transicion.

La etiqueta "transition on exception", correra determinado estado, en caso de lanzar la excepcion dada.

La etiqueta "on-render", correra un determinado metodo al estar cargando una vista. Esta etiqueta solo se usa en los view-state.

Variables

Las variables se declararan con la etiqueta "var" al inicio del flow. Esta etiqueta tiene como atributos, "name" que sera el nombre de la variable y "class" que sera el tipo de la variable, aqui se debe de poner toda la direccion de la clase.

Ejemplo
A continuacion veremos un ejemplo sencillo para entender lo que dijimos con anterioridad.
Este es el codigo del flow.
<?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" >
    
   <var name="informeProveedor" class="mx.edu.um.mateo.contabilidad.facturas.model.InformeProveedor"/>    
    <var name="informeProveedorDetalle" class="mx.edu.um.mateo.contabilidad.facturas.model.InformeProveedorDetalle"/>    
    <var name="rfcProveedor" class="java.lang.String"/>
    <var name="archivosPdfXml" class="mx.edu.um.mateo.contabilidad.facturas.model.ArchivosPdfXml"/> 
    <var name="uploadOtros" class="mx.edu.um.mateo.contabilidad.facturas.model.ArchivosPdfXml"/> 
    <var name="datosFacturaConfirmar" class="mx.edu.um.mateo.contabilidad.facturas.model.DatosFacturaConfirmar"/>
    <var name="concepto" class="java.lang.String"/>
   
    
    
    
    <view-state id="listaInformes" view="/WEB-INF/jsp/factura/informeProveedor/listaEmp.jsp">
        <on-render>
            <evaluate expression="informeProveedorManager.getInformesEmpleado(externalContext.sessionMap.empresaId)" result="requestScope.informes"/>
        </on-render>
        <transition on="crearInformeProveedor" to="traepermisos"/>  
    </view-state>
    
   
    <action-state id="traepermisos">
        <evaluate expression="informeProveedorAction.getPermisos" />
        <transition to="nuevoInformeProveedor"/>       
    </action-state>
    
    <view-state id="nuevoInformeProveedor" view="/WEB-INF/jsp/factura/informeProveedor/nuevoEmp.jsp" model="informeProveedor">
        <transition on="grabaInforme" to="seleccionaConcepto">
            <evaluate expression="informeProveedorAction.creaInforme" />
        </transition>
    </view-state>
    
    <view-state id="seleccionaConcepto" view="/WEB-INF/jsp/factura/informeProveedorDetalle/selectConcepto.jsp">
        <transition on="transporte" to="transporte"/>
        <transition on="comida" to="comida"/>
        <transition on="hospedaje" to="hospedaje"/>
        <transition on="otros" to="otros"/>
    </view-state>
    
    <action-state id="transporte">
        <evaluate expression="informeProveedorAction.agregarConcepto" />
        <transition to="crearDetalle"/>
    </action-state>
    
    <action-state id="comida">
        <evaluate expression="informeProveedorAction.agregarConcepto" />
        <transition to="crearDetalle"/>
    </action-state>
    
    <action-state id="hospedaje">
        <evaluate expression="informeProveedorAction.agregarConcepto" />
        <transition to="crearDetalle"/>
    </action-state>
    
    <action-state id="otros">
        <evaluate expression="informeProveedorAction.agregarConcepto" />
        <transition to="crearDetalle"/>
    </action-state>
    
    <action-state id="crearDetalle">
        <evaluate expression="informeProveedorAction.crearDetalle" />
    <transition to="firstAsk"/>  
    </action-state>
    
    <view-state id="firstAsk" view="/WEB-INF/jsp/factura/informeProveedorDetalle/firstAsk.jsp">
        <transition on="XMLPDF" to="subirPDF"/>
        <transition on="otherFile" to="otherFile"/>  
    </view-state>
    
    <view-state id="subirPDF" view="/WEB-INF/jsp/factura/informeProveedorDetalle/uploadFileEmp.jsp" model="archivosPdfXml">
        <transition on ="sube" to = "validandoPDF"/>
        <transition on="cancel" to="firstAsk" bind="false"/>      
    </view-state>
 
    <action-state id="validandoPDF">
        <evaluate expression="informeProveedorAction.uploadPdf"/>
        <transition on-exception="mx.edu.um.mateo.general.utils.NoTypeFileException" to="subirPDF" />
        
        
        <transition to="subirXML"/>
    </action-state>
    
    <view-state id="subirXML" view="/WEB-INF/jsp/factura/informeProveedorDetalle/uploadFileEmp.jsp" model="archivosPdfXml">
        <transition on ="sube" to = "validandoXML"/>
        <transition on="cancel" to="firstAsk" bind="false"/>      
    </view-state>
    
    <action-state id="validandoXML">
        <evaluate expression="informeProveedorAction.uploadPdf"/>
        <transition on-exception="mx.edu.um.mateo.general.utils.NoTypeFileException" to="subirXML" />
        <transition to="archivoCorrecto">
            <evaluate expression="informeProveedorAction.leerxml"/>
        </transition>
    </action-state>

    <view-state id="archivoCorrecto" view="/WEB-INF/jsp/factura/informeProveedorDetalle/mostrar_xml.jsp" model="informeProveedorDetalle">
        <transition on="aceptar" to="addFile">
            <evaluate expression="informeProveedorAction.guardardetalle"/>
        </transition>
        <transition on-exception="mx.edu.um.mateo.general.utils.FacturaExisteException" to="subirPDF" />
        <transition on-exception="org.springframework.transaction.UnexpectedRollbackException" to="facturaRepetida" />
        <transition on="cancelar" to="subirPDF"/> 
    </view-state>
    
    <view-state id="facturaRepetida" view="/WEB-INF/jsp/factura/informeProveedor/facturaRepetida.jsp">
        <transition on="subirPDF" to="subirPDF"/>
        <transition on="no" to="listaInformes"/>
    </view-state>
    
    <view-state id="otherFile" view="/WEB-INF/jsp/factura/informeProveedorDetalle/uploadFileEmpOtros.jsp" model="uploadOtros">
        <transition on="sube" to="addFile">
        <evaluate expression="informeProveedorAction.uploadOtros"/>
        </transition>
        <transition on="cancelar" to="subirPDF"/> 
    </view-state>

    <view-state id="addFile" view="/WEB-INF/jsp/factura/informeProveedorDetalle/addFileEmp.jsp" >
        <transition on="XMLPDF" to="subirPDF"/>
        <transition on="otherFile" to="otherFile"/>
        <transition on="no" to ="agregarDetalle">
            <evaluate expression="informeProveedorAction.actualizaDetalle"/>
        </transition>
        <transition on="cancel" to="endState" bind="false"/>  
    </view-state>
    
    <view-state id="agregarDetalle" view="/WEB-INF/jsp/factura/informeProveedorDetalle/addDetalle.jsp" >
        <transition on="transporte" to="transporte"/>
        <transition on="comida" to="comida"/>
        <transition on="hospedaje" to="hospedaje"/>
        <transition on="otros" to="otros"/>
        <transition on="enviar" to="endState">
            <evaluate expression="informeProveedorAction.finaliza"/>
        </transition> 
        <transition on="no" to ="endState">
            <evaluate expression="informeProveedorAction.guardarInforme"/>
        </transition>
        <transition on="cancel" to="endState" bind="false"/>  
    </view-state>
    
    <end-state id="endState" commit="true" view="externalRedirect:contextRelative:/facturas/empleado" />

    <global-transitions>
        <transition on="cancel" to="endState" />
    </global-transitions>
  
</flow>



El codigo comienza con el encabezado del xml y la declaración de las variables.

<?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" >
    
   <var name="informeProveedor" class="mx.edu.um.mateo.contabilidad.facturas.model.InformeProveedor"/>    
    <var name="informeProveedorDetalle" class="mx.edu.um.mateo.contabilidad.facturas.model.InformeProveedorDetalle"/>    
    <var name="rfcProveedor" class="java.lang.String"/>
    <var name="archivosPdfXml" class="mx.edu.um.mateo.contabilidad.facturas.model.ArchivosPdfXml"/> 
    <var name="uploadOtros" class="mx.edu.um.mateo.contabilidad.facturas.model.ArchivosPdfXml"/> 
    <var name="datosFacturaConfirmar" class="mx.edu.um.mateo.contabilidad.facturas.model.DatosFacturaConfirmar"/>
    <var name="concepto" class="java.lang.String"/>


Después tenemos el primer estado, que es un view-state. Este view state tiene como vista listaEmp.jsp, contiene la etiqueta <on-render> lo que correra el metodo getInformesEmpleado. Despues contiene una transicion cuando el usuario de click en crearInformeProveedor continuara al estado con id traepermisos.

    <view-state id="listaInformes" view="/WEB-INF/jsp/factura/informeProveedor/listaEmp.jsp">
        <on-render>
            <evaluate expression="informeProveedorManager.getInformesEmpleado(externalContext.sessionMap.empresaId)" result="requestScope.informes"/>
        </on-render>
        <transition on="crearInformeProveedor" to="traepermisos"/>  
    </view-state>

El siguiente estado es un <action-state> Que va a correr el metodo getPersmisos de la clase informeProveedorAction. Tiene una transicion a nuevoInformeProveedor, como no tiene atributo on quiere decir que cuando el action state mande success automaticamente se ira al estado nuevoInformeProveedor.

    <action-state id="traepermisos">
        <evaluate expression="informeProveedorAction.getPermisos" />
        <transition to="nuevoInformeProveedor"/>       
    </action-state>

Nuevamente tenemos un <view-state> pero este estado va a llenar un objeto informeProveedor por eso tiene el atributo model.

    <view-state id="nuevoInformeProveedor" view="/WEB-INF/jsp/factura/informeProveedor/nuevoEmp.jsp" model="informeProveedor">
        <transition on="grabaInforme" to="seleccionaConcepto">
            <evaluate expression="informeProveedorAction.creaInforme" />
        </transition>
    </view-state>

Asi todos estados van avanzando hasta llegar al <end-state> que simplemente mandara al usuario a un link en especifico.

Como configurar los links del JSP

Para que el webflow detecte que el usuario dio click en determinado boton o link, en el jsp debemos de agregar el valor del on de la etiqueta transition.
Por ejemplo en el estado listaInformes el valor de on de la etiqueta transition es crearInformeProveedor y se ira al estado traepermisos:


Si vemos el código de este link en el jsp veremos que el valor de on=crearInformeProveedor, se encuentra dentro del atributo href del código del jsp:

<a class="btn btn-primary" href="${flowExecutionUrl}&_eventId=crearInformeProveedor"><i class="icon-user icon-white"></i> <s:message code='informeEmpleado.nuevo.label' /></a>
            

Se debe anteponer la siguiente sintaxis antes del valor on de la transición. Y debe ir entre comillas dentro del atributo href.
${flowExecutionUrl}&_eventId=

De esta forma el flow sabe que transicion a sido clickada por el usuario y sabe a que estado debe de ir. Las transiciones que no tiene valor on se van automaticamente al estado configurado siempre y cuando el metodo del estado devuelva success.

Comentarios

Entradas populares de este blog

Batch File como Servicio de Windows

Cómo crear archivos XML en Java con JAXB

SQL y los acentos