Manual - Programacion - Java - Struts

29
STRUTS:Implementación del patrón MVC en aplicaciones Web 1 STRUTS Implementación del patrón MVC en aplicaciones Web (Actualizaciones y ejemplos en http://ciberia.ya.com/pxai/ma.html)

Transcript of Manual - Programacion - Java - Struts

Page 1: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

1

STRUTSImplementación del patrón MVC

en aplicaciones Web(Actualizaciones y ejemplos en http://ciberia.ya.com/pxai/ma.html)

Page 2: Manual - Programacion - Java - Struts

http://www.javahispano.com

2

INDICE

1. INTRODUCCIÓN..................................................................................................... 3

2. MVC: Model View Controller................................................................................... 4

3. STRUTS..................................................................................................................... 7

ESTUCTURA .......................................................................................................................... 8

UN EJEMPLO SENCILLO DE STRUTS .......................................................................... 12

UN EJEMPLO DE STRUTS MÁS COMPLEJO............................................................... 15

Errores comunes con Struts.................................................................................................. 29

Page 3: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

3

1. INTRODUCCIÓN

Este documento describe el patrón de diseño MVC (Model View Controller). Comoejemplo de implementación se utiliza el framework Struts, que facilita el desarrollo deaplicaciones web en Java basadas en MVC.

En al ámbito del desarrollo web se siguen unas pautas que tratan más o menos deconseguir un desarrollo estructurado de las aplicaciones, donde la verificación desesión se centraliza y cada caso de uso se distingue claramente. Utilizando Struts ese“más o menos” se convierte en una arquitectura completamente estructurada quedivide perfectamente lógica de negocio (Model), presentación (View) y control de flujode aplicaciones(Controller). En muchos desarrollos web se diseña consciente oinconscientemente siguiendo este patrón, por tanto la adopción del modelo Struts nodebiera suponer un quebradero de cabeza.

Además hay que tener en cuenta que Struts nos da parte del trabajo hecho, funcionacorrectamente, y nos da ciertos extras. Teniendo en cuenta además las aportacionesde grupos de desarrollo (taglibs nuevos, etc..), la adopción de esta plataforma puederesultar muy interesante.

Page 4: Manual - Programacion - Java - Struts

http://www.javahispano.com

4

2. MVC: MODEL VIEW CONTROLLER

MVC o Model view Controller es un patrón de diseño aportado originariamentepor el lenguaje SmallTalk a la Ingeniería del Software. El paradigma MVC consiste endividir las aplicaciones en tres partes:

• Controlador• Modelo• Vistas.

El controlador es el encargado de redirigir o asignar una aplicación (unmodelo) a cada petición; el controlador debe poseer de algún modo, un "mapa" decorrespondencias entre peticiones y respuestas (aplicaciones o modelo) que se lesasignan.

El modelo seria la aplicación que responde a una petición, es la lógica denegocio a fin de cuentas.

Una vez realizadas las operaciones necesarias el flujo vuelve al controlador yeste devuelve los resultados a una vista asignada.

Vemos las diferencias que supone el modelo con los modelos convencionales.

Yéndonos al esquema más básico de programa, tenemos una entrada o parámetrosque llegan(INPUT), se procesan y se muestra el resultado (OUTPUT).

Page 5: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

5

En el caso del patrón MVC el procesamiento se lleva a cabo entre sus trescomponentes. El controller recibe una orden y decide quien la lleva a cabo en elmodelo. Una vez que el modelo (la lógica de negocio) termina sus operacionesdevuelve el flujo vuelve al controller y este envía el resultado a la capa depresentación.

Page 6: Manual - Programacion - Java - Struts

http://www.javahispano.com

6

El Controller en cierta forma debe tener un registro de la relación entre ordenes que lepueden llegar y la lógica de negocio que le corresponde (Es como una operadora deteléfono que recibe una petición y une dos lineas). En el siguiente gráfico serepresenta ese funcionamiento:

¿Que ventajas obtenemos de este modelo? Obviamente una separación total entrelógica de negocio y presentación. A esto se le pueden aplicar opciones como elmultilenguaje, distintos diseños de presentación,.. etc sin alterar la lógica de negocio.

La separación de capas como presentación, lógica de negocio, acceso a datoses fundamental para el desarrollo de arquitecturas consistentes, reutilizables y másfacilmente mantenibles, lo que al final resulta en un ahorro de tiempo en desarrollo enposteriores proyectos.

En el lenguaje Java disponemos de una clases muy sencillas para implantar el modeloMVC: la clase Observer, Observable del paquete util.Aunque esa implementación del MVC con esas clases se podría hacer a un nivel muysimple de interacción entre unas pocas clases.En este caso, mediante Struts se aplica el MVC en toda una aplicación Webconvencional.

Page 7: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

7

3. STRUTS

Struts Framework (http://jakarta.apache.org/struts)Struts es un framework para aplicaciones web java que implementa el modelo MVC.Realmente lo que provee es un conjunto de clases y TAG-LIBS que conforman elControlador, la integración con el Modelo (o lógica de negocio) y facilitan laconstrucción de vistas.Naturalmente, el Modelo o lógica de negocio es la parte que nos correspondedesarrollar. Por eso Struts es una plataforma sobre la que montamos la lógica denegocio, y esta plataforma nos permite dividir la lógica de la presentación entre otrascosas.

Page 8: Manual - Programacion - Java - Struts

http://www.javahispano.com

8

ESTUCTURA

Supongamos que tenemos una aplicación Web que consiste en un formulario que recoge datosy los manda al servidor para su proceso. Este ejemplo tan simple necesitaría implementar unos6 ficheros (2 de ellos jsps). ¿Suena mal eh? Es el precio que hay que pagar por una aplicaciónbien estructurada.

Utilizando Struts nunca se llega a una pagina de la capa de presentación directamente. Estoes, en la url nunca se llega a una pagina jsp o html a traves de su nombre. De eso se trata elMVC, la presentación esta separada en otra capa.En este entorno, se debe invocar una acción o aplicación que debe estar mapeada en Struts:una acción se corresponderá con una clase Java (heredera de la clase Action de Struts). Elmapeo de acciones y clases se especifica en un fichero de importancia vital: struts-config.xml. Ahí se especifican todas las relaciones entre acciones y clases, formularios yclases, acciones y jsps de presentación, que globalmente conforman el “mapa” de laaplicación.

Si quisieramos crear la aplicación Struts más simple posible, por ejemplo una página con unsaludo, debiéramos hacer lo siguiente:1. -Una página JSP (la presentación)2. -Una clase Action (componente del controlador)3. -La clase Action debe definirse en el struts-config.xml correctamente

Veamos los diagramas correspondientes a ese caso:

Diagrama de clasesEn el caso más simple este sería el conjunto de clases utilizadas y sus relaciones.

Como se puede ver, no tendríamos más que dos ficheros, una clase que hereda destruts.Action y una JSP con la presentación. La clase Action se configura en el strtus-config.xmly se convierte en parte del controlador. Cuando la aplicación recibe una petición, Strutsdecidirá que debe cargar esa clase y través de ella cargará la JSP. Así se puede ver en elsiguente diagrama:

Diagrama de colaboraciónEsta sería la manera de interactuar entre la clases y Struts

Page 9: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

9

Una petición llega a struts (una URL); este mira en su “mapa” (el fichero struts-config.xml), ydeduce que tiene que cargar la ClaseAction. Esta clase esta configurada para que cargue unapagina JSP.Como se puede observar,no se carga la JSP directamente, hay que pasar por el controlado

Diagrama de secuencia.

Estos serían los pasos seguidos por la aplicación en el plano temporal.

Obviamente, este no es el ejemplo más clásico de una acción de Struts. Por lo general, encualquier aplicación web siempre se sigue un mismo esquema:1. se muestra un formulario2. se rellena3. se validase4. se manda a una página que realiza la lógica de negocio5. se muestra el resultado.

Todo esto se podría hacer con dos JSPs o dos ASPs, o dos CFM, o dos PHP o con un CGI,etc…En Struts necesitaríamos lo siguiente:1. -Una clase Action (su nombre podría empezar por Edit) encargada de cargar el formulario.2. -Un Bean tipo Form cuyos campos u atributos de instancia coinciden con los campos del

formulario. (al ser tipo JavaBean tendrá los correspondientes métodos set y get para losatributos) . Este form y sus atributos son un requisito imprescindible.

3. -Una JSP que contiene el formulario citado. Los campos deben coincidir con los definidosen el Bean de formulario

4. -Una clase Action (su nombre podría empezar por Save) encargada de pasar la instanciadel formulario al Bean de Logica de Negocio, esperar su resultado y redirigir el flujo a unaJSP de error o de éxito.

5. -Un Bean de lógica de negocio (El que hace algo con los datos del formulario)6. -Una JSP para mostrar un mensaje en caso de éxito (o puede ser la misma del principio)7. -Una JSP para mostrar los errores en caso de error (o puede usarse una genérica).Struts permite cierta flexibilidad en cuanto a nombres, pero conviene especificar cual esAction, cual es Form, cual es Bean de negocio, etc.. así como meterlos en subpaquetes conese nombre.

Veamos como quedan esos siete elementos en diagramas

Page 10: Manual - Programacion - Java - Struts

http://www.javahispano.com

10

Diagrama de clasesEste sería el conjunto de clases utilizadas y sus relaciones.

La clase edit también podría usar el formulario, pero en principio no tiene porqué.

Sería interesante ver como interactúan las clases entre ellas, y eso se ve en el siguientegráfico.Diagrama de colaboraciónEsta sería la manera de interactuar entre las clases y Struts

Page 11: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

11

Diagrama de secuencia.

Estos serían los pasos seguidos por la aplicación en el plano temporal.

Page 12: Manual - Programacion - Java - Struts

http://www.javahispano.com

12

UN EJEMPLO SENCILLO DE STRUTS

Bien, veamos ahora el ejemplo mítico de HelloWorld por el que se suele empezar cuando no setiene ni idea de algo.Vamos a crear una aplicación que muestra una página con el saludo Kaixo! que significa holaen euskera. Es fácil de narices.

Entrada de aplicación: ningunaSalida: Una página que muestra el texto “Kaixo!”

Diagrama de clases

• Clase EditKaixoAction/** * EditKaixoAction.java * Pello Xabier Altadill Izura */

package pxai.struts.kaixo.action;

import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.util.Locale;import java.util.Vector;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.Action;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionServlet;import org.apache.struts.util.MessageResources;import org.apache.struts.util.PropertyUtils;import com.jazztel.numeracionip.comun.Log;

/** * EditKaixoAction.java * Maneja las peticiones enviadas por el browser * en el url se pondra: /kaixo.do y struts cargara esta clase * que redirigira el flujo a una jsp: Kaixo.jsp * * @author Pello Xabier Altadill Izura * @version 1.0 ,date 13/2/02*/public final class EditKaixoAction extends Action {

/*** Procesa la peticion HTTP (request) especificada y genera su correspondiente

Page 13: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

13

* respuesta HTTP (response) (o lo redirige a otro componente web que podriacrear).

* Devuelve una instancia code>ActionForward</code> que describe a DONDE y COMO* se redirige el control, o sino, si la respuesta se ha completado se devolveria* <code>null</code>** @param mapping El mapeo utilizado para seleccionar esta instancia* @param request El request que estamos procesando* @param actionForm La instancia ActionForm que estamos utilizando (si la hay)* @param response La respuesta HTTP que creamos.** @exception IOException en caso de error de entrada/salida (i/o)* @exception ServletException en caso de error de servlet*/public ActionForward perform(ActionMapping mapping,

ActionForm form,HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {

// Extrae los atributos que se necesitanLocale locale = getLocale(request);MessageResources messages = getResources();HttpSession session = request.getSession();String action = request.getParameter("action");ActionErrors errors = null;

try {

if (action == null)action = "Create";

if (servlet.getDebug() >= 1)servlet.log("EditKaixoAction: Procesando action " + action);

/***** Logica segun el parametro action (noimprescindible)**************/

/************************************ fin de logica*********************/

// Redirige el control en caso de exito a la pagina espcificada enstruts-config.xml

if (servlet.getDebug() >= 1)servlet.log(" Redirigiendo a pagina 'success'");

return (mapping.findForward("success"));

} catch (Exception e) {e.printStackTrace(System.out);//Escribe en el fichero de log del

servidor de aplicacioneserrors = new ActionErrors();errors.add("action",new

ActionError("action.perform.carga.error"));//Se incluye un mensaje de error que seencuentra en el fichero especificado especificado en las propiedades de Struts

saveErrors(request,errors);return (mapping.findForward("failure"));

}}

}

El fichero JSP Kaixo.jsp<%@ page language="java" %><%@ taglib uri="/WEB-INF/app.tld" prefix="app" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html><head>

<title>STRUTS :: ejemplo</title></head>

<body><H1><%

out.println("Kaixo!!");

%></H1>

Page 14: Manual - Programacion - Java - Struts

http://www.javahispano.com

14

</body>

</html:html>

Configuracion del fichero struts-config.xml para este sencillo caso.Se debiera añadir, dentro de action mappings:

<action-mappings><!-- Edit Kaixo--> <!-- path: el nombre que debe especificarse en la url para acceder --> <!-- type: la clase asociada a la accion, con la ruta del paquete si la

tuviere --> <!-- name: nombre del formulario asociado con esta accion Normalmente No

requerido para una carga de pagina o accion Edit--> <!-- scope: ambito de validez de ese formulario (request o peticion):

puede ser session--> <!-- validate: si se va a validar el formulario o no.--><action path="/kaixo" type="pxai.struts.kaixo.action.EditKaixoAction"

name="" scope="request" validate="false"><forward name="success" path="/Kaixo.jsp"/>

</action>

(Nota: debe reiniciarse el servidor de aplicaciones si se cambia este fichero)

El resultado:

Page 15: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

15

UN EJEMPLO DE STRUTS MÁS COMPLEJO

En fin, el ejemplo anterior era el típico “toy-code” que únicamente es valido como iniciación alStruts. Ahora veremos un ejemplo más acorde con la funcionalidad esperada de una aplicaciónweb cualquiera.Se trata de una aplicación de alta de usuario, un tipo de aplicación muy común y que presenteen muchos sistemas. Veremos como implementar esto con struts. En cualquier otro entornobastaría con crear un formulario y una página que realiza el alta y da el mensajecorrespondiente; pero aquí no será tan simple.Entrada de aplicación: Un formulario de datos: username, password,edad,fechanacimiento yprofesionSalida: Una página que muestra si se ha dado de alta correctamente

Diagrama de clasesAquí se puede contemplar las clases que serán necesarias para este ejemplo

Page 16: Manual - Programacion - Java - Struts

http://www.javahispano.com

16

Diagrama de colaboraciónEsta sería la manera de interactuar entre las clases action, form, bean, jsp y Struts .

Diagrama de secuenciaAquí podemos ver como interactúan las clases en el tiempo.

Page 17: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

17

El código

EditAltaAction/** * EditAltaAction.java * Pello Xabier Altadill Izura */

package pxai.struts.alta.action;

import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.util.Locale;import java.util.Vector;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.Action;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionServlet;import org.apache.struts.util.MessageResources;import org.apache.struts.util.PropertyUtils;import com.jazztel.numeracionip.comun.Log;import com.jazztel.numeracionip.bean.MigracionNumeracionBean;

/** * EditAltaAction.java * Maneja las peticiones enviadas por el browser * @author Pello Xabier Altadill Izura * @version 1.0 ,date 13/2/02*/public final class EditAltaAction extends Action {

/*** Procesa la peticion HTTP (request) especificada y genera su correspondiente* respuesta HTTP (response) (o lo redirige a otro componente web que podria

crear).* Devuelve una instancia code>ActionForward</code> que describe a DONDE y COMO* se redirige el control, o sino, si la respuesta se ha completado se devolveria* <code>null</code>** @param mapping El mapeo utilizado para seleccionar esta instancia* @param request El request que estamos procesando* @param actionForm La instancia ActionForm que estamos utilizando (si la hay)* @param response La respuesta HTTP que creamos.** @exception IOException en caso de error de entrada/salida (i/o)* @exception ServletException en caso de error de servlet*/public ActionForward perform(ActionMapping mapping,

ActionForm form,HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException {

// Extrae los atributos que se necesitanLocale locale = getLocale(request);MessageResources messages = getResources();HttpSession session = request.getSession();String action = request.getParameter("action");ActionErrors errors = null;

try {

if (action == null)action = "Create";

if (servlet.getDebug() >= 1)servlet.log("EditAltaAction: Procesando action " + action);

Page 18: Manual - Programacion - Java - Struts

http://www.javahispano.com

18

/*******************************************************************************/

// En este caso unicamente cargamos la JSP/************************************

*******************************************/// Redirige el control en caso de exito a la pagina espcificada en

struts-config.xml

if (servlet.getDebug() >= 1)servlet.log(" Redirigiendo a pagina 'success'");

return (mapping.findForward("success"));

} catch (Exception e) {e.printStackTrace(System.out);//Escribe en el fichero de log del

servidor de aplicaciones// Creamos un error y lo salvamos para mostrarlo por pantallaerrors = new ActionErrors();errors.add("alta",new ActionError("alta.edit.error"));saveErrors(request,errors);return (mapping.findForward("failure"));

}}

}

alta.jsp<%@ page language="java" %><%@ taglib uri="/WEB-INF/app.tld" prefix="app" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html><head>

<title>STRUTS :: ejemplo de ALTA</title></head>

<body><html:form action="/saveAlta.do" >

<b>ALTA de USUARIO</b><hr>

Usuario:<html:text property="username" size="8" maxlength="8" /><br>Password:<html:text property="password" size="8" maxlength="8" /><br>Edad:<html:text property="edad" size="3" maxlength="3"/><br>Fecha Nacimiento(dd/mm/aaaa):<html:text property="fechanacimiento" size="10"

maxlength="10"/><br>Profesion:<html:select property="profesion">

<html:option value="-1">Selecciona ...</html:option><html:option value="Parado">Parado</html:option><html:option value="Estudiante">Estudiante</html:option><html:option value="Profesional liberal">Profesional

liberal</html:option><html:option value="Empresario">Empresario</html:option><html:option value="Currela">Currela</html:option>

</html:select><br><html:submit property="alta"/>

</html:form>

</body></html:html>

AltaForm/** * AltaForm.java * Pello Xabier Altadill Izura */

package pxai.struts.alta.form;

import javax.servlet.http.HttpServletRequest;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;

Page 19: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

19

import com.jazztel.numeracionip.comun.IP;import com.jazztel.numeracionip.comun.Log;import java.sql.Date;

/** * AltaForm * * Implementa el formulario de ALTA que se muestra en html * @author Pello Xabier Altadill Izura * @version 1.0 * date 13/2/02*/public final class AltaForm extends ActionForm {

/*** @field Mantenimiento de la accion que estamos procesando (Create or Edit).* atributo IMPRESCINDIBLE para STRUS*/

private String action = "Create";

private String username = null;private String password = null;private Integer edad = null;private String fechanacimiento = null;private String profesion = null;

/*** Devuelve la accion.** @return String la accion*/

public String getAction() {

return (this.action); }

/*** Establece la accion** @param action La nueva accion*/

public void setAction(String action) {

this.action = action; }

/*** getUsername* Devuelve nombre de usuario* @return String*/public String getUsername() {

return (this.username);}

/*** setUsername* Establece el nombre de usuario* @param String*/public void setUsername(String username) {

this.username = username;}

/*** getPassword* Devuelve el password* @return String*/public String getPassword() {

return (this.password);}

/*** setPassword* Establece el password

Page 20: Manual - Programacion - Java - Struts

http://www.javahispano.com

20

* @param String*/public void setPassword(String password) {

System.out.println("Aqui estamos: " +password);this.password = password;

}

/*** getEdad* Devuelve edad* @return Integer*/public Integer getEdad() {

return (this.edad);}

/*** setEdad* Establece la edad* @param Integer*/public void setEdad(Integer edad) {

this.edad = edad;}

/*** getFechanacimiento* Devuelve la fecha de nacimiento dd/mm/aaaa* @return String*/public String getFechanacimiento() {

return (this.fechanacimiento);}

/*** setFechanacimiento* Establece la fechanacimiento* @param String*/public void setFechanacimiento(String fechanacimiento) {

this.fechanacimiento = fechanacimiento;}

/*** getProfesion* Devuelve la profesion* @return String*/public String getProfesion() {

return (this.profesion);}

/*** setProfesion* Establece la profesion* @param String*/public void setProfesion(String profesion) {

this.profesion = profesion;}

/*** Resetea todas las propiedades a sus valores por defecto.** @param mapping El mapping utilizado por la instancia.* @param request El servlet request que estamos procesando.*/

public void reset(ActionMapping mapping, HttpServletRequest request) {

this.action = "Create";

Page 21: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

21

}

/*** Valida las propiedades asignadas desde el HTTP request* y devuelve un objeto <code>ActionErrors</code> que encapsula cualquier* validación de error que haya sido encontrada. Si no se han encontrado errores* , devuelve <code>null</code> o un objeto <code>ActionErrors</code> sin mensajes* de error grabados.** @param mapping El mapping utilizado por la instancia.* @param request El servlet request que estamos procesando.*/public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {

ActionErrors errors = new ActionErrors();

if (getUsername().trim().compareTo("") == 0 || getUsername() == null) {// El nombre de usuario es nulo, se devuelve mensaje de errorerrors.add("alta",new ActionError("alta.username.nulo"));

}

if (getPassword().trim().compareTo("") == 0 || getPassword() == null) {// El password es nulo, se devuelve mensaje de errorerrors.add("alta",new ActionError("alta.password.nulo"));

}

return errors;

}

}//class

SaveAltaAction/** * SaveAltaAction.java * Pello Xabier Altadill Izura */

package pxai.struts.alta.action;

import java.io.IOException;import java.util.Locale;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import org.apache.struts.action.Action;import org.apache.struts.action.ActionError;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionServlet;import org.apache.struts.util.MessageResources;import pxai.struts.alta.bean.AltaBean;import com.jazztel.numeracionip.comun.Log;import com.jazztel.numeracionip.comun.Data;

/** * Invoca al bean de lógica de negocio para procesar la migracion * en caso de encontrar datos validos devuelve un objeto data en * la sesión. * @author Pello Xabier Altadill Izura * @version 1.0 , date 13/2/02*/public final class SaveAltaAction extends Action {

/*** Procesa la peticion HTTP (request) especificada y genera su correspondiente* respuesta HTTP (response) (o lo redirige a otro componente web que podria

crear).* Devuelve una instancia code>ActionForward</code> que describe a DONDE y COMO* se redirige el control, o sino, si la respuesta se ha completado se devolveria* <code>null</code>** @param mapping El mapeo utilizado para seleccionar esta instancia* @param request El request que estamos procesando

Page 22: Manual - Programacion - Java - Struts

http://www.javahispano.com

22

* @param actionForm La instancia ActionForm que estamos utilizando (si la hay)* @param response La respuesta HTTP que creamos.** @exception IOException en caso de error de entrada/salida (i/o)* @exception ServletException en caso de error de servlet*/

public ActionForward perform(ActionMapping mapping, ActionForm theForm,HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException {

// Extract attributes and parameters we will needLocale locale = getLocale(request);MessageResources messages = getResources();HttpSession session = request.getSession();

String action = request.getParameter("action");if (action == null) action = "Create";

ActionErrors errors = null;

try {/********************** LOGICA DE NEGOCIO

*****************************/

//Instancia el bean de lógica de negocio

AltaBean theAltaBean = new AltaBean();

//Invoca al proceso de carga y recoge el valor de vueltaerrors = theAltaBean.alta(theForm);

/********************** FIN de LOGICA DE NEGOCIO**********************/

if (errors==null ) //Se ejecutó correctamentereturn (mapping.findForward("success"));

else { //Hubo erroressaveErrors(request,errors);return (mapping.findForward("failure"));

}

}catch (Exception e) {e.printStackTrace(System.out);//Escribe en el fichero de log del

servidor de aplicacioneserrors = new ActionErrors();errors.add("action",new ActionError("alta.save.error"));saveErrors(request,errors);return (mapping.findForward("failure"));

}

}

}

AltaBean/** * AltaBean.java * Pello Xabier Altadill Izura */

package pxai.struts.alta.bean;

import javax.servlet.http.HttpServletRequest;import javax.servlet.ServletException;import com.jazztel.numeracionip.comun.Log;import com.jazztel.numeracionip.comun.Propiedades;import com.jazztel.numeracionip.comun.DataService;import com.jazztel.numeracionip.comun.Data;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionError;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;

Page 23: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

23

import pxai.struts.alta.form.AltaForm;

/** * Implementa la lógica de negocio para el proceso Alta * @author Pello Xabier Altadill Izura, AXPE * @version 1.0 * date 23/1/02*/public class AltaBean {

/*** @field Constante que identifica el estado libre en la tabla de estados*/private static final Integer _ESTADO = new Integer(1);

/*** alta** Da el alta de un usuario* @param formulario con los datos a guardar** @return null si no hay errores o ActionErrors con los* errores capturados en caso de error.*/public synchronized ActionErrors alta (ActionForm theActionForm) {

//Instancia un objrcto ActionErrors para recoger los erroresActionErrors theActionErrors = null;Connection conn = null;Statement stmn = null;

try {// Casting de ActionForm a nuestro FORM concretoAltaForm form = (AltaForm)theActionForm;

// AQUI SER REALIZA UNA CONEXION A UNA ORIGEN DE DATOS ODBC,// PARA INSERTAR EL NUEVO USUARIO. NO RESULTA UNA FORMA MUY

CORRECTA// DE HACERLO, MENOS AUN EN SERVIDORES DE APLICACIONES Y EN

APLICACIONES// BIEN ESTRUCTURADAS, PERO PARA SIMPLIFICAR EL EJEMPLO SE HA

HECHO ASI.Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");conn =

DriverManager.getConnection("jdbc:odbc:usuarios","db_user","db_password");

// CREAMOS la SENTENCIAstmn = conn.createStatement();// Siii, ya se que es una forma poco elegante de alterar// la BBDD, pero se trata de simplificar el ejemplo.stmn.executeUpdate("INSERT INTO USUARIOS VALUES

('"+form.getUsername()+"','"+form.getPassword()+"',"+form.getEdad()+",'"+form.getFechanacimiento()+"','"+form.getProfesion()+"')");

// Cerramos sentencia y conexionstmn.close();conn.close();

// Si llegamos aqui: Devolvemos objeto ActionErrors (nulo == sinerror)

return theActionErrors;

} catch(Exception e){e.printStackTrace(System.out);//Escribe en el fichero de log del

servidor de aplicacionestheActionErrors = new ActionErrors();theActionErrors.add("alta",new ActionError("alta.bean.error"));return theActionErrors;

}

} //Logica de Negocio

} // Fin class

Page 24: Manual - Programacion - Java - Struts

http://www.javahispano.com

24

confirmacionalta.jsp<%@ page language="java" %><%@ taglib uri="/WEB-INF/app.tld" prefix="app" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html><head>

<title>STRUTS :: ejemplo de ALTA :: Confirmacion ALTA</title></head>

<body><!-- mensaje de confirmación recuperando el nombre de usuario --><h3>Alta de usuario <bean:write name="altaForm" property="username"/>

correcta</h3>

</body></html:html>

errorAlta.jsp<%@ page language="java" %><%@ taglib uri="/WEB-INF/app.tld" prefix="app" %><%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %><%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %><%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %><html:html><head>

<title>Error en el proceso de alta de usuario</title></head><body><table cellspacing="8" cellpadding="8" border="0" align="center">

<tr><td colspan ="3">

<H3><b>Se ha producido un error en la operacion.</b></H3></td>

</tr><td align="center">

<input type="button" name="volver" value="Volver"onclick="javascript:history.back()">

</td></tr>

</table></body><!-- Esta etiqueta de struts devuelve TODOS los mensajes de error guardadosen ActionErrors con el nombre "alta" a lo largo del request --><h3><center><html:errors property="alta" /><center><h3></html:html>

Page 25: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

25

Configuracion del fichero struts-config.xml para este sencillo caso.Se debiera añadir, dentro de action mappings:

<!--Alta form Formulario definido en la zona de formularios--><form-bean name="altaForm" type="pxai.struts.alta.form.AltaForm"/>

<!-- Edit/Save alta--><!-- path: el nombre que debe especificarse en la url para acceder --><!-- type: la clase asociada a la accion, con la ruta del paquete si la tuviere --><!-- name: nombre del formulario asociado con esta accion Normalmente No requerido parauna carga de pagina o accion Edit--><!-- scope: ambito de validez de ese formulario (request o peticion): puede ser session--><!-- input: origen de los datos. No imprescindible --><!-- validate: si se va a validar el formulario o no.--><action path="/editAlta" type="pxai.struts.alta.action.EditAltaAction" name=""scope="request" validate="false"><forward name="success" path="/alta.jsp"/></action><action path="/saveAlta" type="pxai.struts.alta.action.SaveAltaAction" name="altaForm"scope="request" input="/alta.jsp" validate="true"><forward name="success" path="/confirmacionalta.jsp"/><forward name="failure" path="/erroralta.jsp"/></action>

Este sería el formulario de alta, al que accedemos a través de la url “editAlta.do”, tal como seespecifica en struts-config.xml. Al invocar editAlta.do, según el “mapa” de acciones de Struts,se invoca la clase EditAltaAction y esta a su vez carga la JSP alta.jsp.

Page 26: Manual - Programacion - Java - Struts

http://www.javahispano.com

26

El formulario se envía a la url saveAlta.do, que según el “mapa” de acciones de strutsespecificado en strtus-config.xml, provoca la carga de SaveAltaAcion; esta instancia invoca lalógica de negocio (AltaBean) y devuelve un resultado (un objeto ActionErrors que puede estarcargado o ser nulo). Si el bean de lógica de negocio devuelve un valor nulo en el ActionErrors,todo ha ido correctamente y se mostrará la siguiente página.

En caso contrario, según el struts-config.xml se redirigiría el flujo a la página de error“erroralta.jsp”, que sencillamente mostraría un mensaje de error al usuario.

Page 27: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

27

TIPSA continuación se explican una serie de soluciones para ciertas necesidadesfrecuentes en la programación Web; básicamente se trata de modos de comunicar lasclases de la capa de negocio con los JSP.Entre la logica de negocio y un JSP de presentación media una clase de la capaController. Lo que las une a las tres es el la instancia actual dejavax.servlet.http.HttpServletRequest; En ese request se pueden cargar resultados quepodemos presentar mas tarde en JSP. Struts lo hace implicitamente con el lasinstancias de lal clases Formulario.

-Mostrar valores de los Bean por pantalla:Dentro de un objeto action, debemos guardar el Bean en la sesion:

..// En un bean de negocio se puede cargar un objeto en el request// para poder recuperarlo en el JSP con etiquetas STRUTS// También se podría hacer en el objeto action (editXAction, saveXAction,// etc...), aunque no quedaría muy limpio.// Creamos el objeto Red, le asignamos valores, y lo añadimos a las// propiedades del request, para poder recuperarlo en la JSP.Red red2 = new Red();

red2.setNombre("SuperRed");red2.setCodigo(747);red2.setTipo("Red IP de telefonica");red2.setIp("166.166.166.100");

request.setAttribute("red2",red2);

...// en el JSP

<bean:write name="red2" property="nombre"scope="request"/>

//eso sacaria por pantalla: SuperRed

-Mostrar valores en Iteracion.Es parecido a mostrar un bean por pantalla, salvo que hay que definir unbean de tipo Vector, Lista, etc...

// Supongamos que definimos un objeto llamado Redespublic class Redes extends Vector {...}

..// Al igual que antes, en un Bean de negocio cargamos un objeto// en el request para poder recuperarlo mas tarde.// Creamos el objeto Redes, le asignamos valores, y lo añadimos a las// propiedades del request, para poder recuperarlo en la JSP.Redes redes = new Redes();

redes.addElement("www.el-mundo.es");redes.addElement("www.elpais.es");redes.addElement("www.cisco.com");redes.addElement("www.a3n.tv");

request.setAttribute("misredes",redes);...// en el JSP utilizamos el tag logic:iterate

Page 28: Manual - Programacion - Java - Struts

http://www.javahispano.com

28

// donde://lista: bean en el que se guarda cada elemento de iteracion//type: el tipo Java de ese elemento//name: nombre del atributo que contiene los valores// que debe coincidir con el que usamos en "setAttribute"

<logic:iterate id="lista" name="misredes"type="java.lang.String">

<bean:write name="lista" /><br></logic:iterate>// Lo cual mostrara por pantalla:www.cisco.comwww.el-mundo.eswww.elpais.eswww.jazztel.comwww.a3n.tv

Nota: a traves de los tag logic se pueden realizar comapraciones de valoresy se puede condicionar los valores a mostrar. Para conocer estos y otros tagsmirar documentacion sobre tags.(http://jakarta.apache.org/struts/userGuide/index.html)(http://jakarta.apache.org/struts/api-1.0/org/apache/struts/taglib/logic/package-

summary.html)

-Mostrando valores de ResultSet.El caso mas usual en aplicaciones web es el de mostrar el resultado de una consultapor pantalla. Esto se puede hacer de manera parecida a la anterior, pero habria quemapear el ResultSet a una estructura que pueda recorrerse iterativamente; segun ladocumentacion de Struts la estructura puede ser Enumeration,Hashtable, Vector o unarray de Objetos.

-Fichero con mensajes y etiquetas:AplicationResources.properties, debe estar colocado junto a los ficheros .class destruts.Si se realizan cambios en el, hay que reiniciar jrun. Para mostrar estasetiquetas, debe crearse el siguiente tag:<bean:message key="mensaje01"/>En el fichero de AplicationResources.propertiesmensaje01=Introduzca el usuario

Para mostrar mensajes de error (los que cargamos en el ActionErrors)En las clases actio, Form o Bean capturamos un errorActionErrors errors = new ActionErrors();errors.add(“alta”,new ActionError(“alta.error”));saveErrors(errors);

En el fichero JSP añadimos el TAG:<html:errors property="alta" />

En el fichero de AplicationResources.propertiesalta.error=Se ha producido un error al dar de alta.

Page 29: Manual - Programacion - Java - Struts

STRUTS:Implementación del patrón MVC en aplicaciones Web

29

Errores comunes con Struts

- Erorres en el mapa de acciones.Es muy frecuente a la hora de desarrollar aplicaciones con Struts no indicar correctamente elnombre de una aplicación, de una clase de formulario, etc… hay que revisar el struts-config.xmlpara comprobar que los nombres de clases que ahí se especifican son los correctos y secorresponden con las clases generadas.Hay que tener especial cuidado también (como en cualquier otra aplicación Java) con lanomenclatura de los paquetes que precede al nombre de la clase.De todas formas, la plataforma struts nos avisa sobre los errores de este tipo y nos dice que talacción no existe en el mapa, o que tal formulario tampoco esta definido o no se correspondecon la acción. Lo veremos en forma de excepción de mapping.A veces, como consecuencia de un copy-paste en el struts-config.xml, pueden quedarmapeadas acciones que existen pero que no se corresponden con lo que queremos; en esoscasos no hay error por la inexistencia de un fichero, y se puede hacer difícil detectar elproblema.La solución universal siempre será REVISAR bien los nombres hasta que nos lloren los ojos; laevidencia empírica a demostrado que la mayoría de problemas en ese sentido vienen porerrores en los nombres.

- java.lang.NullPointerExceptionEste error será el pan nuestro de cada día en el desarrollo de Struts ya que los datos de losformularios deben viajar desde una jsp pasando por 3 clases, y es fácil que no todos los datoslleguen cargados. Lo que se recomienda es que cuando se desarrolle el Bean de lógica denegocio, en principio solo se haga una traza de los valores del formulario, para comprobar quellegan como se espera. Una vez depurado el paso de datos, conviene tener la costumbre(como en cualquier otra aplicación, en cualquier otro lenguaje), de comprobar los objetospara ver si realmente traen un valor distinto de nulo, y en caso afirmativo asignarlo. En unasola linea se puede comprobar y asignar:

//aquí va un atentado contra la legibilidad:(<condicion>)?val1:val2;codigo = (formulraio.getCodigo() != null) ?formulario.getCodigo():new Integer(0);

El formulario puede traer valores vacíos (Strings “”) o nulos. Dependiendo de nuestra lógica denegocio habrá que comprobar lo que llega desde la jsp y transformarlo. Por ejemplo, en el casode una cadena de caracteres, en caso de venir vacía o con espacios quizá nos intereseconvertirla a null:

// Dentro de la clase Formpublic void setNombre (String nombre) {

if (nombre.trim().compareTo(“”) == 0) // si es nulothis.nombre = null;

elsethis.nombre = nombre;

}o más brevemente:

public void setNombre (String nombre) {this.nombre = (nombre.trim().compareTo(“”) == 0)?null:nombre;

}