Desarrollo de aplicaciones Web con Struts 1

10
85730

Desarrollo de aplicaciones web con Struts 1

En este tutorial y bajo petición de unas personas que me lo solicitaron, voy a intentar plasmar las ideas y los pasos a seguir para que para realizar una pequeña aplicación ejemplo que contemple las ideas y conceptos más importantes en el desarrollo de aplicaciones Web con el FrameWork Struts (1.3.10).

Cabe destacar que la versión 1.3.10, fue la última de las versiones de Struts 1, antes de que naciera el framework Struts 2, cuyo estudio queda pendiente para otro tutorial.

Este tutorial no trata de presentar una extensa documentación teórica sobre este framework, sino más bien, un ejemplo que incluya y explique los conceptos más importantes:

  1. Captura de pantalla de la apariencia gráfica de la aplicación a desarrollar.
  2. Pasos necesarios para crear un proyecto con Struts (sin usar Maven).
  3. Explicación del archivo de configuración de Struts. (/WEB-INF/struts-config.xml).
  4. JSP de ejemplo: TagLibs de Struts e invocación de acciones (/index.jsp).
  5. Referencias.

Captura de pantalla de la apariencia gráfica de la aplicación a desarrollar:

Sí, si, la aplicación es muy fea pero resume los conceptos más importantes (configuración, flujo, internacionalización, validación declarativa, validación programática, etc.) con dependencias mínimas (2 acciones, 2 formularios, 1 Bean y 3 JSP).

Puede descargarse la aplicación en formato WAR (con el código fuente) haciendo clic aquí.

Pasos necesarios para crear un proyecto con Struts (sin usar Maven).

  1. Descargar la distribución de Struts desde la página de descarga oficial.
  2. Descomprir el archivo y copiar todas las librerías (archivos jar) al directorio /WEB-INF/lib de tu proyecto web.
  3. Dar de alta el servlet controlador de Struts en el /WEB-INF/web.xml de tu proyecto. Haga clic aquí para verlo.

Archivo /WEB-INF/web.xml


    
    
    	StrutsExamples
    	
    		action
    		org.apache.struts.action.ActionServlet
    		
    			config
    			/WEB-INF/struts-config.xml
    		
    		1
    	
    	
    	
    		action
    		*.do
    	
    	
    	
    		index.jsp
    	
        
  

Si observa, el servlet controlador de Struts (org.apache.struts.action.ActionServlet) tratará todas las peticiones cuya extensión en la URI sea .do (do » hacer, aunque esto por supuesto se puede cambiar sin problemas).

Explicación del archivo de configuración de Struts (/WEB-INF/struts-config.xml).

Struts se configura de forma declarativa mediante un archivo xml.

En el indicamos básicamente:

  • El flujo de la aplicacion, es decir, las posibles acciones a realizar y los caminos a los que pueden conducir cada una de ellas.
  • Que hacer en caso de errores.
  • El archivo de internacionalización de nuestra aplicación Web.
  • Los tipos de datos de la información que es enviada y validada en el método validate los formularios asocionados a cada acción.

Archivo /WEB-INF/struts-config.xml




    
        
        
              
              
              
        
    
    
	
        
   			
   			
        

		
			
		        
    

    
    
	
		
	    


  • Línea 06: Dentro del tag form-beans se definen los formularios que usa la aplicación. Un formulario es un conjunto de datos que automáticamente Struts nos inicializa con los datos que el usuario ha introduccido en el formulario HTML generado desde la JSP.
    Existen tres tipos principales de formularios:

    1. org.apache.struts.action.ActionForm: Formulario que tiene un atributo, un getter y un setter por cada input del formulario asociada a la acción que lo usa.

      Este tipo de formularios, pueden ser validados de forma programática.

      Observe el ActionForm del ejemplo haciendo clic aquí.
    2. org.apache.struts.action.DynaActionForm: A diferencia de los ActionForm no necesitan que implementemos una clase Java con sus atributos y sus get y set para cada uno de sus atributos. todo se lee y escribe como un mapa (clave atributo/valor atributo), definiéndose previamente en el archivo struts-config.xml las propiedades que tendrá (líneas 9-11).

      No permiten validaciones a no ser que nos escribamos una clase que herede de DynaActionForm y reescribamos el método validate (Por lo que no tiene mucho sentido usarlas si se necesita validación).
    3. org.apache.struts.validator.DynaValidatorForm: Es un DynaActionForm cuyas validaciones están definidas de forma declarativa mediante un archivo xml. Haga clic aqui para ver el archivo de validaciones del ejemplo.
  • Línea 07: Definimos «operandosForm» un SumarForm (hereda de ActionForm) que será usado por la acción «sumar» (línea 18) de manera que antes de ejecutar la acción SumarAction se ejecutará el método validate del formulario SumarForm y sólo si este método no detecta ningún error, será ejecutada la acción.
  • Línea 08: Definimos «registroForm» un DynaValidatorForm que será usado por la acción «registro» (línea 27) de manera que antes de ejecutar la acción RegistroAction se ejecutarán las validaciones especificadas en el archivo /WEB-INF/validation.xml y sólo si no se detecta ningún error, será ejecutada la acción.
  • Línea 37: Definimos el nombre del archivo proporcionará la internacionalización de mensajes de por defecto.
    Puede definir archivos para lenguajes y paises específicos, ejemplos:
    • ApplicationResources_es_ES: Para el lenguaje Español de España.
    • ApplicationResources_es: Para el lenguaje Español en general.
    • ApplicationResources_es_MX: Para el lenguaje Español de México.
    • ApplicationResources_en_US: Para el lenguaje Inglés de Estados Unidos.
    • ApplicationResources_en: Para el lenguaje Inglés en general.
    • etc.

    Haga clic aqui para ver el archivo de internacionalización de mensajes de la aplicación.

  • Línea 39: Habilitamos el plugin necesario para realizar validaciones de forma declarativa (sin necesidad de programar, con un archivo xml) gracias al commons Validator. Haga clic aqui para ver el archivo de validaciones del ejemplo.

ApplicationResources.properties

# -----------------------------------------------------------------------------
# Archivo de internacionalización por defecto: ApplicationResources.properties
# -----------------------------------------------------------------------------

next.page=Siguiente
index=Hola
numeric=No es un número positivo
field.name=Nombre
field.email=Email
field.age=Edad
message.hello=Hola {0}
errors.cancel=cancelada
errors.header=<ul class="errorHeader">
errors.prefix=<li>
errors.suffix=</li>
errors.footer=</ul>
errors.integer={0}: Debe ser un número
errors.required=El campo {0} es requerido
errors.range=El campo {0} debe estár entre {1} y {2}
errors.email=El campo {0} no es un email válido
error.operando.negativo=El operando debe ser un número positivo
error.operandos.negativos=Los operandos deben ser números positivos

JSP de ejemplo: TagLibs de Struts e invocación de acciones. (/index.jsp).

Dentro de la propia página JSP explico que voy haciendo en cada punto.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>

<%-- Indicamos que vamos a usar las TagLibs de Struts --%>	
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>




	
	Ejemplo de uso de TagLib de Struts
	


	<%-- Validación usando un ActionForm --%>
	

/index.jsp

			
<%-- Imprimimos un mensaje internacionalizado con parámetros--%>

Imprimimos un mensaje internacionalizado con parámetros

<%-- Creamos un bean a nivel de session y luego creamos un variable de tipo String con los valores de un bean y lo imprimimos --%>

Creamos un bean a nivel de session y luego creamos
un variable de tipo String con los valores de un bean

<%-- Guarda una Cookie en el Bean de nombre "sess". Imprimimos algunos valores --%>

Guarda una Cookie en el Bean de nombre "sess".

<%-- Guarga la cabecera Accept-Language en una variable --%>

Guarga la cabecera Accept-Language en una variable

<%-- Comparaciones entre valores --%>

Comparaciones entre valores

true

false

El tiempo de vida es mayor que 0

<%-- Comprobamos si tiene valor una variable --%>

Comprobamos si tiene valor una variable

La propiedad login está vacia

La propiedad login NO está vacia

<%-- Formateando la salida de información --%>

Formateando la salida de información

<% pageContext.setAttribute("unDouble", new Double(124587.89)); pageContext.setAttribute("ahora", new java.util.Date(System.currentTimeMillis())); %>   

/index.jsp

				<%-- Consultamos si una cabecera tiene un determinado contenido (también vale para parámetros, cookies, etc) --%>
				

Consultamos si una cabecera tiene un determinado contenido:

Accept-Language Match en cualquier posicion Accept-Language notMatch en cualquier posicion Accept-Language no existe <%-- Iteramos sobre los elementos de una lista --%>

Iteramos sobre los elementos de una lista

<% java.util.ArrayList list = new java.util.ArrayList(); list.add("++++++++ Uno ++++++++"); list.add("++++++++ Dos ++++++++"); pageContext.setAttribute("lista", list); %>
<%-- Nota: Los operandos deben ser números positivos. (Validación usando un ActionForm => Método validate del formulario asociado a la acción sumar) --%>

Validación usando un ActionForm.
Nota: Los operandos deben ser números positivos.


Operando 1:
Operando 2:

El resultado es:

<%-- Validación usando un DynaValidatorForm con validación tanto en el servidor como en el cliente (javascript) --%>

Validación usando un DynaValidatorForm.
Validación en servidor y cliente (javascript).
Todos los campos son requeridos.
El campo email debe tener un formáto válido.
El campo edad debe ser un número entre 18 y 40

<%-- Indicamos que genere el código JavaScript necesario para validar el formulario registroForm. (Las validaciones las optione del archivo validation.xml) --%>
Login:
Email:
Edad:

<%-- En caso de que existan errores, los mostramos --%>

/WEB-INF/jsp/cancel.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>



	
	Página de confirmación


	

¡¡ Se ha registrado correctamente !!

Datos de registro

  • Login:
  • Email:
  • Edad:

Si observa el archivo struts-config.xml verá que está JSP es mostrada cuando el usuario cancela la acción de sumar.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>



	
	Cancelada


	Cancelada



/WEB-INF/jsp/registerOk.jsp

Si observa el archivo struts-config.xml verá que está JSP es mostrada cuando el usuario se registra correctamente a través de la acción de registro.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>



	
	Página de confirmación


	

¡¡ Se ha registrado correctamente !!

Datos de registro

  • Login:
  • Email:
  • Edad:

com.entity.User

package com.entity;

/**
 * Bean para el ejemplo de struts => representa un usuario
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es
 */
public class User {
	private String login;	// Código del usuario
	private String email;	// Dirección de correo
	private byte   age;		// Edad
	
	public String getLogin() {
		return login;
	}
	public void setLogin(String login) {
		this.login = login;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public byte getAge() {
		return age;
	}
	public void setAge(byte age) {
		this.age = age;
	}
}


com.form.SumarForm

Observe que tiene un atributo y un get y set para cada uno de ellos. Además estos deben de coincidir en nombre con los input del formulario HTML

package com.form;

import org.apache.commons.validator.GenericValidator;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMessage;

/**
 * ActionForm usado para la acción "sumar"
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es
 */
public class SumarForm extends org.apache.struts.action.ActionForm {
	private String operando1;
	private String operando2;
	private String resultado;
	
	public String getOperando1() {
		return operando1;
	}

	public void setOperando1(String operando1) {
		this.operando1 = operando1;
	}

	public String getOperando2() {
		return operando2;
	}
	
	public void setOperando2(String operando2) {
		this.operando2 = operando2;
	}

	public String getResultado() {
		return resultado;
	}
	
	public void setResultado(String resultado) {
		this.resultado = resultado;
	}
	
	/* 
	 * Inicializamos los parámetros
	 */
	public void reset(org.apache.struts.action.ActionMapping mapping, javax.servlet.http.HttpServletRequest request) {
		this.operando1 = "";
		this.operando2 = "";
		this.resultado = "";
	}

	/* 
	 * Validamamos los datos introducidos por el usuario
	 */
	public ActionErrors validate(org.apache.struts.action.ActionMapping mapping, javax.servlet.http.HttpServletRequest request) {
		ActionErrors	errors		=  new ActionErrors();
		
		if (GenericValidator.isBlankOrNull(this.operando1) || (! GenericValidator.isInRange(Integer.parseInt(this.operando1), 0, Integer.MAX_VALUE))) {
			errors.add("operando1", new ActionMessage("error.operando.negativo"));
		}
		
		if (GenericValidator.isBlankOrNull(this.operando2) || (! GenericValidator.isInRange(Integer.parseInt(this.operando2), 0, Integer.MAX_VALUE))) {
			errors.add("operando2", new ActionMessage("error.operando.negativo"));
		}
		
		return errors;
	}
}
    
    

com.action.SumarAction

En caso de que el método validate de SumarForm no detecte errores se ejecutará esta acción y se redirigirá a la página /index.jsp.

Todo esto está definido en el action con el atributo path="sumar" dentro del archivo struts-config.xml

package com.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.*;

/**
 * Action que suma dos numeros enteros positivos
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es
 */
public class SumarAction extends Action {
	
	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		ActionForward forward = null;

		if (this.isCancelled(request)){
			forward = mapping.findForward("cancel");	
		} else {	
			com.form.SumarForm operationForm = (com.form.SumarForm) form;
			
			int operando1 = Integer.parseInt(operationForm.getOperando1());
			int operando2 = Integer.parseInt(operationForm.getOperando2());
			
			operationForm.setResultado(String.valueOf(operando1 + operando2));
			
			forward = mapping.findForward("ok");
		}
		
		return forward;
	}
}  

com.action.RegistroAction

Registra al usuario a partir de los datos introducidos en la JSP /index.jsp y redirige a la página /WEB-INF/jsp/registerOk.jsp donde serán mostrados los datos del usuario.

Todo esto está definido en el action con el atributo path="registro" dentro del archivo struts-config.xml

package com.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.*;

/**
 * Action que registra al usuario en el sistema
 * @author Carlos García. Autentia.
 * @see http://www.mobiletest.es
 */
public class RegistroAction extends Action {
	
	public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
		DynaActionForm registerForm = (DynaActionForm) form;
		
		// Extraemos los datos del formulario 
		String  login = (String) registerForm.get("login");
		String  email = (String) registerForm.get("email");
		Byte	edad  = (Byte)   registerForm.get("age");
		
		//////////////////////////////////////////////////////////////////////////////////////
		// Realizariamos las acciones en los objetos de negocio (En este caso, nada)
		//////////////////////////////////////////////////////////////////////////////////////
		
		// Configurariamos los objetos Request, Session, etc. que necesita la siguiente vista a mostrar
		com.entity.User user = new com.entity.User();
		user.setLogin(login);
		user.setEmail(email);
		user.setAge(edad.byteValue());
		
		request.setAttribute("registerUser", user);
		
		// Mostramos la siguiente vista
		return mapping.findForward("ok"); 
	}
}


/WEB-INF/validation.xml

En este archivo especificamos las validaciones de forma declarativa de los formularios form-beans definidos en el /WEB-INF/struts-config.xml

Las validaciones a realizar son:

  • Los campos login, email y edad son requeridos.
  • El campo email debe tener un formato de email válido.
  • El campo edad debe ser un número comprendido entre 18 y 40.



	
		
min 18 max 40

Referencias:

  • Guía de referencia de Struts (en Inglés)
  • Guía de validación con Struts (en Inglés)

Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.

cgpcosmad@gmail.com

10 COMENTARIOS

  1. Muy buen tutorial muy ilustrativo aplia mi panorama y marca un buen punto de partida gracias por compartir esto saludos …..
    gracias Carlos

  2. Hola Muy buen tutorial,
    Lo he estado siguiendo para hacer una prueba pero tengo problemas porque por algún motivo no encuntra las etiquetas html. En concreto esta es la cabecera del error que me da:

    «La uri absoluta: http://struts.apache.org/tags-html no puede resolverse o en web.xml o el los archivos jar desplegados con esta aplicación..»

    Por lo que he podido ver por la web, me falta añadir alguna librería a mi proyecto, Pero, ¿Cuales son estas librerias? ¿Tengo que agregarlas en el poyecto de eclipse?

    • Miguel, debes ir a este enlace http://struts.apache.org/download.cgi y en la parte de Struts 1.3 te descargas la siguiente: struts-1.3.10-lib.zip será suficiente con ella, una vez descomprimidas metes todos los .jar en la siguiente ruta tuworkspacenombreProyectoWebContentWEB-INFlib y deberás corregir dicho problema. Un saludo.

      Yo tengo problemas con la variable de session si alguien puede ayudarme se lo agradecería «undefined type: com.entity.User

  3. Buenas noches es un excelente tutorial!!!!

    Tengo un problema
    value=»/org/apache/struts/validator/validator-rules.xml
    de donde saco validator-rules.xml

  4. Buenas tardes !!! creo que tienes un peque#o olvido en : /WEB-INF/jsp/cancel.jsp

    copiaste la que misma cuando el user/password es valido

  5. Hola Javier,
    Me parece muy buen tutorial de struts, yo llevo algo de tiempo trabajando con una versión anterior (1.1) y me ayudaría mucho tu opinión sobre la idea de migrar de Strtus 1.1 a la versión 1.3.10. Sé que ya esta fuera de soporte, pero no me es posible realizar dicha migración a spring u otro framework ya que es una aplicación heredada. Hasta ahora veo que es actualizar jars y dependencias así como encabezados de los xml de configuración y actualización de la clase ActionError lo cual no impacta mucho en la aplicación que estoy revisando, pero no se si puede implicar mas cambios de fondo. hasta ahora han sido de forma y no son muchos.
    Apreciaría mucho tus 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