miércoles, 12 de marzo de 2008

Escribiendo una aplicación en Struts

En este ejemplo se estudiará como implementar una aplicación Web mediante el uso de Struts, será acompañado de pedazos código, disponibles en el apéndice B en su totalidad, para que el usuario pueda correrlo y analizarlo desde su computadora.
Estructura de los Archivos e Instalación

Las aplicaciones Web poseen una estructura de archivos definida para poder ejecutarse en un contenedor de Servlets, como el Tomcat de Apache, esta estructura por lo regular no se modifica y solamente se le agregan algunas librerías para poder correr una aplicación utilizando Struts (Figura 1).

Figura 1.- Estructura de los directorios


Para obtener e instalar Struts se debe obtener una versión de la herramienta en la dirección http://struts.apache.org/download.cgi. Dentro del archivo comprimido de la distribución, existe un directorio llamado lib que se debe copiar a la carpeta WEB-INF. Esta carpeta contiene todos los archivos JAR que utiliza la aplicación (Figura 2). Al momento de compilar los archivos java se debe asegurar que los archivos contenidos dentro de la carpeta lib estén en el classpath.



Figura 2 archivos JAR de la distribución de Struts
Componentes de Struts

Como se mencionó en el capítulo anterior, el MVC es parte fundamental de Struts, para explicar como encajan las partes de este patrón, se explicará un ejemplo modificado del clásico “Hola Mundo”.
Elementos de la Vista

La vista esta conformada de dos JSPs: index.jsp y hola.jsp, dentro de index.jsp se declara una forma que hace referencia a la acción hola.do, esta compuesta de un campo de texto y un botón para enviar la forma. El campo de texto tiene un atributo name = “nombre” que especifica un nombre lógico para la forma.


Escriba su nombre:




Para el manejo de formas, Struts provee una clase llamada ActionForm que se debe extender para darle funcionalidad. Dentro de la subclase, por cada campo dentro de la forma, se debe declarar una variable instancia con el mismo nombre que se asignó al atributo name en el código HTML, para cada variable se deben escribir métodos get y set como se muestra en el siguiente ejemplo:

/*
* HolaForm.java
*/
package aldo.ejemplo;

//area de imports
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.*;
/**
*
* @author Aldo A. Solis
*/
public class HolaForm extends ActionForm{

/** Esta variable sirve para guardar el nombre del usuario */
private String nombre;

/**
* Sirve para obtener la variable nombre
* @return variable String nombre
*/
public String getNombre(){
return this.nombre;
}

/**
* Sirve para asignar un nombre a la variable
* @param nombre cadena que se asignará
*/
public void setNombre(String nombre){
this.nombre = nombre;
}

public void reset(ActionMapping map, HttpServletRequest req){
this.nombre = "";
}

public ActionErrors validate(ActionMapping map,
HttpServletRequest req){
ActionErrors errors = new ActionErrors();
if((nombre == null) || (nombre.length() < 1))
errors.add("nombre", new ActionMessage("error.nombre"));
return errors;
}
}

Adicionalmente se pueden sobrescribir los métodos reset y validate que tienen funcionalidades específicas. El método reset es invocado para reinicializar las variables a un valor dado por el programador, mientras el método validate se usa para validar que los datos no tengan errores de captura o valores nulos.

El archivo hola.jsp tiene la función de desplegar un letrero con el nombre que el usuario introdujó en index.jsp, esto mediante la siguiente línea de código:

Hola <%= request.getAttribute("nombre")%>



La línea anterior pide un atributo llamado “nombre” dentro del request y lo despliega en la página.
Elementos del controlador

Struts implementa el controlador mediante la clase ActionServlet del paquete org.apache.struts.action, es importante aclarar que esta clase es concreta, es el servlet principal de nuestra aplicación y no se necesita extender para poder usar el framework.

Toda aplicación Web debe tener un descriptor de despliegue (conocido en inglés como deployment descriptor) llamado web.xml, en este archivo se debe especificar el uso de Struts de la siguiente manera:






action


org.apache.struts.action.ActionServlet



config
/WEB-INF/struts-config.xml






action
*.do




El desarrollador indica al framework las acciones, las formas y otros atributos mediante un archivo de configuración que por convención se llama struts-config.xml y tiene los siguientes campos para la aplicación “Hola Mundo”:



"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd" >




type="aldo.ejemplo.HolaForm"/>



type="aldo.ejemplo.HolaAction"
name="forma"
scope="request"
input="/index.jsp"
validate="true" >
path="/hola.jsp" />




La etiqueta form-beans sirve para declarar las clases que representan formas HTML, en el atributo name se escribe un nombre lógico con el que se le hará una referencia futura y en type se especifica el nombre completo de la clase.

Dentro de la etiqueta action-mappings se especifican las acciones, en este caso tenemos una sola acción pero por lo regular se tendrá más de una. La etiqueta action describe los atributos de una acción, en path se indica el nombre de como se llamará al recurso sin el “.do” (dado que esta terminación sirve para llamar al ActionServlet) y agregándose una diagonal al principio. El atributo name sirve para especificar el ActionForm que se usará por esta Action mediante su nombre lógico, validate indica si se llamará o no al método validate del ActionForm, así como input debe tener el nombre del JSP al que se redireccionará si validate regresa algún error.

La etiqueta forward especifica un nombre lógico y una página JSP, que el Action utiliza para continuar con el flujo de la navegación.

ActionServlet funciona más a detalle es la siguiente manera:

1. Recibe peticiones por parte de la vista, está puede ser un JSP.
2. Delega la petición a un objeto RequestProcessor, cuya clase se encuentra en el mismo paquete del ActionServlet y se encarga de seleccionar e invocar a la Action que corresponde a la petición. La clase RequestProcessor sigue para cada petición del usuario los siguientes pasos:

* Identifica la acción que se quiere usar por la petición del usuario
* Obtiene el nombre de la clase correspondiente a la acción.
* Si es la primera petición a la clase, crea una instancia para su uso futuro
* Llena una clase de tipo ActionForm asociada con esta petición, con los datos de la forma.
* Se llama al método executede la clase, pasando referencias al bean con los datos de la forma, al HttpServletRequest y al HttpServletResponse relacionado, así como un objeto ActionMapping que contiene información acerca de los recursos de donde proviene y hacia donde va el flujo de la navegación.

3. A su vez una Action manipula el estado y la lógica de nuestra aplicación y en lugar de mandar a la siguiente página, regresa un objeto ActionForward en el que se indica que recurso se encargará de la respuesta hacia el usuario.
4. El RequestProcessor, a través del objeto ActionForward, se encarga de mostrar o redireccionar a la siguiente página.



Para crear una acción se debe extender la clase org.apache.struts.action.Action y sobrescribir el método execute que tiene la siguiente firma:

public ActionForward execute( ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response )

El siguiente ejemplo muestra como implementar el Action de la aplicación “Hola Mundo”:

/*
* HolaAction.java
*/
package aldo.ejemplo;

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



/**
* Esta clase se encarga de sobre-escribir el método execute
* que extiende de la clase Action, recupera una forma tipo
* HolaForm, y obtiene la variable nombre, después agrega el
* atributo nombre al request y decide la siguiente página a
* mostrar.
*
* @author Aldo A. Solis
*/
public class HolaAction extends Action{

public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){

// Recuperamos la forma
HolaForm forma = (HolaForm) form;
// Obtenemos el nombre introducido por el usuario
String nombre = forma.getNombre();
// Hacemos una instancia del modelo
HolaModelo modelo = new HolaModelo();
// Llamamos a un método del modelo
nombre = modelo.mayusculas(nombre);
// Agregamos al request el atributo nombre
request.setAttribute("nombre", nombre);
// Seleccionamos la siguiente pagina “DecirHola”
// definida en el struts-config.xml
ActionForward fwd = mapping.findForward("DecirHola");
return fwd;
}
}
Elementos del Modelo

El modelo es lo que al desarrollador le interesa. En el modelo se lleva acabo la lógica aplicativa del sistema Web que se esta desarrollando. Struts no provee elementos que faciliten al desarrollador la implementación del modelo, ya que es responsabilidad del programador hacerlo. A continuación se muestra el modelo utilizado por la aplicación ejemplo:

/*
* HolaModelo.java
*/
package aldo.ejemplo;

public class HolaModelo {

/**
* Invierte una cadena
* @param cadena String a modificar
* @return String modificado
*/
public String voltear(String cadena){
String nuevaCadena=new String(" ");
System.out.println(cadena);
for (int i=cadena.length()-1; i>=0; i--){
String tmp = cadena.substring(i,i+1);
nuevaCadena = nuevaCadena.concat(tmp);
}
return nuevaCadena;
}

/**
* Convierte una cadena a mayúsculas
* @param cadena String a modificar
* @return String modificado
*/
public String mayusculas(String cadena){
return cadena.toUpperCase();
}

/**
* Convierte una cadena a minúsculas
* @param cadena String a modificar
* @return String modificado
*/
public String minusculas(String cadena){
return cadena.toLowerCase();
}
}
Correr la aplicación

Para correr la aplicación se deben compilar las clases y copiar los paquetes generados al directorio classes dentro de WEB-INF, por otra parte se deben copiar también las páginas o JSPs encargadas de la vista a la carpeta raíz, una vez tenida la estructura mostrada en la figura 3.1, se procede a copiar la carpeta de la aplicación al directorio de nuestro contenedor de Servlets. La aplicación funciona de la siguiente manera:

1. El sistema pregunta al usuario su nombre
2. El usuario lo escribe y presiona el botón enviar (Figura 3)





Figura 3 Programa corriendo

3. El sistema procesa la solicitud
4. El sistema despliega un resultado (Figura 4)



Figura 4 Resultado del programa



Cualquier duda o sugerencia.
Ing. Aldo A. Solis Zenteno

sábado, 1 de marzo de 2008

Hibernate

Usar JDBC es complejo y muy dependiente de la estructura de los datos. Sería más natural y mucho más sencillo trabajar directamente con objetos, pero es imposible con las BBDD relacionales, y las BBDD orientadas a objeto están todavía muy verdes.

La mejor opción entonces es utilizar un motor de persistencia, que es el componente software encargado de traducir entre objetos y registros. Un motor de persistencia de código abierto es Hibernate, que nos permitirá hacer cosas como poder guardar un objeto en la base de datos simplemente con session.save(miObjeto) o borrarlo con session.delete(miObjeto).

Usa el mecanismo de reflexión de Java, que permite a un objeto en ejecución examinarse y manipularse a sí mismo, en contra de, por ejemplo, JDO, que necesita que modifiquemos los archivos de las clases.

Vamos a tener un archivo properties (hibernate.properties) o un archivo xml (hibernate.cfg.xml) para la configuración, una serie de JavaBeans que son las clases a persistir y en las que cada campo se asociará con una columna de la BBDD, y un archivo xml por cada una de estas clases (NombreClase.hbm.xml) que indica el mapping entre objetos y relaciones.

Este sería el aspecto del JavaBean que representa una sucursal en una supuesta aplicación:







}
Y este el del fichero de mapping de hibernate correspondiente:


















































Como vemos la etiqueta class se utiliza para asociar nuestra clase a una tabla concreta de la base de datos. Las etiquetas que se sitúan por debajo de class nos permiten definir la relación entre las propiedades de la clase y las columnas de la base de datos. La etiqueta id se usa para identificar el campo que actuará como clave primaria e indicar el tipo que va a tener (Long en este caso), así como la columna de la base de datos en la que se almacenará el campo y la forma de generar la clave (en este caso, native, que depende de la base de datos que usemos; podríamos haberle indicado por ejemplo que simplemente fuera sumando 1 cada vez con increment, o incluso crear nuestra propia clase generadora). A continuación tenemos una serie de etiquetas property, una por cada propiedad, que funcionan de forma parecida a id, indicando el nombre de la propiedad de la clase (atributo name) su tipo (atributo type) y la columna a la que se mapea (atributo name de column).


Como sabemos, las tablas también pueden tener relaciones entre ellas. En Hibernate podemos declarar relaciones N:M mediante la etiqueta many-to-many, 1:N con one-to-many y N:1 con many-to-one



Ahora que ya hemos visto como indicarle a Hibernate la correspondencia entre nuestras clases y las tablas de la BBDD, vamos a ver cómo utilizaríamos esta API.

Lo primero que tendríamos que hacer para empezar a utilizar Hibernate sería crear un nuevo objeto Configuration para poder indicarle dónde se encuentra el archivo de configuración:

Configuration cfg = new Configuration();
cfg.configure(RUTA_ARCHIVO_CONF);

A partir del hibernate.cfg.xml podemos crea un SessionFactory, que es el objeto mediante el cual abrimos nuevas sesiones de Hibernate.

SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();

Para insertar objetos en la BBDD usaremos el método save(Object objeto) de Session, para insertar o actualizar si ya existe saveOrUpdate(Object objeto), para borrar delete(Object objeto) y para cargar un objeto desde la BBDD get(String clase, Tipo id) o load(String clase, Tipo id) que devuelven el objeto de la clase indicada por el primer parámetro y con identificador el segundo parámetro si es que existe en la BBDD.

Para hacer búsquedas en la base de datos podemos usar find(String consulta) que devuelve una lista con los resultados, o iterate(String consulta) que devuelve un iterador, o bien crear un objeto Query usando createQuery(String consulta) y llamar más tarde al método find() del Query. La consulta en todos los casos estará escrita en un lenguaje similar a SQL propio de Hibernate llamado HQL (Hibernate Query Language). Otra opción sería trabajar con objetos Criteria.