Tip Struts 2 #10: El interceptor execAndWait

05/12/2013
struts2 tip

El inteceptor execAndWait es uno de los más curiosos de la pila ofrecida por Struts 2. Su objetivo es el de mostrar una página de espera mientras finaliza la ejecución de un Action que es susceptible de tener una larga duración y además evitar que durante la espera el navegador devuelva un timeout al usuario ya que, como veremos, la página de espera se recarga periódicamente haciendo una nueva petición al servidor. Además, es muy fácil de utilizar y especialmente interesante cuando no podemos usar AJAX o javascript que es lo que yo usaría si tuviera que implementar la casuística propuesta en este tip.

Al usar este interceptor hay que tener en cuenta los siguientes detalles:

  • El Action es único por sesión.
  • No se debe utilizar ActionContext porque el Action se ejecuta en un hilo distinto.
  • El interceptor debe ser el último de la pila.

El uso del interceptor es sumamente sencillo tal y como veremos a continuación. Empecemos con la página de espera /jsp/wait.jsp (Struts 2 proporciona una por defecto pero por motivos estéticos no se va a utilizar). Lo significativo de esta jsp es que es necesario incluir una etiqueta meta refresh para que la jsp se refresque ya que es la única forma de que el navegador pueda comprobar periódicamente si el Action ha terminado su ejecución (no estamos usando Ajax). Asimismo, en esta jsp como cabría esperar tenemos acceso al ValueStack del Action lo que permite por ejemplo mostrar información sobre el progreso del proceso:

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html>
	<head>
		<%@include file="/jsp/head.jsp" %>
		<meta http-equiv="refresh" content="3;url=<s:url includeParams="all" />"/>
	</head>       
	
	<body>

	<s:text name="processing"/> <s:property value="percentage"/>
		
		<%@include file="/jsp/footer.jsp" %>
		
	</body>
	
</html>

Para el action simularemos un proceso que tarde en ejecutarse unos 10 segundos y que ofrezca información del porcentaje que lleva realizado.

package com.danielme.tips.struts2.tip10.actions;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * @author danielme.com
 * 
 */
public class MainAction extends ActionSupport
{
	private static final long serialVersionUID = 33466065079709970L;
	
	private int i =0;

	public String execute() throws Exception
	{
		while(i < 100)
		{
			i++;
			Thread.sleep(100);
		}
		return SUCCESS;
	}

	public String getPercentage()
	{
		return i + " %";
	}

	

}

Por último, veamos el struts.xml. Simplemente añadimos el interceptor a la pila de interceptores del Action y definimos el result wait para la jsp que hemos visto, y el o los correspondientes a la finalización de la ejecución del Action. El interceptor admite tres parámetros según la documentación oficial, yo sólo he usado “delay” que permite definir en milisegundos el tiempo de espera inicial de finalización del action. Si tras ese periodo el Action no se ha terminado de ejecutar se mostrará la página de espera. Por defecto el delay es cero y por lo tanto siempre muestra la página de wait, por lo que debemos usar este parámetro si existe la posibilidad de que el Action se ejecute casi de inmediato para evitar mostrar innecesariamente la pantalla de espera e ir directamente a resultado.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>

	<constant name="struts.devMode" value="true" />
	<constant name="struts.custom.i18n.resources" value="i18n" />

        <!-- enable 'action' attribute -->
	<constant name="struts.mapper.action.prefix.enabled" value="false" />
	<!-- enable 'method'  attribute-->	
	<constant name="struts.enable.DynamicMethodInvocation" value="false" />
	
	<package name="default" namespace="/" extends="struts-default">

		<action name="mainAction" class="com.danielme.tips.struts2.tip10.actions.MainAction">
			<interceptor-ref name="execAndWait">
		        <param name="delay">2000</param>
		    </interceptor-ref>
			<result name="wait">/jsp/wait.jsp</result>
			<result name="success">/jsp/done.jsp</result>			
		</action>

	</package>

</struts>

exec and wait interceptor

El siguiente video muestra el funcionamiento del ejemplo. Obsérvese el delay de espera inicial que provoca que la cuenta empiece en el 21% , y cómo la página se va actualizando periódicamente hasta que se devuelve el result (aunque este no lo verá el usuario exactamente cuando termine el Action sino que tendrá que esperar a que la JSP llame al servidor gracias al meta refresh).


El proyecto completo para Maven se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

<< TIPS STRUTS 2

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: