You are on page 1of 18

Introducción a Struts

Prerequisitos

Esta guía de usuario está escrita para desarrolladores Web activos, y asume que tenemos conocimientos sobre como
funcionan las aplicaciones Web Java. Antes de empezar, deberíamos entender los básico de estas tecnologías:

• La secuencia Solicitud/Respuesta HTTP.


La fuente canónica para esto es RFC 2616 - Hypertext Transfer Protocol (HTTP/1.1).
• Java Servlets.
Un buen lugar para empezar es Sun Servlet product page y Sun Java Tutorials.
• JavaServer Pages (JSP).
De igual forma, un buen lugar para emepzar es la Sun JSP product page y Sun Java Tutorials.
• JavaBeans.
Muchas clases Struts están escritas como JavaBeans. Si no has trabajado antes con JavaBeans, puedes ver la página
Sun JavaBean product page y Sun Java Tutorials.

Si hemos creamos aplicaciones Web sobre otras plataformas, probablemente podremos seguir, y luego visitar las referencias
arriba indicadas cuando lo necesitemos. Estas son tecnologías corazón que se utilizan en casi todos los proyectos
desarrollados en Java

Prefacio: Un paso hacia el pasado (o una breve historia de Struts)

Cuando se inventaron los Servlets Java, muchos programadores se dieron cuenta de que eran una Buena Cosa. Eran más
rápidos y más potentes que el CGI estándard, portables, y extensibles infinitamente.

Pero escribir infinitas sentencias println() para enviar HTML al navegador era tirano y problemático. La respuesta fueron las
JavaServer Pages, que nos dejaron escribir servlets dentro de ellas. Ahora los desarrolladores podían mezclar fácilmente
HTML con código Java, y tener todas las ventajas de los servlets. ¡El cielo era el límite!

Las aplicaciones web Java se convirtieron rápidamente en "centradas-en-JSP". Esto, por sí sólo no era en una mala cosa, pero
hacían poco por resolver problemas de control de flujo y otros problemas endémicos de las aplicaciones Web. Claramente se
necesitaba otro modelo... Muchos desarrolladores inteligentes se dieron cuenta que las JavaServer Pages Y y los servlets se
podrían usar juntos para desplegar aplicaciones web. Los servlets podrían ayudar con el control de flujo, y las JPSs podrían
enfocarse en el negocio odioso de escribir HTML. Usar JSP y servlets juntos se ha dado ha conocer como el Modelo 2 (cuando
usar sólo JSPs era el Modelo 1). Por supuesto, no hay nada nuevo bajo el Sol (Sun)... y muchos han apuntado rápidamente
que el Modelo 2 de JSPs sigue el clásico patrón de diseño Modelo-Vista-Controlador de SmallTalk. Ahora es muy común usar
los terminos Modelo 2 y MVC indistintamente. El proyecto Struts lo lanzó en Mayo del 2000, Craig R. McClanahan para
proporcionar un marco de trabajo MVC estándard a la comunidad Java. En Julio del 2001, se liberó Struts 1.0, e IOHO, el
modelo 2 de desarrollo Java nunca será lo mismo.

El Patrón de Diseño ('MVC') Modelo-Vista-Controlador

En el patrón de diseño MVC, el flujo de la aplicación está dirigido por un Controlador central. El Controlador delega solicitudes -
en nuestro caso, solicitudes HTTP -- a un manejador apropiado. Los manejadores están unidos a un Modelo, y cada manejador
actúa como un adaptador entre la solicitud y el Modelo. El Modelo representa, o encapsula, un estado o lógica de negocio de la
aplicación. Luego el control normalmente es devuelto a través del Controlador hacia la Vista apropiada. El reenvío puede
determinarse consultando los conjuntos de mapeos, normalmente cargados desde una base de datos o un fichero de
configuración. Esto proporciona un acoplamiento cercano entre la Vista y el Modelo, que puede hacer las aplicaciones
significativamente más fáciles de crear y de mantener.

Introducción al Marco de Trabajo de Struts

Creyendo en el patrón de diseño Modelo-Vista-Controlador, las aplicaciones Struts tiene tres componentes principales: un
servlet controlador, que está proporcionado por el propio Struts, páginas JSP (la "vista"), y la lógica de negocio de la aplicación
(o el "modelo"). Veamos como esto funciona todo junto.

El servlet controlador Struts une y enruta solicitudes HTTP a otros objetos del marco de trabajo, incluyendo JavaServer Pages
y subclases org.apache.struts.action.Action porporcionadas por el desarrollador Struts. Una vez inizializado, el controlador
analiza un fichero de configuración de recursos, La configuración de recursos define (entre otras cosas) los
org.apache.struts.action.ActionMapping para una aplicación. El controlador usa estos mapeos para convertir las solicitudes
HTTP en acciones de aplicación.

Un ActionMapping normalmente especificará:

• una path solicitado (o "URI"),


• El tipo objeto (subclase de Action) para actuar sobre la solicitud,
• y otras propiedades según se necesite.

El objeto Action puede manejar la solicitud y responder al cliente (normalmente un navegador Web), o indicar a que control
debería ser reenviado. Por ejemplo, si un logín tiene éxito, una acción logín podría desear reenviar la petición hacia el
mainMenu.

Los objetos Action tienen acceso al servlet controlador de la aplicación, y por eso tienen acceso a los métodos del servlet.
Cuando se reenvia un control, un objeto Action puede reenviar indirectametne uno o más objetos compartidos, incluyendo
JavaBeans, situándolos en una de las colecciones estándard compartidas por los servlets Java.

Un objeto acción puede crear un bean de tarjeta de compra, o un ítem de la tarjeta, situando el bean en la colección de sesión,
y luego reenviando el control a otro mapeo. Este mapeo podría usar una página JavaServer Page para mostrar los contenidos
de la tarjeta del usuario. Como cada cliente tiene su propia sesión, cada uno también tendrá su propia tarjeta de compra. En
una aplicación Struts, la mayoría de la lógica del negocio se puede representar usando JavaBeans. Una Action puede llamar a
las propiedades de un JavaBean sin conocer realmente como funciona. Esto encapsula la lógica del negocio, para que la
Action pueda enfocarse en el manejo de errores y dónde reenviar el control.

Los JavaBeans también se pueden usar para manejar formularios de entrada. Un problema clave en el diseño de aplicaciones
Web es retener y validar lo que el usuario ha introducido entre solicitudes. Con Struts, podemos definir un conjunto de clases
bean formulario, subclasificando org.apache.struts.action.ActionForm, y almacenar fácilmente los datos de un formulario de
entrada en estos beans formularios. El bean se graba en una de las colecciones estándard o de contexto compartidas, por eso
puede ser usado por otros objetos, especialmente un objeto Action.

El bean de formulario puede usarlo una JSP para recoger datos del usuario ... por un objeto Action para validar los datos
introducidos por el usuario ... y luego de nuevo por la JSP para rellenar los campos del fomulario. En el caso de validación de
errores, Struts tiene un mecanismo compartido para lanzar y mostrar mensajes de error.

Un bean de formulario Struts se declara en la configuración de recursos definida en un fichero fuente Java, y enlazado a un
ActionMapping usando un nombre de propiedad comnún. Cuando una solicitud llama a un Action que usa un bean de
formulario, el servlet controlador recupera o crea el bean formulario, y lo pasa el objeto Action. Este objeto entonces puede
chequear los contenidos del bean de formulario antes de que su formulario de entrada se muestre, y también la cola de
mensajes a manejar por el formulario. Cuando esta listo, el objeto Action puede devolver el control con un reenvio a su
formulario de entrada, usando un JSP. El controlador puede responder a la solicitud HTTP y dirigir al cliente a la JavaServer
Page.

El marco de trabajo Struts incluye etiquetas personalizadas que pueden rellenar automáticamente los campos de un formulario
o un bean de formulario. Lo único que la mayoría de las páginas JSP necesitan saber sobre el resto del marco de trabajo son
los nombres de los campos apropiados y dónde enviar el formulario. Los componentes como los mensajes "encolados" por el
Action pueden salir usando una simple etiqueta personalizada. También se pueden definir otras etiquetas especificas de la
aplicación para ocultar detalles de implementación de las páginas JSPs.

Las etiquetas personalizadas en el marco de trabajo Struts están diseñadas para usar las características de internacionaización
incluidas en la plataforma Java. Todas las etiquetas de campos y los mensajes pueden recuperarse desde un recurso de
mensajes, y Java puede proporcionar automáticamente el recurso correcto para el idioma y país de un cliente. Para
proporcionar mensajes para otro idioma, simplemente añadimos otro fichero de recurso.

Junto al internacionalismo, otros beneficios de esta aproximación son las etiquetas consistentes entre formularios, y la
posibilidad de revisar todas las etiquetas y mensajes desde una localización central.

Para la aplicación más simple, un objeto Action podría algunas veces manejar la lógica de negocio asociada con una solicitud.
Sin embargo, en lamayoría de los casos, un objeto Action, debería llamar a otro objeto, normalmente un JavaBean, para
realizar la lógica de negocio real. Esto permite al objeto Action enfocarse en el manejo de errores y el control de flujo, en vez de
en la lógica del negocio. Para permitir su reutilizacion en otras plataformas, los JavaBeans de lógica de negocio no deberían
referirse a ningún objeto de aplicación Web. El objeto Action debería traducir los detalles necesarios de la solicitud HTTP y
pasarlos a los beans de la lógica del negocio como variables normales de Java.

Por ejemplo, en una aplicación de base de datos:

• Un bean de lógica de negocio conectaría y consultaría la base de datos,


• El bean de lógica de negocio devolvería el resultado al objeto Action,
• El objeto Action almacenarçia el resultado en un bean formulario en la solicitud,
• La JavaServer Page mostraría el resultado en un formulario HTML.

Ni el objeto Action ni la página JSP necesitan saber (o no les importa) de dónde viene le resultado. Sólo necesitan saber cómo
empaquetarlo y mostrarlo.
El resto de esta guía de usuario explica varios componentes Struts en gran detalle. La versión Struts también incluye varias
Guías de Desarrollo que cubren varios aspectos de los marcos de trabajo, junto con aplicaciones de ejemplo, el API estándard
JavaDoc, y, por supuesto, el código fuente completo!

Struts se distribuye bajo la licencia de la Apache Software Foundation. El código tiene copyright pero es gratuito para usarlo en
cualquier aplciación. Puedes ver las especificaciones en ASF license.

El Modelo: Estado del Sistema y JavaBeans de la Lógica de Negocio

La parte del Modelo de un sistema basado en MVC puede dividirse en conceptos--el estado interno del sistema, y las acciones
que pueden tomarse para cambiar el estado. En términos gramáticos, podríamos pensar en la información de estado como
nombres (cosas) y las acciones como verbos (cambios del estado de esas cosas).

Generalmente, nuestra aplicación representará un estado interno del sistema como un conjunto de uno o más JavaBeans, con
propiedades que representan los detalles del estado. Dependiendo de la complejidad de nuestra aplciación, estos beans
pueden ser autocontenidos (y saber como guardar su información de estado persistentemente de alguna forma), o podrían ser
fachadas que saben cómo recuperar información de fuentes externas (como una base de datos) cuando es solicitado. Los
Entity Enterprise JavaBeans (Entity EJBs) también se usan comunmente para representar estados internos.

Las aplicaciones de gran escala normalmente representarán un conjunto de posibles acciones lógicas de negocio con métodos
que pueden ser llamados sobre los beans que mantienen su información de estado. Por ejemplo, podríamos tener un bean de
una tarjeta de compra, almacenado en el ámbito de sesión por cada usuario actual con las propiedades que representan el
conjunto actual de ítems que el usuario ha decidio comprar. Este bean también podría tener un método checkOut() que autorice
la tarjeta de crédito del usuario, y envíe el pedio al almacen para que sea remitido. Otros sistemas representarán las acciones
disponibles de forma separada, quizas como Session Enterprise JavaBeans (Session EJBs).

Por otro lado, en algunas aplicaciones de menor escala, las acciones disponibles podrían estar embebidas dentro de clases
Action que son parte del rol del Controlador. Esto es apropiado cuando la lógica es muy simple, o donde no está contemplada
la reutilización de la lógica de negocio en otros entornos. El marco de trabajo Struts soporta cualquiera de estas
aproximaciones, pero nosotros recomendamos encarecidamente separar la lógica de negocio ("cómo se hace") del rol que
juegan las clases Action ("que hace").

La Vista: Páginas JSP y Componentes de Presentación

La parte de la Vista de una aplicación basada en Struts generalmente está construida usando tecnología JavaServer Pages
(JSP). Las págnas JSP pueden contener texto HTML estático (o XML) llamado "plantilla de texto", además de la habilidad de
insertar contenido dinámico basado en la interpretación (en el momento de solicitud de la página) de etiquetas de acción
especiales. El entorno JSP incluye un conjunto de etiquetas estándard, como <jsp:useBean>. Además, hay una facilidad
estándard para definir nuestras propias etiquetas, que están organizadas en "librerías de etiquetas personalizadas".

Struts incluye una extensa librería de etiquetas personalizadas que facilitan la creación de interfaces de usuario que están
completamente internacionalizados, y que interactúan amigablemente con beans ActionForm que son parte del Modelo del
sistema. El uso de estas etiquetas se explica más adelante en detalle.

Además de las páginas JSP y la acción y las etiquetas personalizadas que contienen, normalmente los objetos de negocio
necesitan poder dibujarse a sí mismos en HTML (o XML), basándose en su estado actual en el momento de la solicitud. La
salida renderizada desde dichos objetos puede incluirse fácilmente en una página JSP resultante usando la etiqueta de acción
estándard <jsp:include>.

El Controlador: ActionServlet y ActionMapping

La parte Controlador de la aplicación está enfocada en las solicitudes recibidas desde el cliente (normalmente un usuario
ejecutando un navegador Web), decidiendo qué función de la lógica de negocio se va a realizar, y luego delegando la
responsabilidad para producir la siguiente fase del interface de usuario en un componente Vista apropiado. En Struts, el
componente principal del Controlador es un servlet de la clase ActionServlet. Este servlet está configurado definiendo un
conjunto de ActionMappings. Un ActionMapping define un path que se compara contra la URI solicitada de la solicitud entrante,
y normalmente especifica el nombre totalmente cualificado de clase de una clase Action. Todas las Actions son subclases de
org.apache.struts.action.Action. Las acciones encapsulan la lógica del negocio, interpretan la salida, y por último despachan el
control al componente Vista apropiado para la respuesta creada.

Struts también soporta la habilidad de usar clases ActionMapping que tienen propiedades adicionales más allá de las estándard
requeridas para operar el marco de trabajo. Esto nos permite almacenar información adicional específica de nuestra aplciación,
pero aún utiliza las características restantes del marco de trabajo. Además, Struts nos permite definir nombres lógicos para los
controles a los que se debería reenviar para que un método actión pueda preguntar por la página "Main Menu" (por ejemplo),
sin saber el nombre real de la página JSP correspondiente. Estas características nos ayudan a separar la lógica de control (qué
hacer) de la lógica de la vista (cómo se renderiza).
Construir los Componentes del Modelo

Introducción

Muchos documentos de requerimientos usados para construir aplicaciones Web se enfocan en la Vista. Sin embargo,
deberíamos asegurarnos que también está claramente definido el procesamiento requerido por cada solicitud enviada desde la
perspectiva del Modelo. En general, el desarrollador de componentes del Modelo se enfocará en la creación de clases
JavaBeans que soporten todos los requerimientos de funcionalidad. La natural precisión de los beans requeridos por una
aplicación particular variará mucho dependiendo de esos requerimientos, pero generalmente pueden clasificarse en varias
categorías descritas abajo. Sin embargo, primero es útil una breve revisión del concepto de "ámbito" en relación con los beans
y JSP.

Los JavaBeans y el Ámbito

Dentro de una aplicación basada en web, los Javabeans pueden almacenarse en (y ser accedidos desde) varias colecciones
de "atributos" diferentes. Cada colección tiene diferentes reglas para el tiempo de vida de esa colección, y la visibilidad de los
Beans almacenados en ella. Juntos, las reglas que definen el tiempo de vida y la visiblidad se llama el ámbito de esos beans.
La especificación JavaServer Pages (JSP) define las elecciones de ámbito usando los siguientes términos (con el concepto del
API Servlet equivalente entre paréntesis):

• page - Beans que son visibles dentro de una sóla página JSP, para el tiempo de vida de la solicitud actual (Variables
locales del método service() )
• request - Beans que son visibles dentro de una sóla página JSP, así como EN cualquier página o servlet que esté
incluido en esta página, o reenviado por esta página. (Atributos Request).
• session - Beans que son visibles para todas las páginas JSP y los servlets que participan en una sesión de usuario
particular, a través de una o más solicitudes. (Atributos Session).
• application - Beans que son visibles para todas las páginas JSP y los servlets que forman parte de una aplicación Web.
(Atributos de contexto Servlet).

Es importante recordar que las páginas JSP y los servlets, al igual que las aplicaciones Web comparten los mismos conjuntos
de colecciones de beans. Por ejemplo, un Bean almacenado como un atributo request en un servlet como este:

MyCart mycart = new MyCart(...);


request.setAttribute("cart", mycart);

es inmediatamente visible a una página JSP a la que se reenvíe este servlet, usando una etiqueta de acción estándard como
esta:

<jsp:useBean id="cart" scope="request"


class="com.mycompany.MyApp.MyCart"/>

Beans ActionForm

Nota: los beans ActionForm están realmente más cercanos a la Vista que al Modelo.

El marco de trabajo Struts generalmente asume que hemos definido un bean ActionForm (es decir, una clase Java que
extiende la clase ActionForm) por cada formulario de entrada necesario en nuEstra aplicación. Los beans ActionForm algunas
veces son sólo llamados "beans formuLario". Si declaramos dichos beans en nuestro fichero de configuración ActionMapping
(ver "Construir los Componentes del Controlador"), el servlet controlador Struts realiza automáticamente los siguientes servicios
por nosotros, antes de llamar al método Action apropiado:

• Chequea en la sesión de usuario si hay un ejemplar de un bean de la clase apropiada, bajo la clave apropiada.
• Si no está disponible dicho bean en el ámbio de la sesión, se crea uno nuevo automáticamente y se añade a la sesión
de usuario.
• Por cada parámetro de la solicitud cuyo nombre corresponda con el nombre de una propiedad del bean, se llamará al
correspondiente método set(). Esto opera de una forma similar a la acción JSP estándard <jsp:setProperty> cuando
usamos el comodín asterisco para seleccionar todas las propiedades.
• El bean ActionForm actualizado será pasado al método perform() de la clase Action cuando es llamado, haciendo que
esos valores estén disponibles inmediatamente.

Cuando codifiquemos nuestros beans ActionForm, debemos tener en mente los siguientes principios:

• La propia clase ActionForm no requiere que se implemente ningún método específico. Se usa para identificar el rol que
esos beans particulares juegan en la arquitectura general. Normalmente, un bean ActionForm sólo tendrá metodos
setxxx() y getxxx(), sin lógica de negocio.
• El objeto ActionForm también ofrece un mecanismo de validación estándard. Si sobreescribimos un método "stub", y
proporcionamos mensajes de error en el recurso de aplicación estándard, Struts validará automáticamente la entrada
del formualrio (usando nuestro método). Ver Validación del Formulario para más detalles. Por supuesto, también
podemos ignorar la validación de ActionForm y proporcionar nuestro propio objeto Action.
• Definir una propiedad (asociada con métodos getXxx() y setXxx()) para cada campo que esté presente en el formulario.
El nombre del campo y el nombre de la propiedad deben corresponder de acuerdo a las convenciones usuales de los
JavaBeans. Por ejemplo, un campo de entrada llamado username hará que se llame al método setUsername().
• Debemos pensar en nuestros beans ActionForm como firewall ente HTTP y el objeto Action. Usamos el método
validate para asegurarnos de que están presentes todas las propiedades requeridas, y que contienen valores
razonables. Un ActionForm que falla en la validación incluso ni será presentado para el manejo del Action.
• También podríamos situar un ejemplar bean en nuestro formulario, y usar referencias a propieades anidadas. Por
ejemplo, podríamos tener un bean "customer" en nuestro Action Form, y luego referirnos a la propiedad
"customer.name" en nuestra vista JSP. Esto correspondería con los métodos customer.getName() y
customer.setName(string Name) de nuestro bean customer.
• Cuidado: si anidamos ejemplares de beans existentes en nuestro formulario, debemos pensar en las propiedades que
exponemos. Cualquier propiedad pública en un ActionForm que acepta un simple valor String puede seleccionarse con
un string de consulta. Podría ser muy útil situar dichos beans dentro de una fina "envoltura" que exponga sólo las
propiedades requeridas. Esta envoltura también puede proporcionar un filtro para asegurarnos en tiempo de ejecución
de que las propiedades no se seleccionan con valores inapropiados.

Deberías haber observado que un "formulario", en el sentido discutido aquí, no corresponde necesariamente con una sóla
página JSP en el interface de usuario. Es común en muchas aplicaciones tener un "formulario" (desde la perspectiva del
usuario) que se extienda sobre múltiples páginas. Piensa por ejemplo, en un interface de usuario al estilo de los wizard que se
utilizan comunmente cuando instalamos nuevas aplicaciones. Struts nos aconseja definir un sólo ActionForm que contenga las
propiedades de todos los campos, sin importar que página de campo se está mostrando actualmente. De igual forma, las
distintas páginas del mismo formulario deberían ser reenvidas a la misma clase Action. Si seguimos estas sugerencias, los
diseñadores de páginas podrán reordenar los campos entre varias páginas, frecuentemente sin requerir que cambiemos la
lógica de procesamiento.

Beans de Estado del Sistema

El estado real de un sistema normalmente está representado por un conjunto de una o mas clases JavaBeans, cuyas
propiedades definen el estado actual. Un sistema de tarjeta de compra, por ejemplo, incluirá un bean que represente la tarjeta
que está siendo mantenida por cada comprador individual, e incluirá (entre otras cosas) un conjunto de ítems que el comprador
ha seleccionado. Separadamente, el sistema también incluirá diferentes beans para la información del perfil del usuario
(incluyendo su tarjeta de crédito y su dirección de envío), así como el catalogo de ítems disponibles y sus niveles de inventario
actuales.

Para sistemas de pequeña escala, o para información de estado que no necesita guardarse durante mucho tiempo, un conjunto
de beans de estado del sistema podría contener todos los conocimientos que el sistema tiene sobre esos detalles particulares.
O, como es el caso más frecuente, los beans de estado del sistema representarán información que está almacenada
permanentemente en alguna base de datos externa (como un objeto CustomerBean que responde a una fila de la tabla
CUSTOMERS), y son creados o eliminados de la memoria del servidor cuando se necesita. Los JavaBeans Enterprise de
Entidad también se usan para esto en aplicaciones de gran escala.

Beans de Lógica de Negocio

Deberíamos encapsular la lógica funcional de nuestra aplicación como llamadas a métodos en JavaBeans diseñados para este
propósito. Estos métodos pueden ser parte de las mismas clases usadas para los beans de estado del sistema, o podrían estar
en clases separadas dedicadas a realizar la lógica. En el último caso, normalmente necesitaremos pasarle los beans de estado
del sistema para que sean manipulados por estos métodos como argumentos.

Para una reutilización máxima del código, los beans de la lógica del negocio deberían ser diseñados e implementados para que
no sepan que están siendo ejecutados en un entorno de aplicación Web. Si nos encontramos que tenemos que importar una
clase javax.servlet.* en nuestro bean, estamos ligando ésta lógica de negocio al entorno de una aplicación Web. Debemos
considerar reordenar las cosas para que nuestras clases Action (parte del rol del Controlador, según se describe abajo)
traduzcan toda la información requerida desde la solicitud HTTP que está siendo procesada en llamadas a métodos setXxx() de
propiedades de nuestros beans de lógica de negocio, después de que se pueda hacer una llamada a un método execute().
Dicha clase de lógica de negocio podría reutilizarse en entornos distintos al de la aplicación Web para el que fue construida en
un principio.

Dependieno de la complejidad y del ámbito de nuestra aplicación, los beans de lógica de negocio podrían ser JavaBeans
ordinarios que interactúan con beans de estado del sistema que son pasados como argumentos, o JavaBeans ordinarios que
aceden a una base de datos usando llamadas JDBC. Para grandes aplicaciones, estos beans frecuentemente ofrecerán
JavaBeans Enterprise (EJBs) con o sin estado en su lugar.

Acceder a Bases de Datos Relacionales


Struts puede definir las fuentes de datos para una aplicación desde dentro de un fichero de configuración estándard. También
se proporciona un simple almacen de conexiones JDBC.

Después de definir la fuente de datos, aquí tenemos un ejemplo de cómo establecer una conexión desde dentro del método
perform de la clase Action:

public ActionForward
perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
{
try {
javax.sql.DataSource dataSource =
servlet.findDataSource(null);
java.sql.Connection myConnection =
dataSource.getConnection();

//do what you wish with myConnection


} catch (SQLException sqle) {
getServlet().log("Connection.process", sqle);
} finally {

//enclose this in a finally block to make


//sure the connection is closed
try {
myConnection.close();
} catch (SQLException e) {
getServlet().log("Connection.close", e);
}
}
}

Observa que el almacen de conexiones Struts genérico es un componente opcional. Muchas aplicaciones Struts usan otros
almacenes de conexiones para un mejor rendimiento, especialmente con sistemas de producción de alto volumen.

Construir los Componentes de la Vista

Introducción

Este capítulo se enfoca en la tarea de construir los componentes de la Vista de una aplicación, que principalmente está creada
usando tecnología JavaServer Pages (JSP). En particular Struts proporciona soporte para construir aplicaciones
internacionalizadas, así como para interactúar con formularios de entrada.

Mensajes Internacionalizados

Hace unos pocos años, los desarrolladores de aplicaciones podían tener que contar sólo con los residentes de su país, que
normalmente sólo usaban un idioma (a veces dos), y una forma de representar cantidades numéricas, como fechas, números y
valores monetarios. Sin embargo, la explosión del desarrollo de aplicaciones basadas en tecnologías Web, así como el
despliegue de dichas aplicaciones sobre Internet y otras redes accesibles, han hecho que los límites nacionales sean invisibles
en muchos casos. Esto se ha traducido en la necesidad de que las aplicaciones soporten la internacionalización
(frecuentemente llamada "i18n" porque 18 es el número de letras entre la "i" y la "n") y localization.

Struts se construye sobre la plataforma Java proporcionada para construir aplicaciones internacionalizadas y localizadas. Los
conceptos clava para familiarizarnos con ellos son:

• Locale - La clase fundamental Java que soporta internacionalización es java.util.Locale. Toda Locale representa una
elección particular de país e idioma (además de variantes opcionales del idioma), y también un conjunto de
asumpciones de formateo para cosas como los números y las fechas.
• ResourceBundle - La clase java.util.ResourceBundle proporciona la herramienta fundamental para el soporte de
mensajes en varios idiomas.
• PropertyResourceBundle - Una de las implementaciones estándard de ResourceBundle que nos permite definir
recursos usando la misma sintaxis "nombe=valor" usada para inicializar ficheros de propiedades. Esto es muy
conveniente para preparar paquetes de recursos con mensajes que son usados en una aplicación Web, porque estos
mensajes normalmente están orientados a texto.
• MessageFormat - La clase java.text.MessageFormat nos permite reemplazar porciones de un string de un mensaje (en
este cado, recuperado de un paquete de recursos) con argumentos especificados en tiempo de ejecución. Esto es útil
en casos donde estámos creando una sentencia, pero las palabras podrían aparecer en diferente orden en diferentes
idiomas. El string contenedor {0} del mensaje es reemplazado por el primer argumento, {1} es reemplazado por el
segundo argumento, etc.
• MessageResources - La clase Struts org.apache.struts.util.MessageResources nos permite tratar un conjunto de
paquetes de recursos como una base de datos, y nos permite solicitar un string de mensajes particular para una
Localidad particular (normalmente asociado con el usuario actual) en lugar de la localidad por defecto en la que el
propio servidor se está ejecutando.

Por favor, observa que el soporte de i18n en un marco de trabajo como Struts está limitado a la presentación de texto e
imágenes internacionalizadas al usuario.. El soporte para localidades específicas métodos de entrada (usado con idiomas
como el Japonés, el Chino y el Koreano) se deja al dispositivo del cliente, que normalmente es un navegador Web.

Para una aplicación internacionalizada, seguimos los pasos descritos en el documento Internationalization del paquete de
documentación del JDK de nuestra plataforma para crear un fichero de propiedades que contenga los mensajes para cada
idioma. Más adelante, un ejemplo ilustrará esto.

Asumimos que nuestro código fuente se ha creado en el paquete com.mycompany.mypackage, por eso está almacenado en un
directorio (relativo a nuestro directorio fuente) llamado com/mycompany/mypackage. Para crear un paquete de recursos
llamado com.mycompany.mypackage.MyResources, creariamos los siguientes ficheros en el directorio
com/mycompany/mypackage:

• MyResources.properties - Contiene los mensajes del idioma por defecto de nuestro servidor. Si el idioma por defecto
es Inglés, podríamos tener una entrada como esta:prompt.hello=Hello
• MyResources_xx.properties - Contiene los mismos mensajes en el idioma cuyo código de idioma ISO es "xx". Para una
versión Española del mensaje mostrado arriba, tendríamos esta entrada: prompt.hello=Hola. Podemos tener ficheros
de recursos para tantos idiomas como necesitemos.

Cuando configuramos el servlet controlador en el descriptor de despliegue de la aplicación Web, una de las cosas que
necesitamos definir en un parámetro de inicialización es el nombre base del paquete de recursos para la aplicación. En el caso
descrito arriba, sería com.mycompany.mypackage.MyResources.

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.mycompany.mypackage.MyResources</param-value>
</init-param>
<.../>
</servlet>

Los importante para este paquete de recursos es encontrarse en el classpath de nuestra aplicación. Otra aproximación es
almacenar el fichero MyResources.properties en la carpeta classes de nuestra aplicación. Entonces podremos especificar
simplemente "myResources" como el valor de la aplicación. Debemos tener cuidado de no borrarlo si construimos scripts de
borrado de clases como parte de una fuente de "limpieza".

Si lo hace, hay una tarea de Ant a ejecutar cuando compilemos nuestra aplicación que copia los contenidos de un directorio
src/conf al directorio classes:

<!-- Copy any configuration files -->


<copy todir="classes">
<fileset dir="src/conf"/>
</copy>

Interacciones de Forms y FormBean

Una vez u otra, la mayoría de los desarrolladores web han construido formularios usando las capacidades estándard del HTML,
como la etiqueta <input>. Los usuarios esperan que las aplicaciones interactivas tengan ciertos comportamientos, y uno de
estos está relacionado con el manejo de errores -- si el usuario comete un error, la aplicación debería permitirle corregir sólo lo
que necesita ser modificado -- sin tener que re-introducir cualquier parte del resto de la información de la página o formulario
actual.

Conseguir esto es tedioso y aburrido cuando codificamos usando HTML y páginas JSP. Por ejemplo, un elemento de entrada
para un campo username podría parecerse a esto (en JSP):

<input type="text" name="username"


value="<%= loginBean.getUsername() %>"/>

lo que es dificil de teclear correctamente, confunde a los desarrolladores HTML que no tienen conocimientos sobre conceptos
de programación, y puede causar problemas con editores HTML. En su lugar Struts proporciona una facilidad comprensiva
para construir formularios, basada en la facilidad de las Librerías de Etiquetas Personalizadas de JSP 1.1. El caso de arriba
sería renderizado de esta forma usando Struts:

<html:text property="username"/>

sin la necesidad de refirnos explicitamente al formulario JavaBean del que se recupera el valor inicial. Esto lo maneja
automáticamente el marco de trabajo.

Algunas veces los formularios HTML se usan para cargar otros ficheros. La mayoría de los navegadores soportan esto a través
de un elemento <input type="file">, que genera un botón navegador de ficheros, pero es cosa del desarrollador manejar los
ficheros entrantes. Struts maneja estos formularios "multipart" de la misma forma que los formularios normales. En la siguiente
sección, usaremos Struts para crear un simple formulario de login, y también un simple formulario multiparte.

Construir Formularios con Struts

Un ejemplo completo de un formulario de login ilustrara cómo Struts trata con los formularios de una forma menos dolorosa que
usar sólo las facilidades HTML y JSP estandards. Consideremos la siguiente página (basada en la aplicación de ejemplo
incluida con Struts) llamada logon.jsp:

<%@ page language="java" %>


<%@ taglib uri="/WEB-INF/struts-html.tld"
prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld"
prefix="bean" %>
<html:html>
<head>
<title>
<bean:message key="logon.title"/>
</title>
<body bgcolor="white">
<html:errors/>
<html:form action="/logon" focus="username">
<table border="0" width="100%">
<tr>
<th align="right">
<html:message key="prompt.username"/>
</th>
<td align="left">
<html:text property="username"
size="16"/>
</td>
</tr>
<tr>
<th align="right">
<html:message key="prompt.password"/>
</th>
<td align="left">
<html:password property="password"
size="16"/>
</td>
</tr>
<tr>
<td align="right">
<html:submit>
<bean:message key="button.submit"/>
</html:submit>
</td>
<td align="right">
<html:reset>
<bean:message key="button.reset"/>
</html:reset>
</td>
</tr>
</table>
</html:form>
</body>
</html:html>

Los siguientes ítems ilustran las características clave del manejo de formularios en Struts, basadas en este ejemplo:

• La directiva taglib le dice al compilador de la página JSP donde encontrar el tag library descriptor para la librería de
etiquetas Struts. En este caso, estamos usando bean como el prefijo que identifica las etiquetas de la librería struts-
bean, y "html" como el prefijo que identifica las etiquetas de la librería struts-html. Se puede usar cualquier prefijo que
deseemos.
• Esta página usa varias ocurrencias de la librería de mensajes para buscar los strings de mensajes internacionalizados
desde un objeto MessageResources que contiene todos los recursos de esta aplicación. Para que esta página
funcione, se deben definir las siguientes claves de mensajes en estos recursos:
o logon.title - Título de la página de login.
o prompt.username - Un string para pedir el "Username:"
o prompt.password - Un string para pedir la "Password:"
o button.submit - Etiqueta para el botón "Submit"
o button.reset - Etiqueta para el botón "Reset"

Cuando el usuario entra, la aplicación puede almacenar un objeto Locale en la sesión de este usuario. Este Locale se
usará para seleccionar mensajes en el idioma apropiado. Esto se hace sencillo de implementar dando al usario una
opción para elegir el idioma -- simplemente cambiamos el objeto Locale almacenado, y todos los mensajes se
modificaran automáticamente.

• Las banderas de error muestran cualquier mensaje de error que haya sido almacenado por un componente de lógica
de negocio, o ninguna si no se ha almacenado ningún error. Esta etiqueta se describirá más adelante.
• La etiqueta form renderiza un elemento <form> HTML, basándose en los atributos especificados. También asocia todos
los campos que hay dentro del formulario con un FormBean con ámbito de sesión que se almacena bajo la clave
logonForm. El desarrollador de Struts proporciona la implementación Java para este bean de formulario, extendiendo la
clase ActionForm de Struts. Este bean se usa para proporcionar valores iniciales para todos los campos de entrada
que tienen nombres que corresponden con nombres de propiedades del bean. Si no se encuentra un bean apropiado,
se creará uno nuevo automáticamente, usando el nombre de la clase Java especificado.
• El bean formulario también se puede especifiar en el fichero de configuración de Struts, en cuyo caso se pueden omitir
el Nombre y el Tipo. (Puedes ver más detalles en Fichero de Configuraciín para Action Mappings).
• La etiqueta text se renderiza como un elemento <input> de HTML del tipo "text". En este caso también se han
especificado el número de caracteres y la posición a ocupar en la ventana del navegador. Cuando se ejecuta esta
página, el valor actual de la propiedad username del bean correspondiente (es decir, el valor devuelto por
getUsername()).
• La etiqueta password se usa de forma similar. La diferencia está en que el navegador mostrará asteriscos, en lugar del
valor de entrada, mientras el usuario teclea su password...
• Las etiquetas submit y reset generan los botones correspondientes en la parte inferior del formulario. Las etiquetas de
texto para cada botón se crean usando la librería de mensajes, como las peticiones, para que estos valores sean
internacionalizados.

Manejar formularios multiparte también es sencillo. Obviamente cuando creamos un formulario multiparte estámos creando un
formulario que al menos tiene un entrada del tipo "file". El primer paso para crear el formulario multiparte es utlizar la librería de
etiquetas struts-html para crear la página de presentación:

<%@page language="java">
<%@taglib uri="/WEB-INF/struts-html.tld"
prefix="html">
<html:form action="uploadAction.do">
Please Input Text:
<html:text property="myText"><br/>
Please Input The File You Wish to Upload:<br/>
<html:file property="myFile"><br />
<html:submit />
</html:form>

El siguiente paso es crear nuestro bean ActionForm :

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
public class UploadForm extends ActionForm {
protected String myText;
protected FormFile myFile;
public void setMyText(String text) {
myText = text;
}
public String getMyText() {
return myText;
}
public void setMyFile(FormFile file) {
myFile = file;
}
public FormFile getMyFile() {
return myFile;
}
}

Podemos ver los Javadocs del FormFile para ver los métodos que expone para manipular y subir ficheros. También podemos
ver los Javadocs para ActionServlet y ActionMapping para ver los distintos parámetros que podemos especificar para cambiar
la forma en que se (suben) cargan los ficheros. Básicamente en nuestro método peform() de nuestra clase action deberíamos
llamar a ((UploadForm) form).getMyFile() para recuperar el FormFile y hacer lo que queramos con él.

Tipos de Campos de Entrada Soportados

Struts define etiquetas HTML para todos estos tipos de campos de entrada:

• checkboxes
• Campos hidden
• Campos de entrada password
• Botones de radio
• Botones de reset
• Lsitas select con opciones embebidas o ítems de opciones.
• option
• options
• Botones submit
• Campos de entrada de texto text
• textareas

En cada caso, una etiqueta de campo debe estár anidada dentro de una etiqueta form, por eso los campos saben qué bean
utilizar para inicializar los valores mostrados.

Otras Útiles Etiquetas de Presentación

Hay varias etiquetas útiles para crear presentaciones, consulta la documentación de cada librería de etiquetas especifica, junto
con la Guía de Desarrolladores de Etiquetas, para más información:

• [logic] iterate repite su cuerpo de etiqueta una vez por cada elemento de una colección especificada (que puede ser
una Enumeration, un Hashtable, un Vector, o un array de objetos).
• [logic] present dependiendo del atributo que se especifique, esta etiqueta chequea la solicitud actual, y evalua el
contenido de los campos anidados de esta etiqueta sólo si hay un valor presente. Sólo se puede usar uno de los
atributos en una ocurrencia de esta etiqueta, a menos que utilicemos el atributo property, en cuyo caso también es
necesario el nombre del atributo. Los atributos incluyen cookie, header, name, parameter, property, role, scope, y user.
• [logic] notPresent el contrario de la etiqueta present, notPresent proporciona la misma funcionalidad pero cuando el
atributo especificado no está presente.
• [html] link genera un elemento <a> HTML como una definición de un enlace o un hiperenlace a la URL especificada, y
automáticamente aplica codificación URL para mantener el estado de la sesión en la ausencia del soporte de cookies.
• [html] img genera un elemento <img> HTML con la habilidad de modificar dinámicamente las URLs especificadas por
los atributos "src" y "lowsrc" de la misma forma en que se puede hacer con <html:link>.
• [bean] parameter recupera el valor del parámetro solicitado, y define el resultado como un atributo de ámbito de página
del tipo String o String[].

Validación Automática de Formularios

Además de las interacciones entre el formulario y el bean descrita arriba, Struts ofrece una facilidad adicional para validar los
campos de entrada que ha recibido. Para utilizar esta característica, sobreesribimos el siguiente método en nuestra clase
ActionForm:
public ActionErrors
validate(ActionMapping mapping,
HttpServletRequest request);

El método validate() es llamado por el servlet controlador después de que se hayan rellando las propiedades del bean, pero
antes de se llame al método perform() correspondiente de la clase action. El método validate() tiene las siguientes opciones:

• Realiza las validaciones apropiadas y no encuentra problemas -- Devuelve null o ejemplares de ActionErrors de
longitud cero, y el servlet controlador procederá a llamar al método perform() de la clase Action apropiada.
• Realiza las validaciones apropiadas y encuentra problemas -- Devuelve un ejemplar de ActionErrors conteniendo
ActionError's, que son clases que contienen las claves del mensaje de error (dentro del paquete MessageResources de
la aplicación) que se deberían mostrar. El servlet controlador almacena este array como un atributo de la solicitud
disponible para usarse por la etiqueta <html:errors>, y devolverá el control al formulario de entrada (identificado por la
propiedad input de este ActionMapping).

Como se mencionó anteriormente, esta característica es totalmente opcional. La implementación por defecto de validate()
devuelve null, y el servlet controlador asumirá que no se requiere que se haga ninguna validación por parte de la clase Action.

Una aproximación común es realizar validaciones iniciales usando el método validate(), y luego manejar la validación de la
"lógica de negocio" desde el objeto Action.

Un paquete opcional para realizar validaciones ActionForm está disponible en la web site de David Winterfeldt's.

Otras Técnicas de Presentación

Aunque el aspecto y el comportamietno de nuestra aplicación puede construirse completamente basándonos en las
capacidades estándards de JSP y la librería de etiquetas de Struts, deberíamos considerar emplear otras técnicas que mejoren
la reutilización de componentes, reduzca los esfuerzos de mantenimiento, y/o reduzca los errores. En las siguientes secciones
se explican varias opciones.

Etiquetas Personalizadas Específicas de la Aplicación

Más allá del uso de las etiquetas personalizadas proporcioandas por la librería de Struts, es fácil crear etiquetas que sean
específicas de la aplicación que estamos construyendo, para asistirnos en la creación del interface de usuario. La aplicación de
ejemplo incluida con Struts ilustra este principio creando las siguientes etiquetas únicamente para la implementación de esta
aplicación:

• checkLogon - Chequea la existencia de un objeto session particular, y reenvía el control a la página de logon si no
esite. Esto se usa para capturar casos donde un usuario ha colocado un página del medio de la aplicación en su
bookmark e intenta saltarse el login. o si ha expirado la sesión de un usuario.
• linkSubscription - Genera un hiperenlace a una página de detalles para una Subscription, que pasa los valores de la
clave primaria requerida como atributos de la solicitud. Esto se usa cuando se listan las subcripciones asociadas con
un usuario, y proporciona enlaces para editarlas o borrarlas.
• linkUser - Genera un hiperenalce a una página de detalles de usuario, que pasa los valores de la clave primaria
requerida como un atributo de la solicitud.

El código fuente de estas etiquetas está en el directorio, src/example, en el paquete org.apache.struts.example, junto con otras
clases Java que son usadas por esta aplicación.

Composición de Páginas con Includes

Crear la presentación completa de una página en un fichero JSP (con etiquetas personalizadas y beans para acceder a los
datos dinámicos requeridos) es un aproximación de diseño muy común, y fue empleada en el ejemplo incluido con Struts. Sin
embargo, muchas aplicaciones requieren mostrar varias porciones de distinciones lógicas de nuestra aplicación en una sóla
página

Por ejemplo, una aplicación portal, podría tener alguna o todas estas capacidades funcionales disponibles en la página "home"
del portal:

• Acceso a un motor de búsqueda para este portal.


• Uno o más displays "alimentadores de noticias" con los tópicos de interés personalizados desde el perfil de registro del
usuario.
• Acceso a tópicos de discusión relacionados con este portal.
• Un indicador de "mail esperando" si nuestro portal proporciona cuentas gratuitas de correo.
El desarroolo de los distintos segmentos de esta site es sencillo si podemos dividir el trabajo y asignar los distintos segmentos
a diferentes desarrolladores. Luego, podemos usar la capacidad include de las páginas JSP para combinar los resultados en
una sóla página, o usar la etiqueta include proporcionada por Struts. Hay disponibles tres tipos de include, dependiendo de
cuando queremos que ocurra la combinación de la salida:

• Una directiva <%@ include file="xxxxx" %> puede incluir un fichero que contiene código Java o etiquetas JSP. El
código incluido en el fichero puede incluso referenciar variables declaradas antes en la página JSP exterior. El código
se pone en línea dentro de la otra página JSP antes de que sea compilada y por eso puede contener definitivamente
más que sólo código HTML.
• El include de action (<jsp:include page="xxxxx" flush="true" />) se procesa en el momento de la solicitud, y es
manejado de forma transparente por el servidor. Junto con otras cosas, esto significa que podemos realizar el include
condicionalmente anidandolo dentro de una etiqueta como equals usando sus atributos de parámetros
• La etiqueta bean:include toma un argumento "forward" que representa un nombre lógico mapeado al JSP a incluir, o el
argumento "id", que representa la variable string del contexto de la pagina a imprimir en la página JSP.

Otra aproximación a esto sería el uso de la librería de plantillas de etiquetas de Struts. Puedes ver más detalles en la Guia del
Desarrollador.

Tiles es una alternativa a la Librería de Plantilla de Etiquetas, ofreciendo varias mejoras y nuevas capacidades. Tiles está
disponible en el la web site de Cedric Dumoulin.

Componentes de Renderizado de Imágenes

Algunas aplicaciones requieren generar imágenes dinámicamente, como cartas de precios sobre una site de informe de stocks.
Normalmente se utilizan dos diferentes aproximaciones para obtener estos requerimientos:

• Renderizar un hiperenlace con una URL que ejecuta una solicitud Servlet. El servlet usa una librería gráfica para
renderizar la imagen, selecciona el tipo de contenido apropiadamente (como a image/gif), y envia de vuelta al
navegador los bytes de la imagen, que los mostrará como si hubiera recibido un fichero estático.
• Renderizar el código HTML necesario para descargar un Applet Java que cree el gráfico necesario. Podemos
configurar el gráfico selecionando los parámetros de inicialización del applet en el código de renderizado, o podemos
tener que hacer que el applet haga su propia conexión al servidor para recibir estos parámetros.

Dibujo de Texto

Algunas aplicaciones requieren que se genere texto o marcas, como XML, dinámicamente. Si está siendo renderizada una
página completa, y puede sacarse usando un PrintWriter, es muy fácil hacerlo desde un Action:

response.setContentType("text/plain"); // or text/xml
PrintWriter writer = response.getWriter();
// use writer to render text
return(null);
Construir los Componentes del Controlador

Introducción

Ahora que hemos entendido cómo construir los componentes del Modelo y de la Vista de nuestra aplicación, es hora de
enfocarnos en los componentes del Controller. Struts incluye un servlet que implementa la función principal de mapeo de una
solicitud URI a una clase Action. Por lo tanto, nuestras principales responsabilidades con el controlador son:

• Escribir una clase Action por cada solicitud lógica que podría ser recibida (extendida desde org.apache.action.Action).
• Configurar un ActionMapping (en XML) por cada solicitud lógica que podría ser enviada. El fichero de configuración
XML normalmente se llama struts-config.xml.
• Actualizar el fichero del descriptor de despliegue de la aplicación Web (en XML) para nuestra aplicación para que
incluya los componentes Struts necesarios.
• Añadir los componentes Struts apropiados a nuestra aplicación.

Clases Action

La clase Action define dos métodos que podrían ser ejecutados dependiendo de nuestro entorno servlet:

public ActionForward perform(ActionMapping mapping,


ActionForm form,
ServletRequest request,
ServletResponse response)
throws IOException, ServletException;

public ActionForward perform(ActionMapping mapping,


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

La mayoría de los proyectos sólo usarán la versión "HttpServletRequest".

El objetivo de una clase Action es procesar una solicitud, mediante su método perform(), y devolver un objeto ActionForward
que identifica dónde se debería reenviar el control (por ejemplo a una JSP) para proporcionar la respuesta apropiada. En el
patrón de diseño MVC/Model 2, una clase Action típica implementará una lógica como ésta en su método perform():

• Validar el estado actual de la sesión del usuario (por ejemplo, chequear que el usuario ha hecho el login). Si la clase
Action encuentra que no existe logon, la solicitud es reenviada a la página JSP que muestra las peticiones del nombre
de usuario y la password para logging on. Esto podría ocurrir porque un usuario intente entrar "en el medio" de una
aplicación (digamos, desde un bookmark), o porque la sesión ha expirado, y el contenedor servlet creó una nueva.
• Si la validación no se ha completado, valida las propiedades del bean formulario según sea necesario. Si se encuentra
un problema, almacena las claves de los mensajes de error apropiados como un atributo de la petición, y reenvía el
control de vuelta al formulario de entrada para que se puedan corregir los errores.
• Realizar el procesamiento requerido para tratar con esta solicitud (como grabar un fila de la base de datos). Esto se
puede hacer mediante código lógico embebido dentro de la propia clase Action, pero generalmente debería realizarse
llamando a un método apropiado del bean de lógica de negocio.
• Actualizar los objetos del lado del servidor que serán usados para crear la siguiente página del interface de usuario
(normalmente beans del ámbio de solicitud o de sesion, dependiendo de cuánto tiempo necesitemos mantener estos
ítems disponibles).
• Devolver un objeto ActionForward apropiado que identifica la página JSP usada para generar esta respuesta, basada
en los beans actualizados recientemente. Típicamente adquiriremos una referencia a dicho objeto llamando a
findForward() o al objeto ActionMapping que recibimos (si estamos usando un nombre lógico normal para este mapeo),
o en el propio servlet controlador (si estamos usando un nombre lógico global para la aplicación).

Entre los problemas de diseño a recordar cuando codificamos clases Action incluimos los siguientes:

• El servlet controlador crea un sólo ejemplar de nuestra clase Action, y la usa para todas las solicitudes. Es decir,
necesitamos codificar nuestra clase Action para que opere correctamente en un entorno multi-thread, como si
estuvieramos codificando un método service() de un servlet.
• El principio más importante que nos ayuda en la codificación de threads seguros es usar sólo variables locales, no
variables de ejemplar, en nuestra clase Action. Las variables locales se crean en una pila que es asignada (por nuestra
JVM) a cada thread solicitado, por eso no necesitamos preocuparnos de compartirlas.
• Los beans que representan el Modelo de nuestro sistema podría lanzar excepciones debido a problemas de acceso a
bases de datos o a otros recursos. Deberíamos atrapar dichas excpeciones en la lógica de nuestro método perform(), y
guardalas en el fichero de log de la aplicación (junto con el seguimiento de pila correspondiente) llamando a:
• servlet.log("Error message text", exception);
• Como regla general, asignar recursos y mantenerlos a través de las solicitudes del mismo usuario (en la misma sesión
de usuario) puede causar problemas de escalabilidad. Deberíamos pensar en liberar esos recursos (como las
conexions a una base de datos) antes de reenviar el control al componente de la Vista apropiado -- incluso si un
método del bean que hemos llamado lanza una excepción.

Además, queremos protegernos contra clases Action que son demasiado largas. La forma más fácil de hacer que esto suceda
es embeber la lógica funcional en la propia clase Action, en vez codificarla en beans de lógica de negocio independientes.
Además de hacer la propia clase Action dura de entender y de mantener, esta aproximación también hace díficil re-utilizar el
código de la lógica de negocio, porque está embebido dentro de un componente (la clase Action) que está concebido para ser
ejecutado en un entorno de aplicación Web.

Una Action puede dividirse en varios métodos locales, mientras que todas las propiedades necesarias sean pasadas en las
firmas de métodos. La JVM maneja dichas propiedades usando la pila, y por eso son seguras ante los threads.

La aplicación de ejemplo incluida con Struts no cumple este principio, porque la propia lógica de negocio está embebida dentro
de las clases Action. Esto debería considerarse un bug en el diseño de la aplicación de ejemplo, en vez de una característica
intrínseca de la arquitectura , o una aproximación a emular.

La Implementación de ActionMapping

Para poder operar satisfactoriamente, el servlet controlador Struts necesita conocer varias cosas sobre como se debería
mapear toda URI solicitada a una clase Action apropiada. El conocimiento requerido ha sido encapsulado en un interface Java,
llamado ActionMapping, estas son las propiedades más importantes:

• type - nombre totalmente cualificado de la clase Java que implementa la clase Action usada por este mapeo.
• name - El nombre del bean de formulario definido en el fichero de configuración que usará este action.
• path - El path de la URI solicitada que corresponden con la selección de este mapeo.
• unknown - Seleccionado a true si este action debería ser configurado como por defecto para esta aplicación, para
manejar todas las solicitudes no manejadas por otros action. Sólo un Action puede estar definido como por defecto
dentro de una sóla aplicación.
• validate - Seleccionado a true si se debería llamar al método validate() de la action asociada con este mapeo.
• forward - El path de la URI solicitada a la que se pasa el control cuando se ha invocado su mapeo. Esto es una
alternativa a declarar una propiedad type.

Fichero de Configuración de los Mapeos de Action

¿Cómo aprende el servlet controlador sobre los mapeos que queremos? Sería posible (pero tedioso) escribir una pequeña
clase Java que simplemente ejemplarizara nuevos ejemplares de ActionMapping, y llamara a todos los métodos set()
apropiados. Para hacer este proceso más sencillo, Struts incluye un módulo Digester que es capaz de leer la descripción
basada en XML de los mapeos deseados, creando los objetos apropiados de la misma forma. Puedes encontrar más
información sobre este Digester en la documentación del API

La responsabilidad del desarrollador es crear un fichero XML llamado struts-config.xml, y situarlo en el directorio WEB-INF de
su aplicación. Este formato de documento está restringido por su definición en "struts-config_1_0.dtd". El elemento XML más
exterior debe ser <struts-config>.

Dentro del elemento <struts-config>, hay dos elementos importantes que son usados para describir nuestras acciones:

• <form-beans>
Esta sección contiene nuestras definiciones de beans. Usamos un elemento <form-bean> por cada bean de formulario,
que tiene los siguientes atributos importantes:
o name: Un identificador único para este bean, que será usado para referenciarlo en los correspondientes
mapeos de acciones. Normalmente, es también el nombre del atributo de solicitud o sesión bajo el que se
almacena este bean de formulario.
o type: El nombre totalmente cualificado de la clase Java de nuestro bean de formulario.
• <action-mappings>
Esta sección contiene nuestras definiciones de acciones. Usamos un elemento <action> por cada una de nuestras
acciones que queramos definir. Cada elemento action requiere que se definan los siguientes atributos:
o path: El path a la clase action en relación al contexto de la aplicación.
o type: El nombre totalmente cualificado de la clase Java de nuestra clase Action.
o name: El nombre de nuestro elemento <form-bean> para usar con esta action.
El fichero struts-config.xml de la aplicación de ejemplo incluye las siguientes entradas de mapeo para la función "log on", que
se usará para ilustrar los requerimientos. Oserva que las entradas para otras acciones se han dejado fuera:

<struts-config>
<form-beans>
<form-bean
name="logonForm"
type="org.apache.struts.example.LogonForm" />
</form-beans>
<global-forwards
type="org.apache.struts.action.ActionForward" />
<forward name="logon" path="/logon.jsp"
redirect="false" />
</global-forwards>
<action-mappings>
<action
path="/logon"
type="org.apache.struts.example.LogonAction"
name="logonForm"
scope="request"
input="/logon.jsp"
unknown="false"
validate="true" />
</action-mappings>
</struts-config>

Primero se define el bean formulario, Un bean básico de la clase "org.apache.struts.example.LogonForm" es mapeado al


nombre lógico "logonForm". Este nombre se usa como un nombre de atributo de sesión o solicitud para el bean de formulario.

La sección "global-forwards" se usa para crear mapeos de nombres lógicos para páginas JSP usadas comunmente. Cada uno
de estos reenvíos está disponible a través de una llamada a nuestro ejemplar de mapeo de action, por ejemplo
actionMappingInstace.findForward("logicalName").

Como podemos ver, este mapeo corresponde con el path /logon (realmente, porque la aplicación de ejemplo usa mapeo de
extensión, la URI que especificamos en una página JSP terminaría en /logon.do). Cuando se recibe una solicitud que
corresponde con el path, se crea un ejemplar de LogonAction (sólo la primera vez). El Servlet controlador buscará un bean de
ámbito de sesión bajo la clave logonForm, creando y guardando un bean de la clase especificada si es necesario.

Opcionales pero muy útiles son los elementos localizados en "forward". En la aplicación de ejemplo, muchas acciones incluyen
un reenvio local "success" y/o "failure" como parte de un mapeo de Action.

<!-- Edit mail subscription -->


<action path="/editSubscription"
type="org.apache.struts.example.EditSubscriptionAction"
name="subscriptionForm"
scope="request"
validate="false">
<forward name="failure" path="/mainMenu.jsp"/>
<forward name="success" path="/subscription.jsp"/>
</action>

Usando estas dos propiedades extras, las clases Action de la aplicación de ejemplo son casi totalmente independientes de los
nombres reales de las páginas JSP que son usadas por los diseñadores, Las páginas, pueden renombrarse (por ejemplo)
durante un rediseño, con un mínimo impacto en las propias clases Action. Si los nombres de las páginas JSP "next" estuvieran
codificados dentro de las clases Action, todas estas clases tendrían que ser modificadas. Por supuesto, podemos definir
cualquier propiedad de reenvío local que tenga sentido para nuestra aplicación.

Una sección más de buen uso es la sección <data-sources>, que especifica las fuentes de datos que puede usar nuestra
aplicación. Aquí podemos ver cómo especificar una fuente de datos para nuestra aplicación dentro de struts-config.xml:

<struts-config>
<data-sources>
<data-source
autoCommit="false"
description="Example Data Source Description"
driverClass="org.postgresql.Driver"
maxCount="4"
minCount="2"
password="mypassword"
url="jdbc:postgresql://localhost/mydatabase"
user="myusername"/>
</data-sources>
</struts-config>

Descriptor de Despliegue de la Aplicación Web

El paso final en la configuración de la aplicación es configurar el descriptor de despliegue (almacenado en el fichero WEB-
INF/web.xml) para incluir todos los componentes Struts que son necesarios. Usando el descriptor de despliegue del la
aplicación de ejemplo como guía, veremos que se necesitan crear o modificar la siguientes entradas.

Configurar el Ejemplar de Action Servlet

Añadimos una entrada definiendo el propio servlet action, junto con los parámetros de inicialización apropiados. Dicha entrada
se podría parecer a esto:

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>
org.apache.struts.example.ApplicationResources
</param-value>
</init-param>
<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>2</param-value>
</init-param>
<init-param>
<param-name>mapping</param-name>
<param-value>
org.apache.struts.example.ApplicationMapping
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

Los parámetros de inicialización soportados por el servlet controlador se describen abajo. Los corchetes cuadrados describen
los valores por defecto que se asumen si no proporcionamos un valor para el parámetro de inicialización.

• application - El nombre de la clase Java para la clase base del paquete de recursos de la aplicación. [NONE].
• bufferSize - El tamaño del buffer de entrada usado para procesar uploads de ficheros. [4096].
• config - Path relativo al contexto del recurso XML que contiene nuestra información de configuración.[/WEB-INF/struts-
config.xml].
• content - Tipo de contenido por defecto y codificación de caracteres a seleccionar en cada respuesta; podría ser
sobreescrito por un servlet re-enviado o una página JSP. [text/html].
• debug - El nivel de detalle de depuración para este servlet, que controla cuanta información se pone en el log. [0].
• detail - El nivel de detalles de depuración para el Digester que utilizamos en initMapping(), que sale por System.out en
lugar de servlet log. [0].
• factory - El nombre de la clase Java del MessageResourcesFactory usado para crear el objeto MessageResources de
la aplicación. [org.apache.struts.util.PropertyMessageResourcesFactory].
• formBean - El nombre de la clase Java de la implementación de ActionFormBean a utilizar.
[org.apache.struts.action.ActionFormBean].
• forward - el nombre de la clase Java de la implemetnación de ActionForward a utilizar.
[org.apache.struts.action.ActionForward]. Podríamos usar aquí dos clases de conveniencia:
o org.apache.struts.action.ForwardingActionForward - Subclase de org.apache.struts.action.ActionForward que
por defecto pone la propiead redirect a false (lo mismo que el valor por defecto de ActionForward).
o org.apache.struts.action.RedirectingActionForward - Subclase de org.apache.struts.action.ActionForward que
por defecto pone la propiedad redirect a true.
• locale - Si se selecciona a true, y hay una sesión de usuario, indentifica y almacena un objeto java.util.Locale apropiado
(bajo la clave estándard indentificada por Action.LOCALE_KEY) en la sesión de usuario si no hay ya un objeto Locale.
[true]
• mapping - El nombre de la clase Java de la implementación del ActionMapping a utilizar.
[org.apache.struts.action.ActionMapping]. Podríamos usar aquí dos clases de conveniencia:
o org.apache.struts.action.RequestActionMapping - Subclase de org.apache.struts.action.ActionMapping que por
defecto deja la propiedad scope a "request".
o org.apache.struts.action.SessionActionMapping - Subclase de org.apache.struts.action.ActionMapping que por
defecto deja la propiedad scope a "session". (Igual que el valor por defecto de ActionMapping).
• maxFileSize - El tamaño máximo (en bytes) para que un ficheo sea aceptado para upload. Puede expresarse como un
número seguido por una K" "M", o "G", que serán interpretadas como kilobytes, megabytes, o gigabytes,
respectivamente. [250M].
• multipartClass - El nombre totalmente cualificado de la clase de la implementación de MultipartRequestHandler usado
para procesar uploads de ficheros. [org.apache.struts.upload.DiskMultipartRequestHandler].
• nocache - Si se selecciona a true, añade cabeceras HTTP a cada respuesta para evitar que el navegador almacene en
el cahé cualquier respuesta generado o reenviada. [false].
• null - Si se selecciona a true, configura los recursos de nuestra aplicación a devolver null si se usa una clave de
mensaje desconocida. De otra forma, se devolverá un mensaje de error incluyendo la clave errónea. [true].
• tempDir - El directorio de trabajo temporal usado cuando se procesan uploads de ficheros. [El directorio de trabajo
proporcionado para esta aplicación web como atributo contexto del servlet].
• validate - ¿Estámos suando el nuevo formato de fichero de configuración? [true].
• validating - ¿Deberíamos usar un analizador con validación XML para procesar el fichero de configuración (altamente
recomendado? [true].

Configurar el Mapeo del Servlet Action

Nota: El material de esta sección no es específico de Struts. La configuración del mapeo de servlets está definida en la Java
Servlet Specification. Esta sección describe los significados más comunes de configuración de una aplicación Struts.

Hay dos aproximaciones comunes para definir las URLS que serán procesadas por el servlet controlador -- correspondencia de
prefijo y correspondencia de extensión.

La correspondencia de prefijo significa que queremos que todas las URLs que empiecen con (después de la parte del path de
contexto) un valor particular sean pasadas a este servlet. Dicha entrada se podría parecer a esto:

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/execute/*</url-pattern>
</servlet-mapping>

lo que significa que una URI que coincida con el path /logon descrito anteriormente podría parecerse a esto:

http://www.mycompany.com/myapplication/execute/logon

donde /myapplication es el path de contexto bajo el que se ha desplegado nuestra aplicación.

Por otro lado, en el mapeo por extensión, se renvian las URIs solicitadas al servlet action basándose en el hecho de que la URI
termine en un punto seguido por un conjunto defindo por caracteres. Por ejemplo, el servlet de procesamiento JSP está
mapeado al patrón *.jsp para que sea llamado cada vez que se solicite una página JSP. Para usar la extensión *.do (que
implica "hacer algo"), la entrada de mapeo se podría parecer a esta:

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

y una URI que corresponda con el path /logon descrito anteriormente se parecería a esto:

http://www.mycompany.com/myapplication/logon.do

Configurar la Librería de Etiquetas de Struts


Luego, debemos añadir una entrada definiendo la librería de etiquetas Struts. Actualmente hay cuatro librerías que vienen con
Struts.

La librería struts-bean contiene etiquetas útiles para acceder a los beans y sus propiedades, así como para definir nuevos
beans (basados en esos accesores) que son accesibles para el resto de la página mediante variables de scripting y atributos
de ámbito de página. También se proporcionan mecanismos convenientes para crear nuevos beans basados en el valor de una
cookie, de las cabeceras y de los parámetros.

La librería struts-html contiene etiquetas para crear formularios de entrada struts, así como otras etiquetas generalmente útiles
en la creación de interfaces de usuario basados en HTML.

La librería struts-logic contiene etiquetas que son útiles para manejar la generación condicional de salida de texto, hacer bucles
sobre colecciones de objetos para generación repetitiva de salida de texto y control del flujo de la aplicación.

La librería struts-template contiene etiquetas que definen un mecanismo de plantillas.

Abajo podemos ver cómo se definirían todas las librerías de etiquetas para usarlas en nuestra aplicación, en realidad, sólo
deberíamos especificar las librerías que vayamos a utilizar:

<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-html.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-html.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
/WEB-INF/struts-logic.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-logic.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
/WEB-INF/struts-template.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-template.tld
</taglib-location>
</taglib>

Esto le dice al sistema JSP donde encontrar el descritor de librería de etiqueta para esta librería (en nuestro directorio WEB-
INF de la aplicación, en vez de en algún lugar exterior en Internet).

Añadir Componentes Struts a nuestra Aplicación

Para usar Struts, debemos copiar los ficheros .tld que necesitamos en nuestro directorio WEB-INF, y copiar struts.jar (y todos
los otros ficheros commons-*.jar) en nuestro directorio WEB-INF/lib.

You might also like