Vous êtes sur la page 1sur 24

Home | Quienes Somos | Empleo | Foros | Tutoriales | Servicios Gratuitos | Contacte

Descargar este documento en formato PDF strutsb.pdf



CMO CREAR UNA APLICACIN CON STRUTS PASO A PASO
Como ya se introduce en el tutorial de Struts Jakarta, estamos ante un entorno (framework) normalizado de presentacin. Dicho as
puede quedar un poco confuso, pero veamos como encajndolo dentro de la arquitectura de desarrollo MVC (Modelo-Vista-
Controlador) seguro que descubrimos cunto nos puede ayudar Struts.
Struts se encarga de normalizar (o al menos intentarlo) el desarrollo de la capa Vista dentro de la arquitectura MVC. Sin embargo,
es necesario que para tal fin, tambin proporcione mecanismos para trabajar con la capa C. Pero nunca Struts se mezclar con la
capa del Modelo. Esta caracterstica principal de Struts permite separar la lgica de presentacin de la lgica del negocio, con las ya
consabidas ventajas que este tipo de desarrollo supone.
Este tutorial que aqu se presenta pretende mostrar cmo llevar a cabo la tarea de desarrollar una aplicacin Web utilizando la API
de Struts; pero, adems, est concebido de forma que se demuestra la independencia completa de Struts con el modelo de negocio
y, como consecuencia, con la tecnologa utilizada para implementar la capa M. As, este tutorial utiliza:
Struts para el desarrollo de la capa de Vista y Control (presentacin Web)
Un servicio JDBC simple para la capa de Modelo (sin EJBs)
Aunque en la mayora de los casos el uso de Struts se aconseja en el desarrollo de aplicaciones muy complejas y, casi siempre, se
utilizarn EJBs para la capa de negocio (modelo), la idea es presentar en este tutorial una primera aproximacin a Struts de la
manera ms sencilla posible (a pesar de la complejidad de este framework). De esta forma, en un posterior tutorial de continuacin,
se mostrar cmo la inclusin de EJBs en nuestra aplicacin no supondr tocar ni una lnea de cdigo de las capas V y C, y slo
habr que modificar (y ligeramente) la capa de Modelo.
Nuestra aplicacin ejemplo: un carrito de la compra
Quizs la aplicacin ms ilustrativa y ms sencilla de asimilar sea un carrito de la compra. Por ello, hemos decidido implementar
este tipo de aplicacin sin ningn tipo de pretensiones, ya que el objetivo de este tutorial es comprender y aprender a manejar
Struts, y no crear una aplicacin profesional de e-commerce, por ejemplo.
Entre las caractersticas que tendr nuestra aplicacin ejemplo destacamos el uso de:
ActionForms, tanto estticos como dinmicos (DynaActionForm).
Tiles, para creacin y trabajo con plantillas (pginas Web).
Acciones nicas (Action) y de grupo (DispatchAction).
ActionMappings, que permiten mapear las caractersticas de las acciones en un fichero externo XML.
ActionErrors, para devolver mensajes de error en la validacin de formularios ActionForms.
Contenedor, para guardar toda la informacin necesaria de sesin.
Struts Tags, librera de etiquetas que nos ahorrarn mucho cdigo.
Patrones de diseo: Business Delegate, Business Interface y DTOs (Data Transfer Objects) o Value Objects.
Servicios, para conexin con la BD mediante JDBC.
Como podis comprobar, se ha intentado hacer uso de prcticamente toda la tecnologa inherente en Struts, aunque por cuestiones
de complejidad, no se hace uso de aproximaciones ms optimizadas (como usar un mapeador objeto/relacional, el validador de
Struts, ms patrones de diseo como Dynamic Proxy, etc.).
En cuanto a las herramientas utilizadas para desarrollar la aplicacin, se ha optado por utilizar las ms fciles de manejar: un editor
de texto (os recomiendo alguno que "sepa" Java para que os marque los errores de sintaxis, aunque yo he utilizado uno genrico) y
JBoss (ya que es gratuito y soporta EJBs). La idea de hacerlo as se debe a que el uso de herramientas de mercado como JBuilder,
obvian algunos detalles del desarrollo que son imprescindibles conocer para entender y comprender cmo funciona Struts.
Por dnde empiezo?
Esta pregunta es bsica a la hora de afrontar un proyecto complejo de desarrollo, sea de la naturaleza que sea. Este tutorial no
pretende desarrollar una ingeniera del software, pero s desmenuzar de una forma directa los pasos a seguir en el desarrollo de
nuestra aplicacin.
Gracias a la arquitectura MVC, podramos desarrollar por un lado la interfaz del cliente Web, y delegar en otro equipo de desarrollo
la parte de la lgica de negocio. En nuestro caso primero desarrollaremos la parte de negocio, para terminar implementando la capa
de presentacin y control (ms que nada, por claridad en el desglose de los conceptos y su aplicacin prctica).
Tutorial desarrollado por:
Enrique Medina Montenegro
Puedes ver mi CV y contratarme en:

Pagina 1 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Entender cmo trabaja Struts
Antes de entrar en detalles especficos de nuestra aplicacin, debemos entender cmo trabaja Struts para poder afrontar con xito
otro tipo de desarrollos y aplicaciones.

Como se aprecia en la figura, las aplicaciones Struts residen en un contenedor Web (dentro de un servidor de aplicaciones) y
pueden hacer uso de los servicios proporcionados por el contenedor, como el manejo de peticiones HTTP o HTTPS. Esto permite al
desarrollador olvidarse de la lgica de negocio. As, Struts hace uso de varias reas de recursos compartidos para almacenar
objetos: peticin (javax.servlet.http.HttpServletRequest), sesin (javax.servlet.http.HttpSession), aplicacin
(javax.servlet.ServletContext) y pgina (javax.servlet.jsp.PageContext).
Desde el punto de vista de la arquitectura MVC, las clases que proporciona Struts respecto de la capa C son:

ActionServlet, clase que extiende javax.servlet.http.HttpServlet responsable del empaquetado y enrutado del trfico HTTP
hacia el manejador apropiado dentro del entorno (framework). No es abstracta, y por tanto se puede utilizar directamente
en cualquier aplicacin.
RequestProcessor, clase que permite desacoplar el proceso de peticin (request process) del ActionServlet y as poder
modificar cmo se procesa la peticin (haciendo un 'subclass' de RequestProcessor).
Action, clase que independiza la peticin del cliente del modelo de negocio. Es una extensin del componente de control
(capa C) y permite llevar a cabo funciones como autorizacin, logging, o validacin de sesin, antes de invocar la lgica de
negocio. Su mtodo ms importante es:
public ActionForward execute(ActionMapping mapping, HttpServletRequest request, HttpServletResponse response) throws
Exception;
ActionMapping, clase que representa una accin de mapeado que se define en el fichero de configuracin de Struts. Indica
al controlador que instancia de Action se debe invocar en cada peticin.
ActionForward, clase que representa el destino al cual el controlador debe enviar el control una vez que una Action se ha
completado (nos evitamos meter el 'forward' en la pgina JSP).
Pagina 2 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb

Con respecto de la capa M, ya hemos comentado que Struts no fue diseado para trabajar con esta capa. Sin embargo, es obvio que
Struts recibir informacin de esta capa (aunque no sepa cmo est implementada). As, la mejor forma de solucionar cmo Struts se
comunica con la capa de negocio de forma que sea completamente independiente de la tecnologa de implementacin de sta, es
utilizar un patrn de diseo, como por ejemplo DTOs (Data Transfer Objects), tambin llamados Value Objects (VO).
La idea es que Struts reciba la informacin en forma de vistas (VOs), pero no sepa cmo se han creado esas vistas. Para ello tambin
necesitaremos implementar un nuevo patrn de diseo muy conocido, el Business Delegate. Con este patrn, crearemos un servicio
perteneciente a la capa de negocio, que servir de nexo de unin con la capa de control y ser a travs del cual Struts pedir y recibir
los nicos objetos que entiende y con los que sabe trabajar: los VOs. Por el otro lado, la capa de negocio slo sabr que puede recibir
peticiones del servicio de acceso a BD a travs de JDBC y devolver VOs, sin importarle ni quin los pide ni quin los usa a
continuacin (no os preocupis que con los ejemplos se ver mucho ms claro).
Por ltimo, con respecto a la capa V, los elementos de los que hace uso Struts son (algunos ya los conocemos):
HTML
Value Objects (vistas)
ActionForms, clase que permite pasar datos de entrada hacia delante y hacia atrs entre el usuario y la capa de negocio.
JavaServer Pages
Struts Tags (librera de etiquetas)
Otros recursos Java
Paso a paso: la capa del modelo de negocio
Veamos, tal y como se ha comentado, en primer lugar cmo ir desarrollando el cdigo de la lgica de negocio para nuestra aplicacin
del carrito de la compra.

As, primero creamos las vistas (VOs) que necesitaremos en nuestra aplicacin. Para optimizar la implementacin, primero creamos
una superclase BaseVO que extendern el resto de vistas. La creamos que implemente java.io.Serializable para que pueda ser
referenciada desde un interfaz remoto (cuando implementemos por ejemplo los EJBs):
package com.tutorial.struts.vo;
import java.sql.Timestamp;
// Clase Value Object de la que todas las vistas deberan descender.
public class BaseVO implements java.io.Serializable
{
private int id;
private Timestamp timeCreated = null;
Pagina 3 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Como se puede observar, la clase implementa un JavaBean muy simple con los mtodos set/get necesarios. Ahora implementamos
una clase que extiende de BaseVO para representar a los productos (ProductoVO):
private String description;
private String name;
// Constructor por defecto.
public BaseVO()
{
super();
setTimeCreated(new Timestamp(System.currentTimeMillis()));
}
// Constructor a partir de los datos.
public BaseVO(int id, String name, String desc)
{
this();

this.id = id;
this.name = name;
this.description = desc;
}
public void setName(String name)
{
this.name = name;
}

public void setTimeCreated(Timestamp now)
{
timeCreated = now;
}

public void setDescription(String description)
{
this.description = description;
}

public void setId(int id)
{
this.id = id;
}

public String getName()
{
return name;
}

public String getDescription()
{
return description;
}

public int getId()
{
return id;
}

public Timestamp getTimeCreated()
{
return timeCreated;
}

}
package com.tutorial.struts.vo;
// Clase Value Object que implementa la vista del producto.
public class ProductoVO extends BaseVO
{
// Datos del VO Producto.
private String smallImageURL;
private double basePrice;

// Constructor por defecto.
public ProductoVO()
{
super();
}

// Constructor a partir de los datos.
public ProductoVO(int id, String name, String desc, double price, String smallImageURL)
{
super(id, name, desc);

setBasePrice(price);
setSmallImageURL(smallImageURL);
Pagina 4 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Y tambin una clase que represente la vista del usuario (UserVO), que utilizaremos posteriormente para crear el contenedor de los
datos de la sesin:
Ya tenemos creadas todas las vistas (VOs) que necesitamos para nuestra aplicacin. Ahora vamos a centrarnos en la implementacin
del servicio que conectar mediante JDBC con nuestra BD y devolver la vista adecuada (patrn Business Delegate). Para ello,
utilizamos el patrn de diseo Business Interface, segn el cual primero creamos un interface a modo de 'caja negra', que ser el nico
que conozca el cliente. As, incluso podremos modificar el comportamiento del servicio sin que se entere Struts. El cdigo para la clase
ICarritoService se muestra a continuacin:
Aqu deben declararse todos los mtodos de negocio que utilizar nuestra aplicacin y que podrn ser llamados desde la parte del
cliente. A continuacin, implementamos el interface mediante la clase CarritoServiceImpl, que es donde va la lgica de negocio:
}
// ... resto de mtodos get/set ...
}
package com.tutorial.struts.vo;
import com.tutorial.struts.vo.BaseVO;
// Clase Value Object que implementa una vista del usuario.
public class UserVO extends BaseVO
{
private String lastName;
private String firstName;
private String emailAddress;

public UserVO()
{
super();
}
// ... resto de mtodos get/set ...
}
package com.tutorial.struts.service;
import javax.servlet.ServletContext;
import java.util.List;
// Imports de clases propias de la aplicacin.
import com.tutorial.struts.vo.ProductoVO;
import com.tutorial.struts.vo.UserVO;
public interface ICarritoService
{
public List getListaProducto();

public ProductoVO getDetalleProducto(String itemId);
public void setServletContext(ServletContext ctx);

public UserVO authenticate(String email, String password);

public void logout(String email);
public void destroy();
}
package com.tutorial.struts.service;
import java.util.List;
import java.util.LinkedList;
import javax.servlet.ServletContext;
import java.sql.*;
import java.io.*;
// Imports de las clases propias de la aplicacin.
import com.tutorial.struts.vo.ProductoVO;
import com.tutorial.struts.vo.UserVO;
// Implementamos el servicio que nos da acceso a los datos de la aplicacin (BD).
public class CarritoServiceImpl implements ICarritoService
{
ServletContext servletContext = null;
// Referencia de conexin a una BD con JDBC.
Connection con = null;
/**
Pagina 5 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
* Creamos el servicio, que incluye inicializar la conexin con la BD..
**/
public CarritoServiceImpl()
{
super();

// Abrimos la conexin con la BD.
init();
}
public void setServletContext(ServletContext ctx)
{
this.servletContext = ctx;
}
public ServletContext getServletContext()
{
return servletContext;
}
/**
* Devolvemos la lista de todos los productos.
**/
public List getListaProducto()
{
// Devolvemos una lista de los productos.
List listaProducto = new LinkedList();
ResultSet result = null;

try
{
// Componemos la sentencia SQL para obtener los productos.
String query = "SELECT * FROM PRODUCTO";

// Ejecutamos la query y obtenemos el resultado.
Statement stmt = con.createStatement();
result = stmt.executeQuery(query);
int id;
String nombre, descripcion, smallImageURL;
double basePrice;

while (result.next())
{
id = result.getInt("id");
nombre = result.getString("nombre");
descripcion = result.getString("descripcion");
smallImageURL = result.getString("smallImageURL");
basePrice = result.getDouble("basePrice");

ProductoVO productoVO =
new ProductoVO(id, nombre, descripcion, basePrice, smallImageURL);

System.out.println(productoVO.toString());

listaProducto.add(productoVO);
}
}
catch (SQLException se)
{
System.err.println("Se ha producido un error de BD.");
System.err.println(se.getMessage());
}

return listaProducto;
}

/**
* Devuelve una vista detallada de un producto.
**/
public ProductoVO getDetalleProducto(String productoId)
{
ResultSet result = null;
ProductoVO productoVO = null;

try
{
// Componemos la sentencia SQL para obtener los productos.
String query = "SELECT * FROM PRODUCTO WHERE ID = " + productoId;

// Ejecutamos la query y obtenemos el resultado.
Statement stmt = con.createStatement();
result = stmt.executeQuery(query);

// Vemos si no ha devuelto ningn resultado.
if (!result.next())
{
throw new SQLException();
Pagina 6 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
}

// Construimos una VO para el producto.
String nombre, descripcion, smallImageURL;
double basePrice;
int id = result.getInt("id");

nombre = result.getString("nombre");
descripcion = result.getString("descripcion");
smallImageURL = result.getString("smallImageURL");
basePrice = result.getDouble("basePrice");

productoVO = new ProductoVO(id, nombre, descripcion, basePrice, smallImageURL);
}
catch (SQLException se)
{
System.err.println("Se ha producido un error de BD.");
System.err.println(se.getMessage());
}
return productoVO;
}
/**
* Autenticamos los credenciales del usuario y devolvemos un VO o null.
**/
public UserVO authenticate(String email, String password)
{
ResultSet result = null;
UserVO userVO = null;

try
{
// Componemos la sentencia SQL para obtener los productos.
String query = "SELECT * FROM USUARIO WHERE EMAIL = ? AND PASSWORD = ?";

PreparedStatement ps = con.prepareStatement(query);

// Pasamos los parmetros a la query.
ps.setString(1, email);
ps.setString(2, password);

// Ejecutamos la query y obtenemos el resultado.
result = ps.executeQuery();
if (result.next())
{
// Construimos el VO a partir de los datos de la query.
userVO = new UserVO();

userVO.setId(result.getInt("id"));
userVO.setFirstName(result.getString("FirstName"));
userVO.setLastName(result.getString("LastName"));
userVO.setEmailAddress(result.getString("Email"));
}
}
catch (SQLException se)
{
System.err.println("Se ha producido un error de BD.");
System.err.println(se.getMessage());
}

return userVO;
}
/**
* Desloguea al usuario del sistema.
**/
public void logout(String email)
{
// No hacemos nada de momento ...
}
public void destroy()
{
// Cerramos la conexin con la BD.
try
{
con.close();
}
catch (SQLException se)
{
System.err.println("Se ha producido un error al cerrar la conexin de BD.");
System.err.println(se.getMessage());
}
}
/**
* Abre la conexin con la BD.
Pagina 7 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Una vez implementado el servicio, necesitamos crear una clase factora de servicios para que el cliente pueda crear el servicio y hacer
uso de l. Para ello tenemos la clase ICarritoServiceFactory:
La idea es igual que en el caso anterior. Ahora la clase que implementa el interface, CarritoServiceFactory:
Expliquemos con detalle la implementacin de la factora de servicios. Primero, implementa la clase PlugIn, exclusiva de Struts, que
permite que una clase externa a Struts se cargue como un mdulo adicional en el entorno; en otras palabras, permite introducir en el
contexto del controlador de Struts el servicio para que est disponible siempre (public void init(ActionServlet servlet, ModuleConfig
config) throws ServletException).
**/
private void init()
{
// Aqu debe ir la carga del driver y la conexin
try
{
Class.forName("org.gjt.mm.mysql.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost/carrito", "root", "");
}
catch (SQLException se)
{
System.err.println("Se ha producido un error al abrir la conexin de BD.");
System.err.println(se.getMessage());
}
catch (java.lang.ClassNotFoundException s)
{
System.out.println("No se encuentra la clase "+ s.toString());
}
}
}
package com.tutorial.struts.service;
public interface ICarritoServiceFactory
{
public ICarritoService createService()
throws ClassNotFoundException, IllegalAccessException, InstantiationException;

public void destroy();
}
package com.tutorial.struts.service;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.struts.action.PlugIn;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.config.ModuleConfig;
import com.tutorial.struts.service.*;
/**
* Una factora para crear instancias del servicio para la aplicacin.
*/
public class CarritoServiceFactory implements ICarritoServiceFactory, PlugIn
{
private ActionServlet servlet = null;
String serviceClassname = "com.tutorial.struts.service.CarritoServiceImpl";
public ICarritoService createService()
throws ClassNotFoundException, IllegalAccessException, InstantiationException
{
ICarritoService instance = (ICarritoService)Class.forName(serviceClassname).newInstance();

instance.setServletContext(servlet.getServletContext());

return instance;
}

public void init(ActionServlet servlet, ModuleConfig config) throws ServletException
{
// Nos guardamos el servlet para despus.
this.servlet = servlet;
// Guardamos la factora del servicio en el contexto del servlet que Struts utiliza como controlador.
// As estar siempre disponible para quien la necesite dentro de Struts.
servlet.getServletContext().setAttribute("com.tutorial.struts.service.ICarritoServiceFactory", this);
}

public void destroy()
{
// No hacemos nada de momento ...
}
}
Pagina 8 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Luego vemos tambin que proporciona el mtodo a travs del cual el cliente podr crear una instancia del servicio siempre que lo
necesite (public ICarritoService createService() throws ClassNotFoundException, IllegalAccessException, InstantiationException).
Para decirle a Struts que se trata de un PlugIn y que lo cargue al inicializar la aplicacin debemos incluir lo siguiente en el fichero
externo struts-config.xml:
Paso a paso: la capa del controlador Struts
Una vez hemos creado las clases e interfaces necesarios para la lgica de negocio, pasamos a desarrollar la parte correspondiente a la
capa de control. Como vimos anteriormente, esta capa s forma parte del entorno Struts y, por lo tanto, har uso de la API de Struts
en su desarrollo.
Primero vamos a extender las clases de control de Struts para adaptarlas a nuestras necesidades. Empezaremos por extender la clase
org.apache.struts.action.Action para que, cada vez que realicemos alguna accin Struts, tengamos disponible una instancia del
servicio, tal y como lo hemos implementado anteriormente. La idea es que siempre que ejecutemos una accin podamos usar los
mtodos del servicio para obtener los productos, autenticarnos, etc. El cdigo de la clase abstracta CustomBaseAction es:
<plug-in className="com.tutorial.struts.service.CarritoServiceFactory"/>
package com.tutorial.struts;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Iterator;
import javax.servlet.http.*;
import org.apache.struts.action.*;
// Imports de clases propias de la aplicacin.
import com.tutorial.struts.service.ICarritoService;
import com.tutorial.struts.service.ICarritoServiceFactory;
// Clase abstracta de Action que todas las acciones deben extender.
abstract public class CustomBaseAction extends Action
{
protected ICarritoService getCarritoService()
{
// Obtenemos la factora que nos permitir crear el servicio.
ICarritoServiceFactory factory = (ICarritoServiceFactory)getApplicationObject
("com.tutorial.struts.service.ICarritoServiceFactory");
ICarritoService service = null;

try
{
service = factory.createService();
}
catch(Exception ex)
{
System.out.println("Error al crear el servicio...");
System.out.println(ex.getMessage());
}

return service;
}
// Mtodo auxiliar para obtener un objeto de la sesin por su nombre.
protected Object getSessionObject(HttpServletRequest req, String attrName)
{
Object sessionObj = null;
HttpSession session = req.getSession(false);

if (session != null)
{
sessionObj = session.getAttribute(attrName);
}

return sessionObj;
}
// Obtenemos el contenedor del usuario que est en la sesin.
protected UserContainer getUserContainer(HttpServletRequest request)
{
UserContainer userContainer = (UserContainer)getSessionObject(request, "UserContainer");

// Creamos un UserContainer para este usuario si no existe ...
if(userContainer == null)
{
userContainer = new UserContainer();

HttpSession session = request.getSession(true);
session.setAttribute("UserContainer", userContainer);
}

return userContainer;
Pagina 9 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Adems, tambin hacemos lo mismo extendiendo la clase org.apache.struts.action.DispatchAction. El cdigo de la clase
CustomDispatchAction es prcticamente idntico al anterior:
Los dos mtodos ms importantes son el que permite crear el servicio para el cliente (protected ICarritoService getCarritoService()) y
el que permite obtener el contenedor del usuario con los datos de la sesin (protected UserContainer getUserContainer
(HttpServletRequest request)). Por ello, debemos a continuacin crear la clase que implementa el contenedor UserContainer, que
contendr tanto la informacin del usuario como el carrito de la compra actual:
}
// Obtenemos un objeto del contexto de la aplicacin por su nombre.
protected Object getApplicationObject(String attrName)
{
return servlet.getServletContext().getAttribute(attrName);
}
}
package com.tutorial.struts;
import javax.servlet.http.*;
import com.tutorial.struts.service.ICarritoService;
import com.tutorial.struts.service.ICarritoServiceFactory;
import org.apache.struts.actions.DispatchAction;
public class CustomDispatchAction extends DispatchAction
{
// ... igual que la clase anterior CustomBaseAction ...
}
package com.tutorial.struts;
import java.util.Locale;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionBindingEvent;
import com.tutorial.struts.vo.UserVO;
// Almacena la informacin del usuario en su sesin.
// Implementa el interfaz HttpSessionBindingListener para que se le notifique
// el timeout y as pueda liberar los recursos de la sesin.
public class UserContainer implements HttpSessionBindingListener
{
// El carrito de la compra del usuario.
private Carrito cart = null;
// Almacenamos la informacin del usuario.
private UserVO userVO = null;

// Constructor por defecto.
public UserContainer()
{
super();
initialize();
}
// El contenedor llama a este mtodo cuando se termina la sesin.
public void valueUnbound(HttpSessionBindingEvent event)
{
// Liberamos recursos de la sesin.
System.out.println( "Liberando sesin...");
cleanUp();
}
public Carrito getCart()
{
return cart;
}
public void setCart(Carrito newCart)
{
cart = newCart;
}
// El contenedor llama a este mtodo cuando comienza la sesin.
public void valueBound(HttpSessionBindingEvent event)
{
// No hacemos nada por ahora ...
}
public UserVO getUserVO()
{
return userVO;
}
Pagina 10 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Como se puede apreciar, hemos tomado la decisin de no hacer el carrito persistente, es decir, trabajamos con el carrito en memoria
dentro del contenedor en la sesin, de forma que se pierde cuando nos salimos de la aplicacin. Una buena idea para optimizar la
aplicacin sera dotar de persistencia al carrito y que el usuario pudiera recuperar su pedido en posteriores sesiones.
Pero para nuestro ejemplo, el carrito se implementar como un JavaBean que ir dentro del contenedor en la sesin del usuario. Para
ello creamos dos clases: una llamada Carrito, y otra llamada CarritoProducto, que sern las lneas de detalle de nuestro carrito:
public void setUserVO(UserVO newVO)
{
userVO = newVO;
}
// Inicializacin de los datos del usuario en sesin.
private void initialize()
{
// Create a new Shopping cart for this user
cart = new Carrito();
}
// Liberamos recursos de la sesin.
public void cleanUp()
{
setUserVO(null);
cart = new Carrito();
}
}
package com.tutorial.struts;
import java.util.List;
import java.util.LinkedList;
// Clase JavaBean que implementa un carrito de la compra en memoria (no es persistente).
public class Carrito
{
private List productos = null;
// Constructor por defecto (crea una lista enlazada vaca).
public Carrito()
{
productos = new LinkedList();
}

public void addProducto(CarritoProducto newProducto)
{
// Miramos si este producto ya est en el carrito.
// Si ya est simplemente incrementamos su cantidad.
CarritoProducto cartProducto = findProducto(Integer.toString(newProducto.getId()));

if (cartProducto != null)
{
cartProducto.setQuantity(cartProducto.getQuantity() + newProducto.getQuantity());
}
else
{
// Es un producto que no estaba; lo aadimos al carrito.
productos.add(newProducto);
}
}

// Aadimos una lista de productos.
public void setProductos(List otherProductos)
{
productos.addAll(otherProductos);
}

public void setSize(int size)
{
// El tamao es el de la lista enlazada.
// Pero hay que implementar este mtodo al tratarse de un JavaBean.
}

public int getSize()
{
return productos.size();
}
public void empty()
{
productos.clear();
}

public double getTotalPrice()
{
double total = 0.0;
Pagina 11 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
int size = productos.size();

for (int i = 0;i < size;i++)
{
total += ((CarritoProducto)productos.get(i)).getImporte();
}

return total;
}

public void removeProducto(String productoId)
{
CarritoProducto producto = findProducto(productoId);

if (producto != null)
{
productos.remove(producto);
}
}

public void removeProductos(List productoIds)
{
if (productoIds != null)
{
int size = productoIds.size();

for (int i = 0;i < size;i++)
{
removeProducto((String)productoIds.get(i));
}
}
}

public void updateQuantity(String productoId, int newQty)
{
CarritoProducto producto = findProducto(productoId);

if (producto != null)
{
producto.setQuantity(newQty);
}
}

public List getProductos()
{
return productos;
}

private CarritoProducto findProducto(String productoId)
{
CarritoProducto producto = null;
int size = getSize();

for (int i = 0;i < size;i++)
{
CarritoProducto cartProducto = (CarritoProducto)productos.get(i);

if (productoId.equals(Integer.toString(cartProducto.getId())))
{
producto = cartProducto;
break;
}
}

return producto;
}

}
package com.tutorial.struts;
import com.tutorial.struts.vo.ProductoVO;
// Clase JavaBean que almacena las lneas de un carrito de la compra.
public class CarritoProducto
{
// Importe es el precio de unidad * cantidad.
private double importe = 0.0;
private ProductoVO producto = null;
// Cantidad por defecto a 1.
private int quantity = 1;

// Constructor de lnea a partir de un producto y su cantidad.
public CarritoProducto(ProductoVO producto, int qty)
{
this.producto = producto;
this.quantity = qty;
calculateImporte();
}
Pagina 12 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
La implementacin del carrito no tiene mayor complicacin y se ajusta a una implementacin tpica de la mayora de aplicaciones que
hacen uso de este elemento.
Paso a paso: la capa de presentacin Struts
Hasta ahora hemos ido desarrollando nuestra aplicacin ejemplo de forma similar a cmo lo haramos si no conocisemos Struts. La
nica caracterstica especfica que hemos estado obligados a tener en cuenta es la existencia de las Action (o DispatchAction). Sin
embargo, lo ms seguro es que en nuestras anteriores aplicaciones sin conocer Struts ya nos hubiramos montado mecanismos de
control al estilo de las acciones.
Pero cuando llegamos a la capa Vista, entonces Struts cambia toda nuestra forma de trabajar, ya que es aqu donde haremos mayor
uso de la tecnologa y normalizacin que propone Struts. Veamos con calma como desarrollar cada uno de los componentes de la capa
de presentacin.
Lo primero, y para seguir el sentido de desarrollo que estamos llevando, vamos a implementar las acciones Struts. Para ello debemos
tener muy claro las necesidades de nuestra aplicacin. En nuestro ejemplo necesitaremos:
Loguearnos y desloguearnos del sistema
Ver la lista de productos en venta
Ver el detalle de un producto en particular
Ver nuestro perfil
Trabajar con el carrito de la compra: ver, modificar, actualizar, aadir, borrar, etc.
Segn estas acciones expuestas, necesitamos ahora decidir cmo las implementaremos usando Struts. Como ya se ha comentado al

public void setProducto(ProductoVO newProducto)
{
producto = newProducto;
calculateImporte();
}

public void setImporte(double newPrice)
{
importe = newPrice;
}

public String getDescription()
{
return producto.getDescription();
}

public int getId()
{
return producto.getId();
}

public String getName()
{
return producto.getName();
}

public int getQuantity()
{
return quantity;
}

public void setQuantity(int newQuantity)
{
quantity = newQuantity;
calculateImporte();
}

public ProductoVO getProducto()
{
return producto;
}

public double getBasePrice()
{
return producto.getBasePrice();
}

public double getImporte()
{
return importe;
}

private void calculateImporte()
{
if (producto.getBasePrice() != 0)
{
importe = producto.getBasePrice() * getQuantity();
}
}
}
Pagina 13 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
principio del tutorial, Struts proporciona dos clases para las acciones: org.apache.struts.actions.Action y
org.apache.struts.actions.DispatchAction (extendidas por nosotros como CustomBaseAction y CustomDispatchAction,
respectivamente). En nuestro caso vamos a utilizar ambas para mostrar su uso: usaremos CustomDispatchAction para las acciones
exclusivas del carrito, y CustomBaseAction para el resto.
El grupo de acciones exclusivas del carrito lo implementamos en CarritoActions de la siguiente forma:
package com.tutorial.struts.actions;
import java.io.IOException;
import java.text.Format;
import java.text.NumberFormat;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.struts.actions.DispatchAction;
import com.tutorial.struts.service.ICarritoService;
import com.tutorial.struts.vo.ProductoVO;
import com.tutorial.struts.UserContainer;
import com.tutorial.struts.CarritoProducto;
import com.tutorial.struts.Carrito;
import com.tutorial.struts.CustomDispatchAction;
/**
* Implementa toda la funcionalidad mediante acciones de un carrito de la compra.
**/
public class CarritoActions extends CustomDispatchAction
{
/**
* Este mtodo simplemente reenvia al estado de Success,
* el cual debera representar la pgina shoppingcart.jsp.
**/
public ActionForward view(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
// Nos aseguramos que el usuario est en sesin.
UserContainer userContainer = getUserContainer(request);

return mapping.findForward("Success");
}

/**
* Este mtodo actualiza los productos y cantidades del carrito.
**/
public ActionForward update(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
updateProductos(request);
updateQuantities(request);

return mapping.findForward("Success");
}

/**
* Este mtodo aade un producto al carrito segn los parmetros
* id y qty de la peticin.
**/
public ActionForward addProducto(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
System.out.println("Aadiendo producto al carrito");

UserContainer userContainer = getUserContainer(request);

System.out.println("El usuario es " + userContainer);
System.out.println("Empezamos");
System.out.println("Buscando: " + request.getSession().getAttribute("UserContainer"));
System.out.println("Terminamos" );

// Obtenemos el id del producto a buscar.
String productoId = request.getParameter("id");
String qtyParameter = request.getParameter("cantidad");

int quantity = 1; // Valor por defecto a aadir.
if(qtyParameter != null)
{
Locale userLocale = request.getLocale();
Format nbrFormat = NumberFormat.getNumberInstance(userLocale);

try
{
Object obj = nbrFormat.parseObject(qtyParameter);
quantity = ((Number)obj).intValue();
Pagina 14 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Este ejemplo demuestra las ventajas de uso de org.apache.struts.actions.DispatchAction para agrupar acciones comunes, frente al uso
de mltiples acciones individuales.
Pero vamos a centrarnos en las partes del cdigo ms interesantes. Quizs lo primero que llama la atencin es que la mayora de los
mtodos devuelven un objeto ActionForward. Este objeto es exclusivo de Struts y permite definir en un fichero externo (struts-
config.xml) mediante mapeados las caractersticas de las acciones: nombre, ruta, mbito, validacin, qu hacer si xito y qu hacer si
fracaso (hacia donde redirigir la peticin). De esta forma, en nuestro cdigo podemos indicar mediante return mapping.findForward
("Success") que contine el flujo de la aplicacin por otra accin o JSP. Veamos el mapeado para CarritoActions:
}
catch(Exception ex)
{
// Simplemente utilizamos la cantidad por defecto.
}
}

// Llamamos al servicio y le pedimos un ProductoVO para el producto elegido.
ICarritoService serviceImpl = getCarritoService();
ProductoVO productoVO = serviceImpl.getDetalleProducto(productoId);

// Aadimos el producto al carrito.
userContainer.getCart().addProducto(new CarritoProducto(productoVO, quantity));

return mapping.findForward("Success");
}
/**
* Actualizamos los productos del carrito.
**/
private void updateProductos(HttpServletRequest request)
{
// Hay mltiples casillas de verificacin con el nombre "deleteCarritoProducto" en el
// formulario. Los que estn activados se pasan en la sesin.
String[] deleteIds = request.getParameterValues("deleteCarritoProducto");

// Construimos una lista de ids para eliminar.
if(deleteIds != null && deleteIds.length > 0)
{
int size = deleteIds.length;
List productoIds = new ArrayList();

for (int i=0;i<size;i++)
{
productoIds.add(deleteIds[i]);
}

// Obtenemos el carrito del UserContainer y boramos los productos.
UserContainer userContainer = getUserContainer(request);
userContainer.getCart().removeProductos(productoIds);
}
}
/**
* Update the quantieis for the productos in the shopping cart.
*/
private void updateQuantities(HttpServletRequest request)
{
Enumeration enum = request.getParameterNames();
// Iteramos por los parmetros y miramos aquellos que empiezan con
// "qty_". Los campos qty en la pgina se llamaban todos "qty_" + productoId.
// Quitamos el id de cada producto y el correspondiente valor de qty.
while(enum.hasMoreElements())
{
String paramName = (String)enum.nextElement();
if(paramName.startsWith("qty_"))
{
String id = paramName.substring(4, paramName.length());
String qtyStr = request.getParameter(paramName);
if(id != null && qtyStr != null)
{
Carrito cart = getUserContainer(request).getCart();
cart.updateQuantity(id, Integer.parseInt(qtyStr));
}
}
}
}
}
<action
path="/carrito"
type="com.tutorial.struts.actions.CarritoActions"
scope="request"
input="/jsp/carrito.jsp"
validate="false"
parameter="method">

<forward name="Success" path="/jsp/carrito.jsp" redirect="true"/>
</action>
Pagina 15 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Si nos fijamos en los atributos de la etiqueta action podemos comprobar cmo indicamos las caractersticas de nuestra accin. Como
en este caso se trata de un grupo de acciones (DispatchAction), necesitamos indicar parameter="method". De esta forma podremos
llamar a la subaccin dentro del grupo de acciones de la forma /carrito?method=view, por ejemplo. Adems, indicamos que si todo ha
ido bien, nos redireccione a la pgina JSP llamada /jsp/carrito.jsp (la lgica de redirecciones la controla Struts y nos olvidamos de
tener que incuirla en los JSP, lo cual es una gran ventaja, como podris suponer).
Un mtodo muy importante, que demuestra como desde la parte del control de la presentacin podemos llamar a mtodos de negocio
a travs de nuestro mecanismo de servicio implementado antes, es AddProducto. En l se puede observar cmo hacemos uso de
getCreateService() de la superclase CustomDispatchAction para obtener una instancia de ICarritoService, y as poder invocar los
mtodos de negocio necesarios: serviceImpl.getDetalleProducto(productoId). Este mecanismo proporciona gran reusabilidad a nuestra
aplicacin.
Tambin destacar el mtodo getUserContainer(), implementado tambin en la superclase CustomDispatchAction, que nos permite
obtener el contenedor con los datos del usuario y el carrito a travs de la sesin.
Pasemos ahora a la accin GetListaProductoAction, encargada de devolver una lista de productos existentes en nuestra BD:
En el caso de una accin del tipo CustomBaseAction, ya comentamos que se deba implementar el mtodo execute(). De nuevo se
puede comprobar cmo se hace uso similar al caso anterior del servicio almacenado en el contexto de ActionServlet (recordemos) para
invocar mtodos de la capa de negocio de forma transparente al cliente. Luego metemos el resultado como un atributo de la peticin
(no de la sesin, ojo) y nos redirigimos donde indique el mapeado de la accin en el fichero struts-config.xml:
En este mapeado observamos que no hay parameter="method" puesto que se trata de una accin simple que se indica en el atributo
type="com.tutorial.struts.actions.GetListaProductoAction".
El resto de acciones (no se detallan por cuestiones de espacio) son LoginAction, LogoutAction, GetDetalleProductoAction y
GetPerfilAction, para cada una de las cuales deberemos mapear sus caractersticas en el fichero struts-config.xml:
package com.tutorial.struts.actions;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import java.util.List;
// Imports de clases propias de la aplicacin.
import com.tutorial.struts.CustomBaseAction;
import com.tutorial.struts.vo.ProductoVO;
import com.tutorial.struts.service.ICarritoService;
public class GetListaProductoAction extends CustomBaseAction
{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
// Creamos el servicio para obtener la lista de productos.
ICarritoService serviceImpl = getCarritoService();
List listaProducto = serviceImpl.getListaProducto();

// Almacenamos el resultado en la sesin.
request.setAttribute("ListaProductoKey", listaProducto);

// Devolvemos el Action Forward para el caso de Success.
return mapping.findForward("Success");
}
}
<action
path="/viewlistaproducto"
input="/jsp/listaproducto.jsp"
type="com.tutorial.struts.actions.GetListaProductoAction"
scope="request"
validate="false">

<forward name="Success" path="/jsp/listaproducto.jsp"/>
</action>
<action
path="/login"
type="com.tutorial.struts.actions.LoginAction"
scope="request"
name="loginForm"
validate="true"
input="/jsp/login.jsp">

<forward name="Success" path="/action/viewperfil" redirect="true"/>
<forward name="Failure" path="/action/login" redirect="true"/>
</action>
<action
path="/logout"
type="com.tutorial.struts.actions.LogoutAction"
scope="request">

Pagina 16 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Pero adems, Struts nos permite definir mapeados de acciones genricas, como por ejemplo un simple 'forward':
Como se puede comprobar fcilmente en el mapeado, indicamos que se trata de una accin predefinida en
type="org.apache.struts.actions.ForwardAction".
Con todas las acciones ya creadas, slo nos queda la parte de la interfaz con la que trabajar el usuario. Para nuestra aplicacin
usaremos un navegador Web y, por tanto, tecnologa JSP para presentar resultados e informacin. Pero adems, haremos uso de las
Struts Tags para facilitar la tarea de crear formularios, trabajar con los datos, etc.
Lo primero de todo es entender los mecanismos que nos proporciona Struts para las tareas exclusivas de presentacin. As, para cada
pgina HTML que trabaje con datos, deberamos usar un ActionForm e implementar obligatoriamente dos mtodos de la superclase:
Para hacer esta tarde ms fcil todava, Struts proporciona una forma dinmica de trabajar con formularios mediante la superclase
org.apache.struts.action.DynaActionForm. Este tipo de formulario utiliza un Map para almacenar valores internamente a partir de la
estructura definida en nuestros VOs, por ejemplo.
Segn esto, veamos a continuacin un par de ejemplos sacados de nuestra aplicacin que ilustran tanto un 'action form' construido
manualmente, como uno generado de forma automtica. El del primer tipo se implementa mediante LoginForm:
<forward name="Success" path="/action/login" redirect="true"/>
</action>
<action
path="/viewdetalleproducto"
name="detalleProductoForm"
input="/jsp/index.jsp"
type="com.tutorial.struts.actions.GetDetalleProductoAction"
scope="request"
validate="false">

<forward name="Success" path="/jsp/detalleproducto.jsp"/>
</action>
<action
path="/viewperfil"
name="perfilForm"
input="/jsp/index.jsp"
type="com.tutorial.struts.actions.GetPerfilAction"
scope="request"
validate="false">

<forward name="Success" path="/jsp/perfil.jsp"/>
</action>
<action
path="/viewcarrito"
parameter="/jsp/carrito.jsp"
type="org.apache.struts.actions.ForwardAction"
scope="request"
validate="false">
</action>
public void reset(ActionMapping mapping, HttpServletRequest request);

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request);
package com.tutorial.struts.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.*;
/**
* Bean de formulario para que el usuario se valide.
**/
public class LoginForm extends ActionForm
{
private String password = null;
private String email = null;
public void setEmail(String email)
{
this.email = email;
}

public String getEmail()
{
return (this.email);
}

public String getPassword()
{
return (this.password);
}

Pagina 17 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Como se puede comprobar, una subclase ActionForm debe implementar los dos mtodos que veamos anteriormente. Adems, se trata
de un simple JavaBean con sus mtodos set/get, que son utilizados por Struts para poder trabajar con los datos del formulario y
hacerlos disponibles al usuario. Pero, adems, podemos hacer uso de ActionErrors para presentar errores, por ejemplo de validacin.
Al igual que las acciones, los ActionForm hay que declararlos en el fichero struts-config.xml, en la seccin <form-beans>:
En cuanto al segundo tipo de formularios, no hay necesidad de hacer un 'subclass' de ActionForm. Simplemente se declaran en el
fichero XML de la siguiente forma:
Hemos de indicar que se trata de un DynaActionForm y a partir de que JavaBean obtendr su estructura. Si nos fijamos, es
prcticamente igual al ActionForm anterior, slo que como los mtodos set/get ya estn definidos en los VOs, los aprovechamos y nos
ahorramos tener que redefinirlos.
Una vez creados los formularios ya slo nos queda comenzar a desarrollar los JSP. Struts tambin nos ayuda en esta tarea a travs de
los Tags, que nos permiten acceder encapsular tareas relacionadas con diseo HTML, lgica (iteraciones, condiciones, etc.) y trabajo
con beans (ActionForms). Estas ltimas 'tags', las relacionadas con los bean, proporcionan tambin un mecanismo de
internacionalizacin de nuestra aplicacin, al permitirnos declarar un fichero externo de cadenas de texto para utilizar en nuestras
pginas web.
Para indicar que vamos a utilizar un fichero de recursos para nuestra aplicacin, debemos crear un fichero externo situado a partir de
WEB-INF/classes, con extensin .properties y que debemos declarar en el fichero struts-config.xml de la siguiente forma:
Como podemos apreciar, le decimos a Struts que busque los recursos de mensaje en un subdirectorio llamado resources (dentro de
WEB-INF/classes) y en un fichero llamado ApplicationResource (sin la extensin .properties). En la documentacin de Struts viene
como crear ms de un fichero de recursos de mensajes (por ejemplo, se podra crear uno para las 'labels' de la aplicacin, otro para
los mensajes de error, otro para los 'alt' de las imgenes, etc.).
Ya slo nos queda entonces la parte de los JSP exclusivamente. Para ello hemos utilizado el paquete Tiles incorporado a Struts, por el
cual podemos trabajar con plantillas de una forma muy prctica. Esto nos permitir realizar cambios en el diseo sin tener que
public void setPassword(String password)
{
this.password = password;
}

/**
* Validamos las propiedades que se han establecido para esta peticin HTTP,
* y devolvemos un objeto <code>ActionErrors</code> que encapsula cualquier
* error de validacin que encontremos. Si no se encuentran errores, devolvemos
* <code>null</code> o un objeto <code>ActionErrors</code> sin mensajes de error.
**/
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)
{
ActionErrors errors = new ActionErrors();

if (getEmail() == null || getEmail().length() < 1)
{
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("global.required", "email"));
}

if(getPassword() == null || getPassword().length() < 1)
{
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("global.required", "password"));
}

return errors;
}

/**
* Resetea todas las propiedades a sus valores por defecto.
*/
public void reset(ActionMapping mapping, HttpServletRequest request)
{
this.password = null;
this.email = null;
}
}
<form-bean name="loginForm" type="com.tutorial.struts.forms.LoginForm"/>
<form-bean
name="detalleProductoForm" dynamic="true"
type="org.apache.struts.action.DynaActionForm">

<form-property name="detalle" type="com.tutorial.struts.vo.ProductoVO"/>
</form-bean>

<form-bean
name="perfilForm" dynamic="true"
type="org.apache.struts.action.DynaActionForm">

<form-property name="perfil" type="com.tutorial.struts.vo.UserVO"/>
</form-bean>
<message-resources parameter="resources.ApplicationResource"/>
Pagina 18 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
modificar cada uno de los JSP de nuestra aplicacin.
Veamos lo primero de todo como se define un 'layout' para luego crear una plantilla a partir de nuestro layout defaultLayout.jsp (el uso
de Struts Tags queda fuera del alcance de este tutorial, aunque son muy intuitivas):
Si nos fijamos en la distribucin que hemos diseado, se trata de un 'layout' tpico con una parte superior, una media dividida en dos
(izquierda men y derecha donde se trabaja y presenta la informacin) y una parte inferior, a modo de copyright, por ejemplo.
Ahora slo nos queda definir un JSP que haga uso en forma de plantilla de este 'layout'. En la especificacin del 'layout' anterior,
utilizamos la etiqueta <tiles:insert> para especificar un atributo que nos servir para indicar ahora en la plantilla cmo insertar el
diseo de cada zona. Veamos el cdigo de template.jsp:
Fijaos que sumamente sencillo es crear un template a partir del 'layout'. Slo declaramos un nombre para este template
id="template.default" y qu 'layout' estamos utilizando page="defaultLayout.jsp". Luego simplemente indicamos las zonas fijas de
nuestra plantilla, que para nuestro caso sern todas menos la zona central donde presentaremos la informacin (en una aplicacin m
compleja pueden incluso ser todas las zonas variables).
De esta forma, cualquiera de nuestras futuras pginas Web podremos generarla a partir de un par de JSP: uno para indicar que
utilizaremos la plantilla, y el otro para realmente implementar el cdigo de la pgina Web. Veamos un ejemplo ilustrativo de nuestra
aplicacin con carrito.jsp y carrito_body.jsp:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%>
<html:html locale="true">

<head>
<title><bean:message key="global.title"/></title>
<html:base/>
</head>

<body topmargin="0" leftmargin="0" bgcolor="#9999CC">
<font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#000000">
<table width="100%" border="1" cellspacing="0" cellpadding="0" border="0">

<tr>
<!-- Informacin de cabecera-->
<td colspan="2"><tiles:insert attribute="header"/></td>
</tr>

<tr>
<!-- Barra de men-->
<td valign="top" width="25%"><tiles:insert attribute="menubar"/></td>
<!-- Informacin principal-->
<td width="75%" valign="top"><tiles:insert attribute="body-content"/></td>
</tr>

<tr>
<!-- Informacin de pie de pgina-->
<td colspan="2"><tiles:insert attribute="copyright"/></td>
</tr>

</table>
</font>
</body>
</html:html>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%>
<tiles:definition id="template.default" page="defaultLayout.jsp" scope="request">
<tiles:put name="header" value="header.jsp"/>
<tiles:put name="menubar" value="menu.jsp"/>
<tiles:put name="copyright" value="copyright.jsp"/>

</tiles:definition>
carrito.jsp
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%>
<%@include file="template.jsp"%>
<tiles:insert beanName="template.default" beanScope="request">
<tiles:put name="body-content" value="carrito_body.jsp"/>
</tiles:insert>
carrito_body.jsp
Pagina 19 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<br>
<center>
<p>
<b>CARRITO DE LA COMPRA DEL USUARIO</b>
</p>
</center>
<logic:lessEqual scope="session" name="UserContainer" property="cart.size" value="0">
<blockquote>
<html:link page="/action/viewlistaproducto">Continuar comprando</html:link>
</blockquote>
</logic:lessEqual>
<logic:greaterThan scope="session" name="UserContainer" property="cart.size" value="0">
<blockquote>
<p>
<form name="form1" action="../action/carrito?method=update" method="post">
<div align="left">
<table width="80%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="10%"><div align="center">Borrar</div></td>
<td width="47%"><div align="left">Producto</div></td>
<td width="15%"><div align="center">Cantidad</div></td>
<td width="14%"><div align="center">Precio</div></td>
<td width="14%"><div align="center">Total</div></td>
</tr>

<logic:iterate id="carritoProducto" scope="session" name="UserContainer" property="cart.productos">

<tr>
<td width="10%">
<div align="center">
<input type="checkbox" value="<bean:write name="carritoProducto" property="id"/>"
name="deleteCarritoProducto">
</div>
</td>

<td width="47%">
<div align="left">
<html:link page="/action/viewdetalleproducto" paramId="id" paramName="carritoProducto" paramProperty="id">
<bean:write name="carritoProducto" property="name"/>
</html:link>
</div>
</td>

<td width="15%">
<div align="center">
<input type="text" maxlength="3" size="3" name="qty_<bean:write name="carritoProducto" property="id"/>"
value="<bean:write name="carritoProducto" property="quantity"/>">
</div>
</td>

<td width="14%">
<div align="center">
<strong><bean:write name="carritoProducto" format="#,##0.00" property="basePrice"/></strong>
</div>
</td>

<td width="14%" bgcolor="#FF9933">
<div align="center">
<strong><bean:write name="carritoProducto" format="#,##0.00" property="importe"/></strong>
</div>
</td>
</tr>

</logic:iterate>

</table>

<p>
<a href="javascript:self.form1.submit();">
Borrar productos seleccionados
</a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="javascript:self.form1.submit();">
Actualizar totales
</a>
&nbsp;&nbsp;&nbsp;&nbsp;
Pagina 20 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Aunque no podemos entrar en detalle del cdigo aqu ilustrado, s merece la pena destacar el uso de etiquetas de lgica
(<logic:greaterThan> o <logic:iterate>), etiquetas para mostrar los elementos de los formularios ActionForm y DynaActionForm
definidos antes (<bean:write>) y etiquetas de HTML (<html:link>).
Paso a paso: unir todo el trabajo
Ya hemos terminado toda la parte del cdigo para toda la arquitectura y ahora slo nos queda desplegar la aplicacin. Puesto que esta
tarea ya ser conocida por todos, simplemente se muestra a continuacin las modificaciones exclusivas de Struts en el descriptor de
despliegue (web.xml):
<html:link page="/action/viewlistaproducto">
Continuar comprando
</html:link>
</p>
</div>
</form>
</p>
</blockquote>
</logic:greaterThan>
<br>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>carrito</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>application</param-name>
<param-value>ApplicationResources</param-value>
</init-param>
<init-param>
<param-name>validating</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>carrito</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
<!-- The Welcome File List -->
<welcome-file-list>
<welcome-file>jsp/login.jsp</welcome-file>
</welcome-file-list>
<!-- Template Tag Library Descriptor -->
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
Pagina 21 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
y el fichero de configuracin de Struts (struts-config.xml) completo:
<taglib>
<taglib-uri>/WEB-INF/struts-template.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-template.tld</taglib-location>
</taglib>

<taglib>
<taglib-uri>/WEB-INF/struts-nested.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-nested.tld</taglib-location>
</taglib>
</web-app>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean name="loginForm" type="com.tutorial.struts.forms.LoginForm"/>

<form-bean name="detalleProductoForm" dynamic="true"
type="org.apache.struts.action.DynaActionForm">
<form-property name="detalle" type="com.tutorial.struts.vo.ProductoVO"/>
</form-bean>

<form-bean name="perfilForm" dynamic="true"
type="org.apache.struts.action.DynaActionForm">
<form-property name="perfil" type="com.tutorial.struts.vo.UserVO"/>
</form-bean>

</form-beans>
<action-mappings>
<action
path="/login"
type="com.tutorial.struts.actions.LoginAction"
scope="request"
name="loginForm"
validate="true"
input="/jsp/login.jsp">
<forward name="Success" path="/action/viewperfil" redirect="true"/>
<forward name="Failure" path="/action/login" redirect="true"/>
</action>
<action
path="/logout"
type="com.tutorial.struts.actions.LogoutAction"
scope="request">
<forward name="Success" path="/action/login" redirect="true"/>
</action>
<action
path="/viewcarrito"
parameter="/jsp/carrito.jsp"
type="org.apache.struts.actions.ForwardAction"
scope="request"
validate="false">
</action>

<action
path="/carrito"
type="com.tutorial.struts.actions.CarritoActions"
scope="request"
input="/jsp/carrito.jsp"
validate="false"
parameter="method">
<forward name="Success" path="/jsp/carrito.jsp" redirect="true"/>
</action>
<action
path="/viewdetalleproducto"
name="detalleProductoForm"
input="/jsp/index.jsp"
type="com.tutorial.struts.actions.GetDetalleProductoAction"
scope="request"
validate="false">
<forward name="Success" path="/jsp/detalleproducto.jsp"/>
</action>
Pagina 22 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb
Con todo ello creamos un fichero WAR carrito.war (he incluido tambin el cdigo fuente) y ya podemos desplegar nuestra aplicacin en
cualquier servidor de aplicaciones como JBoss o Tomcat (ya que de momento no hemos incluido EJBs). Os incluyo adems un ZIP con
la BD que yo he utilizado en MySQL.
Resumen
Si hemos conseguido desplegar la aplicacin, podremos comenzar a utilizar nuestra aplicacin del carrito de la compra. Algunas
pantallas son:
Captura 1
Captura 2
Captura 3
Captura 4
Espero que este tutorial os sirva de ayuda, ya que su intencin no es ser un manual de Struts, sino iniciar al programador en este
entorno de presentacin, del que seguro obtendr muchas ventajas. Si veo que tiene mucha aceptacin, os mostrar como aadir EJBs
de forma inmediata ...
Autor: Enrique Medina Montenegro (c) 2003
Si desea contratar formacin, consultoria o desarrollo de piezas a medida puede contactar con



Somos expertos en:
J2EE, C++, OOP, UML, Vignette, Creatividad ..
y muchas otras cosas




Otros Tutoriales Recomendados (Tambin ver todos)

<action
path="/viewlistaproducto"
input="/jsp/listaproducto.jsp"
type="com.tutorial.struts.actions.GetListaProductoAction"
scope="request"
validate="false">
<forward name="Success" path="/jsp/listaproducto.jsp"/>
</action>

<action
path="/viewperfil"
name="perfilForm"
input="/jsp/index.jsp"
type="com.tutorial.struts.actions.GetPerfilAction"
scope="request"
validate="false">
<forward name="Success" path="/jsp/perfil.jsp"/>
</action>

</action-mappings>
<message-resources parameter="resources.ApplicationResource"/>
<plug-in className="com.tutorial.struts.service.CarritoServiceFactory"/>

</struts-config>
Nuevo servicio de notificaciones
Si deseas que te enviemos un correo electrnico cuando introduzcamos nuevos tutoriales, inserta tu direccin
de correo en el siguiente formulario.
Subscribirse a Novedades


Nombre Corto Descripcin
Aplicacin bsica con RMI
Gracias a este tutorial, podreis aprender paso a paso como crear una aplicacin cliente-
servidor con RMI
Pagina 23 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb

Patrocinados por enredados.com .... Hosting en Castellano con soporte Java/J2EE








Primeras aplicaciones con Bea
Weblogic Platform
Os mostramos como instalar Bea Weblogic Platform as como a crear la primera
aplicacin, con su entorno visual, utilizando la implementacin particular basada en
Struts....
Generador automtico de
Webservices
Os mostramos como crear un servicio Web a partir de una clases, gracias a generadores
automticos de cdigo y NetBeans
Despliegue grfico de EJBs
Os mostramos como crear y desplegar de un modo grfico un EJB de sesin el el
servidor de aplicaciones de referencia de Sun
Cachear porciones de JSPs
En este tutorial os ensaamos como incrementar increiblemente el rendimiento de
vuestro Web basado en tecnologa JSP con el FrameWork de cache OSCACHE
JSP 2.0, JSTL y Lenguaje de
expresiones
Os mostramos las novedades de JSP 2.0: Nuevas libreras estandar de etiquetas y el
lenguaje de expresiones con ejemplos de acceso a base de datos, XML y XSL en JSP
Struts Jakarta
Cuando se ha trabajado creando aplicaciones Java poco a poco se va viendo la
necesidad de normalizar los desarrollo. Uno de los Framework (entornos) ms
extendidos es Struts
Pool de Conexiones y Tomcat5
Os mostramos como instalar Tomcat5 en vuestro PC y como ejemplo de uso,
configuramos un Pool de Conexiones y lo usamos contra MySQL
JDBC y MySql
En el tutorial anterior vimos como instalar MySQL en Windows, ahora vamos a ver como
acceder desde una aplicacin Java.
Integracin de Struts y eclipse
Alejandro Perez nos ensea como construir un entorno de alta eficiencia de desarrollo on
Struts a travs de plugins de eclipse
www.AdictosAlTrabajo.com Opimizado 800X600
Pagina 24 de 24 Tutoriales en AdictosAlTrabaio: Java. J2EE. Visual C. Linux. UML. OOP y mucho mas
04/08/2004 http://www.adictosaltrabaio.com/tutoriales/tutoriales.php?paginastrutsb

Vous aimerez peut-être aussi