Tema 4 - Apache Jakarta
Struts
Dr. Diego Lz. de Ipiña Gz. de Artaza
http://paginaspersonales.deusto.es/dipina
http://paginaspersonales.deusto.es/dipina/cursos/J2EECesine.zip
[email protected]
Contenido


Patrón de diseño MVC
La framework Apache Struts


Instalación
Flujo de control en Struts







Procesamiento de peticiones
Control de errores
Manejo de Formularios
Librerías de etiquetas de Struts
Internacionalización
Ejemplo de aplicación Struts
Java Server Faces
Modelos de desarrollo de
aplicaciones web en Java




Los servlets son buenos ejecutando lógica de negocio,
pero no son tan buenos presentando información
JSPs son muy buenos presentando pero pésimos
introduciendo lógica programática en ellos
La combinación Servlet/JSPs es lo más común hoy en día
en el desarrollo de aplicaciones web
Dos arquitecturas:


Model-1: JSPs para presentación y control y JavaBeans para
la lógica
Model-2: Model-View-Controller = JavaBeans-JSPs-Servlets

MVC es tan común que se han desarrollado varias
infraestructuras en torno a este patrón de diseño:


Apache Struts
Java Server Faces
Arquitectura Model 1
Arquitectura Model 2
Modelo MVC 0
Modelo MVC I

El Controlador (Controller)



Servlet central recibe peticiones, procesa
URL recibida y delega procesamiento a
JavaBeans
Servlet guarda resultado de procesamiento
realizado por JavaBeans en el contexto de
la petición, la sesión o la aplicación
Servlet transfiere control a un JSP que lleva
a cabo la presentación de resultados
Modelo MVC II
El Modelo (Model)


JavaBeans (o EJBs para aplicaciones más
escalables) desempeña el rol de modelo:



Algunos beans ejecutan lógica
Otros guardan datos
Normalmente:
1.
2.
Servlet controlador invoca un método en
bean lógico y éste devuelve un bean de datos
Autor de JSP tiene acceso a bean de datos
Modelo MVC III

La Vista (View)



Rol ejecutado por JSPs
Servlet Controlador transfiere control al JSP
después de haber guardado en un
contexto el resultado en forma de un bean
de datos
JSP usa jsp:useBean y
jsp:getProperty para recuperar datos
y formatear respuesta en HTML o XML
Modelo MVC IV

En resumen:



Los beans o EJBs ejecutan la lógica de
negocio y guardan los resultados
Los JSPs proveen la información
formateada
Los servlets coordinan/controlan la
ejecución de los beans y los JSPs
Frameworks


Las frameworks pueden ser vistas como
implementaciones de patrones de diseño que
facilitan la reutilización de diseño y código
Dado que MVC ha sido utilizado en muchas
aplicaciones web, el desarrollo de frameworks
que den soporte a áreas comunes en todas
las aplicaciones MVC es necesario


Apache Struts es una de estas frameworks
Aplicaciones basadas en Struts consistirán de:


Código Java
Deployment descriptors que configuran la
framework para el uso de nuestra aplicación
Apache Jakarta Struts


Implementación del modelo 2/patrón de
diseño MVC que facilita la creación de
aplicaciones web en Java
Creada por Craig McClanahan y donada
a la Apache Software Foundation en el
2000 (pertenece a Apache Jakarta)
¿Qué proporciona Struts?


Un servlet (ActionServlet) que actúa como controlador MVC
totalmente configurable
Clases base que son extendidas para implementar la lógica de la
aplicación web:








Struts Action
Struts ActionForm
Un rico conjunto de etiquetas personalizadas JSP que cooperan
con el controlador para su uso en la capa view de MVC
Varias opciones para la validación de entrada de usuario en
formularios HTML: ActionForm o Validator Framework
Mecanismos para el manejo y reporte de errores
Soporte para la internacionalización (i18n) a través de ficheros
de recursos y Java Locales
Soporte para fuentes de datos
Y más …..
Instalando Apache Struts I


Instalar Apache Tomcat 4.x o superior
Bajar la última versión de Apache Struts de:
http://struts.apache.org/download.cgi



Actualmente en la versión 1.2 (fichero jakarta-struts-1.2.4.zip para
Windows)
Crear directorio de aplicación. E.j: myStrutsApp
Copiar ficheros .tld en directorio
{StrutsDirectory}/contrib/struts-el/lib a
myStrutsApp/WEB-INF:




c.tld
struts-bean-el.tld
struts-html-el.tld
struts-logic-el.tld
Instalando Apache Struts II

Copiar los ficheros .jar files de
{StrutsDirectory}/contrib/struts-el/lib a
myStrutsApp/WEB-INF/lib directory:









commons-beanutils.jar
commons-collections.jar
commmons-digester.jar
commons-logging.jar
jstl.jar
standard.jar
struts-el.jar
struts.jar
Lo mejor es tomar la aplicación struts-blank.war como
punto de partida.
Documentación y ejemplos de
Struts

En el directorio webapps de la distribución
de Struts 1.2 se pueden encontrar varios
ficheros .war muy útiles:

struts-documentation.war



En el subdirectorio api/index.html se puede
encontrar JavaDoc de Struts API
Si se ejecuta esta aplicación web en
http://localhost:8080/struts-documentation/ se puede
también obtener información detallada sobre el uso de
Struts
Ejemplos de uso de Struts:



struts-examples.war
struts-blank.war  base para la creación de
cualquier aplicación que use Struts
etc.
Flujo de Control en Struts I
Flujo de Control en Struts II
Flujo de control en Struts III

La clase org.apache.struts.action.ActionServlet es el eje de Struts.
Dada una petición de entrada HTTP:





El fichero de configuración web.xml contiene los url mappings para enviar las
peticiones de llegada al ActionServlet, mientras que el fichero de
configuración de Struts struts-config.xml contiene los mappings a
acciones
Los form beans creados por ActionServlet deben ser implementados por el
programador, extendiendo org.apache.struts.action.ActionForm.



Crea un objeto ActionForm donde guarda y valida los parámetros de entrada
Decide que objeto Action se debe invocar y le pasa el objeto ActionForm creado
Transfiere control a la siguiente etapa de procesamiento de la petición (típicamente un
JSP).
El programador deberá definir un conjunto de getters y setter y sobreescribir los
métodos validate() y reset()
Los objetos Action invocados deben ser desarrollados por el programador y
extienden org.apache.struts.action.Action. Tienen un método
execute() o (perform() en Struts 1.0) que ejecuta la lógica de negocio
La acción devuelve un objeto ActionForward al servlet que especifica el
siguiente paso a ejecutar, normalmente se transfiere el control a un JSP para
que visualice los resultados.
Pasos a seguir en el desarrollo
de una aplicación en Struts










Diseña la aplicación en términos de las acciones, vistas y estados del
modelo
Añade las librerías Java de Struts y los .tlds de sus etiquetas
personalizadas a tu proyecto
Configura tu web.xml para que envíe peticiones HTTP al ActionServet
Configura el ActionServlet definiendo elementos <actionmappings> y <form-beans> en struts-config.xml
Define tus clases Action
Define tus clases ActionForm
Define clases adicionales Java representando la lógica de negocio
Define tus páginas de presentación JSP
Desplegar la aplicación
La aplicación ejemplo suministrada con Struts, struts-blank.war, es
normalmente un buen punto de partida para desarrollar una nueva
aplicación usando Struts
Actions en Struts


Se crea una acción extendiendo la clase
org.apache.struts.action.Action
El ActionServlet ejecuta acciones invocando el método
execute() tu clase Action


Dentro del método execute() tienes acceso a:






El método execute() contiene código para manipular el modelo
Cabeceras y parámetros de peticiones HTTP
Atributos/beans guardados en los contextos
application/session/request scope
Struts ActionForm asociados con la acción (opcional)
El ActionMapping associado a esta acción (opcional)
El objeto httpResponse
El método execute() devuelve un objeto ActionForward
que indica al ActionServlet a dónde transferir el control a
continuación
Form Beans

Un ActionForm es un JavaBean con propiedades que corresponden a los
controles de un formulario HTML. Los parámetros son mapeados a
propiedades del bean.







Proveen un mecanismo de buffer/validate/convert que necesitamos para
asegurarnos que el usuario introduce los datos esperados
Actúa como puente entre el navegador y el objeto de negocio
El programador define un form bean extendiendo la clase
org.apache.struts.action.ActionForm (o de forma declarativa
usando org.apache.struts.action.DynaActionForm)
Hay que definir cada una de las propiedades en la clase y escribir los
getters/setters correspondientes, siguiendo las reglas de JavaBeans
Después de escribir el código del form bean, es necesario asociarlo con
una o más acciones a través del fichero de configuración de Struts
struts-config.xml
Cada vez que se llama a la acción , el ActionServlet poblará las
propiedades con los valores de los parámetros recibidos en el formulario
HTML
Las propiedades no sólo pueden ser escalares sino que también pueden
ser colecciones de valores
¿Por qué se necesitan Forms
Beans?


¿Por qué no simplemente se accede a los parámetros de una
petición, en vez de usar un form bean como intermediario?
Razones:

Los Form beans pueden ser validados antes de que una acción sea
invocada


Si un form bean falla en la validación puede hacer que Struts envíe
al usuario de vuelta a la vista (JSP) desde la que se realizó el POST
en primer lugar, junto con un mensaje de error


Si la propiedad validate de un elemento Action en el fichero
struts-config.xml contiene el valor true (por defecto), el método
validate será invocado
Es importante asignar a la propiedad input del elemento action en
struts-config.xml una referencia a la vista que entregó el
formulario
Los form beans pueden ser usados por múltiples acciones o incluso
una aplicación completa

Si se configura al ActionController para que guarde un form bean
en el contexto de sesión se permitirá el uso del form bean en todas las
peticiones web que llegan a la aplicación
Dynamic Action Forms


Son ActionForms creados de manera declarativa en strutsconfig.xml
Una o varias propiedades dinámicas pueden ser pasadas a una
instancia de org.apache.struts.action.DynaActionForm
<form-bean name=“checkoutForm”
type=“org.apache.struts.action.DynaActionForm”>
<form-property name=“firstName”
type=“java.lang.String”/>
<form-property name=“lastName”
type=“java.lang.String”/>
<form-property name=“age” type=“java.lang.Integer”
initial=“18”/>
</form-bean>
Recursos de String/Manejo de
Errores

Recursos de String



Todos los strings usados en mensajes en JSPs tanto de datos de aplicación
como de errores puedes ser colocados en un ficheros de recursos
(ApplicationResources.properties)
Struts proporciona etiquetas personalizadas JSP tags para acceder a estos
recursos
<bean:message key="prompt.goodguess.heading"/>
Manejo de errores

Se recomienda que el manejo de errores se lleve a cabo dentro del método
execute() y el control se transfiera a la vista apropiada
errors.add("passphrase",new
ActionError("error.passphrase.required"));


Struts proporciona un mecanismo separado para permitir la implementación
de un manejador global de excepciones
Struts proporciona etiquetas JSP que ayudan en la visualización de los
errores en tu JSP:
<html:errors property=“passphrase”/>
Internationalization i18n




Struts soporta internacionalización a través de ficheros de recursos, sus
librerías de etiquetas personalizadas y Java Locales
Se pueden definir strings a visualizar en tu fichero de recursos, y luego ser
usados en tus JSPs
Los strings del idioma por defecto se guardan en el fichero
ApplicationResources.properties
Otros ficheros de recursos adicionales pueden ser definidos que incluyen el
idioma a usar en el nombre del fichero.

Ejemplo:





ApplicationResources_eu.properties (Contiene mensajes en Euskera)
ApplicationResources_es.properties (Contiene mensajes en Castellano)
Para cambiar el idioma preferido en IE: ToolsInternet OptionsLanguages
Los navegadores envían la cabecera HTTP Accept-Language en cada
petición que indica cuál es el idioma preferido por el usuario
Los ficheros de recursos deben colocarse en un lugar accesible desde el
CLASSPATH de la aplicación web, por ejemplo, debajo del directorio WEBINF/classes
Ejemplo web.xml de aplicación
usando Struts
<web-app>
<!-- Action Servlet Configuration -->
<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.develop.ejsp.struts.resources.ApplicationResources
</param-value>
</init-param>
<init-param>
<!– etc. -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <!-- Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
Configurando Struts

Como en toda framework se minimiza el código Java
a escribir y se maximiza la configuración a través de
ficheros XML



Struts se configura a través struts-config.xml
Leído por la framework cuando arranca
Contiene:


Fuentes de datos (data-sources)
Form beans, variaciones de JavaBeans.






Ejecutan una petición basado en una entrega de un formulario.
Son poblados por el controlador con los datos del formulario
Llevan a cabo validación de datos
Son procesados por objetos Action
Global forwards y
ActionMappings

Mapean el nombre de una acción a un objeto Action
Ejemplo struts-config.xml I
<struts-config>
<data-sources>
<data-source name=“usuarios”>
<set-property property= "autoCommit" value="false"/>
<set-property property= "description" value="MessageBoard"/>
<set-property property= "driverClass" value="..SQLServerDriver"/>
<set-property property= "maxCount" value="4"/>
<set-property property= "minCount" value="2"/>
<set-property property="password" value=""/>
<set-property property= "url"value="someurl"/>
<set-property property= "user" value="someuser"/>
</data-source>
</data-sources>
<!-- === Form Bean Definitions === -->
<form-beans>
<form-bean name="SigninForm"
type= "com.develop.ejsp.struts.beans.SigninForm"/>
</form-beans>
<!-- === Global Forward Definitions === -->
<global-forwards>
<forward name="signin" path="/signin.jsp"/>
</global-forwards>
Ejemplo struts-config.xml II
<!-- === Action Mapping Definitions === -->
<action-mappings> <!-- Process a user logon -->
<action path="/SigninAction“
type= "com.develop.ejsp.struts.actions.SigninAction“
name="SigninForm"
scope="session“
input="/signin.jsp">
<forward name="succeeded" path="/groups.jsp"/>
<forward name="failed" path="/groups.jsp"/>
</action>
<action path="/GotoReplyToAction“
type= "com.develop.ejsp.struts.actions.GotoMessageAction">
<forward name="succeeded" path="/newmessage.jsp"/>
<forward name="failed" path="/groups.jsp"/>
</action>
</action-mappings>
</struts-config>
Procesamiento de una petición
en Struts I

Si el cliente envía la petición:




http://server/app/GotoReplyToAction.do
El ActionServlet de Struts quita la extensión
(.do) y mira la acción correspondiente en el fichero
de configuración Struts para la acción
GotoReplyToAction
Si la encuentra encontrará o creará una instancia del
‘tipo’ (type) indicado:
com.develop.ejsp.struts.actions.GotoMes
sageAction
El método execute() será invocado en el objeto
GotoMessageAction:

Este es el lugar donde la lógica de negocio de la petición es
ejecutada
Procesamiento de petición en
Struts II
public class GotoMessageAction
extends org.apache.struts.action.Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// lots of code omitted for clarity, but here the
// business logic should be implemented
ActionForward af = mapping.findForward("succeeded");
return af;
}
}
Procesamiento de petición en
Struts III



De los cuatro parámetros recibidos en
execute(), ActionMapping y
ActionForm son específicos a Struts
El objeto ActionMapping contiene
información de configuración proveniente de
struts-config.xml file.
El objeto ActionForm contiene el bean del
formulario que fue inicializado por el
ActionServlet al procesar la petición
Procesamiento de petición en
Struts IV

En el mapeo de la acción GotoReplyToAction hay
dos posibles forward definidos:



Uno con el nombre "succeeded" y otro
"failed“
Si el método execute() se completa sin errores el
método ActionMapping.findForward() es
llamado, pasando el nombre del siguiente recurso a
llamar.


El método findForward() devuelve un objeto
ActionForward que es pasado al ActionServlet
El objeto ActionForward contiene detalles de a dónde
debería el ActionServlet enviar la petición (contiene el
path del JSP que va a visualizar los resultados)
Manejo de errores en Struts I
Struts define la clase ActionErrors que mantiene una colección de objetos
ActionError.
ActionErrors errors = new ActionErrors();
errors.add (ActionErrors.GLOBAL_ERROR,
new ActionError("error.signing.connect"));
saveErrors(request,errors);
return (new ActionForward (mapping.findForward(“failed")));

El código añade un sólo objeto ActionError a la colección, pero si se llevase a
cabo validación de los campos de un formulario varios errores podrían ser
mostrados.

Luego devuelve una instancia de ActionForward que redirige a "failed".

El ActionServlet guardará en el objeto request el objeto ActionErrors
bajo un nombre bien conocido por Struts:
request.setAttribute( Action.ERROR_KEY, errors);

Este objeto ActionErrors es ahora disponible a cualquier página o acción
consecutiva.

La página JSP “failed” anterior debería tener un área donde se mostrasen los
errores producidos.

El string usado para construir un objeto ActionError no es un mensaje de
error sino que un identificador de un recurso (i18n Struts)

Manejo de errores en Struts II
public class GotoMessageAction extends org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm actionForm,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
ActionErrors errors = new ActionErrors();
try {
// business logic omitted for clarity
} catch(SQLException e) {
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.sqlerror"));
}
if (!errors.empty()) {
saveErrors(request, errors);
ActionForward af = mapping.findForward("failed");
return af;
}
request.setAttribute(Message.MESSAGE_NAME, message);
ActionForward af = mapping.findForward("succeeded");
return af;
}
}
Manejo de Formularios I


La otra acción definida en el fichero de configuración de Struts era:
<action path="/SigninAction"
type="com.develop.ejsp.struts. actions.SigninAction"
name="SigninForm" scope="session"
input="/signin.jsp">
<forward name="succeeded" path="/groups.jsp"/>
<forward name="failed" path="/groups.jsp"/>
</action>
Esta acción está asociada con el formulario llamado SigningForm,
también definido en el fichero de configuración:
<form-beans>
<form-bean name="SigninForm"
type="com.develop.ejsp.struts. beans.SigninForm"/>
</form-beans>
Manejo de Formularios II



Si una acción tiene un formulario asociado a
ella (atributo name en action mapping), el
ActionServlet crea un form bean
Todo form bean hereda de
org.apache.struts.action.ActionFo
rm, que es un JavaBean serializable.
Dos métodos en ActionForm pueden ser
sobreescritos:


validate() y
reset()
Manejo de Formularios III
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if ((username == null) || (username.length() < 1))
errors.add ("username",
new ActionError("error.username.required"));
if ((password == null) || (password.length() < 1))
errors.add("password",
new ActionError("error.password.required"));
return errors;
}

El FormBean es poblado por el ActionServlet con los parámetros de la
petición de entrada llamando a los métodos setXXX() correspondientes.

Una vez poblado, el form bean es validado:


Si el objeto ActionErrors devuelto es null o vacío significa que la validación tuvo
éxito y una instancia del form bean creado, en este caso SigningForm, es pasado al
objeto SigningAction
Si la validación falla, la petición será re-direccionada por Struts a la página que
contenía el formulario inicialmente el formulario, dada por el atributo input del
elemento action en struts-config.xml
Manejo de Formularios IV
public class SigninForm extends ActionForm {
String userName = null;
String password = null;
public SigninForm() {}
public void setUsername(String userName) {
this.userName = userName;
}
public String getUserName() {
return this.userName;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return this.password;
}
...
Manejo de Formularios V
// accessors and mutator omitted for clarity
public ActionErrors validate(ActionMapping actionMapping,
HttpServletRequest
httpServletRequest) {
ActionErrors errors = new ActionErrors();
if ((password == null) || (password.length() < 1))
errors.add("password", new
ActionError("error.password.required"));
if ((userName == null) || (userName.length() < 1))
errors.add("username", new
ActionError("error.username.required"));
return errors;
}
public void reset(ActionMapping actionMapping,
HttpServletRequest httpServletRequest) {
username = "";
password="";
}
}
Manejo de Formularios VI
public class SigninAction
extends org.apache.struts.action.Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
}
}
try {
String username = ((SigninForm) form). getUserName();
String password = ((SigninForm) form). getPassword();
// etc.
}
DataSources en Struts
try {
DataSource ds = servlet.findDataSource(“usuarios”);
message = new Message();
message.getMessage(ds,
request.getParameter( Message.MESSAGE_ID)),
request.getParameter( GROUP_ID_NAME))
}

El código arriba muestra otra característica de Struts, la habilidad de configurar
y usar referencias a javax.jdbc.DataSources

El extracto de struts-config.xml anteriormente mostrado tiene una sección
<data-sources> para configurar las data sources de la aplicación.

Struts provee las clases GenericDataSource y GenericConnection que
son wrappers sobre los objetos JDBC Connections y DataSources definidos
en el fichero de configuración.
Struts Tag Libraries


Documentadas en http://www.onjava.com/lpt/a/4034
La framework Struts proporciona un conjunto de 6
librerías de etiquetas, que asisten en la tarea de la
creación de la vista de MVC para evitar incluir código
Java en los JSPs:







Bean Tags
HTML Tags
Logic Tags
Nested Tags
Template Tags
Tiles Tags
Las funcionalidad de las etiquetas definidas en las
librerías Bean y Logic es también provista por las
librerías core y fmt de JSTL

Se recomienda el uso de las librerías en JSTL
HTML Tags

Estas etiquetas son principalmente usadas para:



Crear formularios de entrada de datos y
Otras utilidades para visualizar interfaces basados en HTML.
Algunas de las acciones más útiles son:







base  genera un elemento HTML <base>
errors  condicionalmente visualiza un conjunto
acumulado de mensajes de error
form  define un formulario de entrada
text  visualiza un campo de entrada de tipo texto
messages  condicionalmente visualiza un conjunto de
mensajes acumulados
submit  visualiza un botón de entrega
Etc.
Logic Tags

Usadas para:




Iterar sobre colecciones
Generación condicional de salida, y
Flujo de aplicación
Algunas de las acciones más útiles son:





present  genera el contenido de marcado dentro de esta
etiqueta si el valor indicado es encontrado en esta petición
notPresent  lo opuesto a present
iterate  repite el contenido anidado dentro de esta
etiqueta al iterar sobre una colección
forward  transfiere control a la página especificada por
la entrada ActionForward.
Etc.
Tiles Tags (Framework)


La librería de etiquetas Tiles es un super-conjunto de la librería
Templates
Intenta evitar la duplicación de contenido de lenguaje de
marcado dentro de una aplicación web con respecto al look-andfeel de un portal:


Tiles reduce el tamaño de código redundante en una aplicación
web y separa el contenido de la visualización del mismo de
manera más eficiente


Un mecanismo normalmente utilizado es usar la directiva
jsp:include para añadir cabeceras/menús y pies de páginas a
un portal web
Tiles define Layout Managers para JSPs
Su objetivo principal es evitar en los JSPs contenido de marcado
que corresponda con el layout del portal  factoriza este
marcado, de tal manera que la modificación del layout sea
sencilla y eficiente
JSP Templates

Un template es una página JSP que usa
una librería de etiquetas personalizadas
para describir la disposición (layout) de
los componentes de la página


Define cómo aparecerán las páginas JSP de
una aplicación, sin especificar el contenido
Esta definición es utilizada por todos los
JSPs sin necesidad de mezclar layout con
contenido
Ejemplo Tiles: index.jsp I
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html>
<head>
<title><bean:message key="global.title"/></title>
<html:base/>
<script language=javascript src="include/scripts.js"></script>
<link rel="stylesheet" href="stylesheets/format_win_nav_main.css"
type="text/css">
</head>
<body topmargin="0" leftmargin="0" bgcolor="#FFFFFF">
<!-- Header Page Information -->
<%@ include file="include/head.inc"%>
<!-- Nav Bar -->
<%@ include file="include/menubar.inc"%>
Ejemplo Tiles: index.jsp II
<%@ include file="include/mainoffer.inc"%>
<!-- Featured Items Header Row -->
<table width="645" cellpadding="0" cellspacing="0" border="0">
<tr>
<td width="21"><html:img height="1" alt="" page="/images/spacer.gif" width="1"
border="0"/></td>
<td width="534"><html:img page="/images/week_picks.gif"
altKey="label.featuredproducts"/></td>
<td width="1" bgcolor="#9E9EFF"><html:img height="1" alt="" page="/images/spacer.gif"
width="1" border="0"/></td>
<td width="1" bgcolor="#9E9EFF"><html:img height="1" alt=""
page="/images/spacer.gif" width="1" border="0"/></td>
<td width="90" bgcolor="#9E9EFF" align="right"><html:img height="1" alt=""
page="/images/spacer.gif" width="90" border="0"/></td>
</tr>
<tr>
<td><html:img height="1" alt="" page="/images/spacer.gif" width="21"
border="0"/></td>
<td colspan="4" bgcolor="#9E9EFF"><html:img height="1" alt=""
page="/images/spacer.gif" width="1" border="0"/></td>
</tr>
</table>
<html:img height="10" alt="" page="/images/spacer.gif" width="1" border="0"/><br>
<!-- THIS WEEK'S FEATURES -->
<%@ include file="include/featureditems.inc"%>
<%@ include file="include/copyright.inc"%>
</body>
</html:html>
Ejemplo Tiles: storefront
DefaultLayout.jsp
<%@ taglib uri=“/WEB-INF/struts-html.tld” prefix=“html” %>
<%@ taglib uri=“/WEB-INF/struts-bean.tld” prefix=“bean” %>
<%@ taglib uri=“/WEB-INF/tiles.tld” prefix=“tiles” %>
<html:html>
<head>
<title><bean:message key=“global.title”/></title>
<html:base/>
</head>
<body topmargin=“0” leftmargin=“0” bgcolor=“#FFFFFF”>
<tiles:insert attribute=“header”/>
<tiles:insert attribute=“menubar”/>
<tiles:insert attribute=“body-content”/>
<tiles:insert attribute=“copyright”/>
</body>
</html:html>
Ejemplo Tiles: storefrontdefs.jsp
<%@ taglib uri=“/WEB-INF/tiles.tld” prefix=“tiles” %>
<tiles:definition
id=“storefront.default”
page=“/layouts/storefrontDefaultLayout.jsp”
scope=“request”>
<tiles:put name=“header”
value=“/common/header.jsp”/>
<tiles:put name=“menubar”
value=“/common/menubar.jsp”/>
<tiles:put name=“copyright”
value=“/common/copyright.jsp”/>
</tiles:definition>
Ejemplo Tiles: index.jsp
<%@ taglib uri=“/WEB-INF/tiles.tld” prefix=“tiles” %>
<%@ include file=“../common/storefront-defs.jsp” %>
<tiles:insert beanName=“storefront.default”
beanScope=“request”>
<tiles:put name=“body-content”
value=“index-body.jsp”/>
</tile:insert>


Para más información sobre Tiles Framework ir a:
http://www.lifl.fr/~dumoulin/tiles/index.html
Para instalar Tiles en Struts es necesario añadir una sección plug-in
en struts-config.xml para la clase:
org.apache.struts.tiles.TilesPlugin
Mi primera aplicación con
Apache Struts

Aplicación para llevar a cabo login


Una vez que el usuario ha hecho login las páginas
cambian para indicar tal circunstancia
Consiste de dos pantallas:


Página Welcome que saluda al usario y ofrece enlaces a
la aplicación
Página Logon que permite al usuario introducir
username y password

Esta página lleva a cabo la validación que los datos
introducidos son correctos
Welcome.html
<HTML>
<HEAD>
<TITLE>Welcome World!!</TITLE>
<base
href="http://localhost:8080/logon/pages/Welcome.jsp">
</HEAD>
<BODY>
<H3>Welcome World!</H3>
<UL>
<LI><a href="/logon/logon.do">Sign in</a></LI>
</UL>
<IMG src='struts-power.gif' alt='Powered by Struts'>
</BODY>
</HTML>
Welcome.jsp I
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-logic" prefix="logic" %>
<HTML>
<HEAD>
<TITLE>Welcome World!!</TITLE>
<html:base/>
</HEAD>
<BODY>
<logic:present name="user">
<H3>Welcome <bean:write name="user" property="username"/>!</H3>
</logic:present>
<logic:notPresent scope="session" name="user">
<H3>Welcome World!</H3>
</logic:notPresent>
<html:errors/>
<UL>
<LI><html:link forward="logon">Sign in</html:link></LI>
<logic:present name="user">
<LI><html:link forward="logoff">Sign out</html:link></LI>
</logic:present>
</UL>
<IMG src='struts-power.gif' alt='Powered by Struts'>
</BODY>
</HTML>
Welcome.jsp II
<html:base/> garantiza que referencias a imágenes o otros recursos
son relativas a la localización del JSP
<logic:present name="user">
<H3>Welcome <bean:write
name="user"
property="username"/>!</H3>
</logic:present>

Esta etiqueta personalizada asegura que el usuario solamente es
saludado si ha efectuado login

<logic:notPresent> tiene el comportamiento opuesto
<LI><html:link forward="logon">Sign
in</html:link></LI>

Struts reescribe automáticamente los enlaces para mantener la sesión
del usuario. También permite dar a los enlaces un nombre lógico y
luego guardar los enlaces reales en un fichero de configuración.

Logon.html
<HTML>
<HEAD>
<TITLE>Sign in, Please!</TITLE>
</HEAD>
<BODY>
<form name="logonForm" method="POST" action="/logon/LogonSubmit.do">
<TABLE border="0" width="100%">
<TR>
<TH align="right">Username:</TH>
<TD align="left"><input type="text" name="username" value=""></TD>
</TR>
<TR>
<TH align="right">Password:</TH>
<TD align="left"><input type="password" name="password" value=""></TD>
</TR>
<TR>
<TD align="right"><input type="submit" name="submit" value="Submit"></TD>
<TD align="left"><input type="reset" name="reset" value="Reset"></TD>
</TR>
</TABLE>
</form>
<script language="JavaScript" type="text/javascript">
<!-document.forms["logonForm"].elements["username"].focus()
// -->
</script>
</BODY>
Logon.jsp I
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<HTML>
<HEAD>
<TITLE>Sign in, Please!</TITLE>
</HEAD>
<BODY>
<html:errors/>
<html:form action="/LogonSubmit" focus="username">
<TABLE border="0" width="100%">
<TR>
<TH align="right">Username:</TH>
<TD align="left"><html:text property="username"/></TD>
</TR>
<TR>
<TH align="right">Password:</TH>
<TD align="left"><html:password property="password"/></TD>
</TR>
<TR>
<TD align="right"><html:submit/></TD>
<TD align="left"><html:reset/></TD>
</TR>
</TABLE>
</html:form>
</BODY>
</HTML>
Logon.jsp II
<%@ taglib uri="/tags/struts-html"
prefix="html"%>

La librería de etiquetas html definida por Struts es disponible a
la página

<html:errors/> garantiza si ha habido algún error durante
el login, que estos errores sean visualizados
<html:form action="/LogonSubmit"
focus="username">

Produce un formulario HTML para la entrada de datos. También
genera JavaScript para mover el cursor al campo username del
formulario

La propiedad action hace referencia a un componente
ActionMapping en el fichero de configuración de Struts  dice al
formulario que JavaBean (derivado de ActionForm) debe usar
para poblar los controles de HTML.
Logon.jsp III
<html:text property="username"/>
 Crea un control de entrada HTML para un campo de
texto. Asignará a este campo la propiedad username
del JavaBean de ayuda antes mencionado.
 <html:password> crea un campo de entrada
 <html:submit> y <html:reset> generan botones
HTML Submit y Reset. Dos objetos serán invocados
cuando se usen estos botones:


ActionForm
Action
Configuración de la acción
logon I

Configuración para la pantalla de logon:


JSP hace referencia al /LogonSubmit
ActionMapping
ActionMapping hace referencia a los
objetos:


app.LogonForm  describe propiedades
usadas por el formulario logon
app.LogonAction  lleva a cabo el
procesamiento del formulario
Configuración de la acción
logon II
<html:form action="/LogonSubmit" focus="username">

La configuración asociada al atributo acción en Struts sería:
<action path="/LogonSubmit"
type="app.LogonAction"
name="logonForm"
scope="request"
validate="true"
input="/pages/Logon.jsp"/>

path  identicador único para el mapping

type  acción a invocar cuando el formulario es entregado

name  el helper JavaBean (ActionForm) a usarse con el formulario HTML

scope  indica en qué contexto debe guardarse el ActionForm

validate  indica si es necesario invocar al método validate del
ActionForm antes de invocar al objeto Action

input  indica a donde ir si validate devuelve falso
<form-bean name="logonForm"
type="app.LogonForm"/>

Este extracto del fichero de configuración relaciona el nombre lógico
logonForm con la clase app.LogonForm
LogonForm: un ejemplo de un
ActionForm
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if ((username == null) || (username.length() < 1))
errors.add ("username",
new ActionError("error.username.required"));
if ((password == null) || (password.length() < 1))
errors.add("password",
new ActionError("error.password.required"));
return errors;
}

Si validate no devuelve null, entonces el ActionController servlet guardará
el objeto ActionErrors devuelto en el contexto request, bajo una clave
conocida por la etiqueta html:errors

Los tokens error.username.required y error.password.required
son claves que son utilizadas para mirar los strings correspondientes en el
fichero de recursos de Struts

Recordar que cada Locale contiene su propio fichero de recursos lo que hace que los
mensajes sean fácilmente localizables.
LogonAction: un ejemplo de
un LogonAction I
package app;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
public final class LogonAction extends Action {
// Validate credentials with business tier
public boolean isUserLogon (String username,
String password) throws UserDirectoryException {
return (UserDirectory.getInstance().isValidPassword(username,password));
} // end isUserLogon
LogonAction: un ejemplo de
un LogonAction II
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// Obtain username and password from web tier
String username = ((LogonForm) form).getUsername();
String password = ((LogonForm) form).getPassword();
// Validate credentials
boolean validated = false;
try {
validated = isUserLogon(username,password);
} catch (UserDirectoryException ude) {
// couldn't connect to user directory
ActionErrors errors = new ActionErrors();
errors.add (ActionErrors.GLOBAL_ERROR, new ActionError("error.logon.connect"));
saveErrors(request,errors);
// return to input page
return (new ActionForward (mapping.getInput()));
}
// Save our logged-in user in the session, because we use it again later.
HttpSession session = request.getSession();
session.setAttribute(Constants.USER_KEY, form);
// Log this event, if appropriate
if (servlet.getDebug() >= Constants.DEBUG) {
StringBuffer message = new StringBuffer("LogonAction: User '");
message.append(username);
message.append("' logged on in session ");
message.append(session.getId());
servlet.log(message.toString);
}
// Return success
return (mapping.findForward (Constants.WELCOME));
} // end perform
} // end LogonAction
LogonAction: un ejemplo de
un LogonAction III
// Validate credentials
boolean validated = false;
try {
validated = isUserLogon(username,password);
} catch (UserDirectoryException ude) {
// couldn't connect to user directory
ActionErrors errors = new ActionErrors();
errors.add (ActionErrors.GLOBAL_ERROR,
new ActionError("error.logon.connect"));
saveErrors(request,errors);
// return to input page
return (new ActionForward(mapping.getInput()));
}

Si un error es encontrado mientras se lleva a cabo la validación de la entrada del usuario y
una excepción es lanzada, entonces el error es transformado en un ActionError y el
control es devuelto a la página de entrada. Lo mismo se lleva a cabo si se puede contactar
al servicio de directorio pero el login del usuario no es correcto
return (mapping.findForward (Constants.WELCOME));

Un objeto de tipo ActionForward será devuelto al ActionServlet si todo va bien. En este caso
se envía control al forward success declarado en el fichero de configuración como:
<forward name=“success”
path=“/pages/Welcome.jsp”/>
Modificaciones a realizar en
guessing
1.
2.
3.
4.
5.
6.
Modificar action /guess en struts-config.xml, haciendo que esa
acción esté asociada a la clase
es.deusto.guessing.action.GuessingAction y al formulario
es.deusto.guessing.form.GuessingForm.
Asegurarse que existe correspondencia entre clase guessing.jsp y
GuessingForm
Asegurarse que un usuario después de haber hecho login pueda
jugar una partida, el usuario podrá realizar intentos infinitamente,
pero esos intentos hay que contabilizarlos y visualizarlos cada vez
que el usuario falla o adivina el número
El número a adivinar es asociado a la sesión del usuario y generado
la primera vez que la acción execute se ejecuta para un usuario
Idealmente crear una clase llamada Game que contenga el número
a adivinar y el número de intentos fallidos
Modificar la aplicación de manera que nuevos usuarios puedan ser
definidos y los datos de login de esos usuarios se salven en un
fichero .properties.
Más Ejemplos

Para más ejemplos del uso de Struts
visitar:

http://struts.sourceforge.net/
Descargar

Apache Struts