Tutorial Struts - 2016 Java Revolutions

Anuncio
Curso de Struts
Contenido



Introducción a Struts
o
Prerrequisitos
o
Prefacio: Un paso hacia el pasado (o una breve historia de
Struts)
o
El Patrón de Diseño ('MVC') Modelo-Vista-Controlador
o
Introducción al Marco de Trabajo de Struts
o
El Modelo: Estado del Sistema y JavaBeans de la Lógica de
Negocio
o
La Vista: Páginas JSP y Componentes de Presentación
o
El Controlador: ActionServlet y ActionMapping
Construir los Componentes del Modelo
o
Introducción
o
Los JavaBeans y el Ámbito
o
Beans ActionForm
o
Beans de Estado del Sistema
o
Beans de Lógica de Negocio
o
Acceder a Bases de Datos Relacionales
Construir los Componentes de la Vista
o
Introducción
o
Mensajes Internacionalizados
o
Interacciones de Forms y FormBean
o

Construir Formularios con Struts

Tipos de Campos de Entrada Soportados

Otras Útiles Etiquetas de Presentación

Validación Automática de Formularios
Otras Técnicas de Presentación

Etiquetas Personalizadas Específicas de la
Aplicación

Composición de Páginas con Includes
www.javarevolutions.com
Canal YouTube: Java Revolutions


Componentes de Renderizado de Imágenes

Dibujo de Texto
Construir los Componentes del Controlador
o
Introducción
o
Clases Action
o
La Implementación de ActionMapping
o
Fichero de Configuración de los Mapeos de Action
o
Descriptor de Despliegue de la Aplicación Web

Configurar el Ejemplar de Action Servlet

Configurar el Mapeo del Servlet Action

Configurar la Librería de Etiquetas de Struts
Añadir Componentes Struts a nuestra Aplicación
www.javarevolutions.com
Canal YouTube: Java Revolutions
Introducción a Struts
Prerequisitos
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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
www.javarevolutions.com
Canal YouTube: Java Revolutions
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
www.javarevolutions.com
Canal YouTube: Java Revolutions
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):
www.javarevolutions.com
Canal YouTube: Java Revolutions




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:
www.javarevolutions.com
Canal YouTube: Java Revolutions






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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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,
www.javarevolutions.com
Canal YouTube: Java Revolutions
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
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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,
www.javarevolutions.com
Canal YouTube: Java Revolutions
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">
www.javarevolutions.com
Canal YouTube: Java Revolutions
<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
www.javarevolutions.com
Canal YouTube: Java Revolutions




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;
}
www.javarevolutions.com
Canal YouTube: Java Revolutions
}
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>.
www.javarevolutions.com
Canal YouTube: Java Revolutions

[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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions


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
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions


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 reutilizar 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
www.javarevolutions.com
Canal YouTube: Java Revolutions
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.
www.javarevolutions.com
Canal YouTube: Java Revolutions
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 -->
www.javarevolutions.com
Canal YouTube: Java Revolutions
<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>
www.javarevolutions.com
Canal YouTube: Java Revolutions
<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).
www.javarevolutions.com
Canal YouTube: Java Revolutions
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].
o









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>
www.javarevolutions.com
Canal YouTube: Java Revolutions
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:
www.javarevolutions.com
Canal YouTube: Java Revolutions
<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 WEBINF, y copiar struts.jar (y todos los otros ficheros commons-*.jar) en nuestro directorio
WEB-INF/lib.
www.javarevolutions.com
Canal YouTube: Java Revolutions
Descargar