63
4.4 Tutorial de Jakarta Struts

4.4 Tutorial de Jakarta Strutsfbellas/teaching/is-2001-2002/Tema4Apart... · El patrón Front Controller en Struts (1) javax.servlet.http.HttpServlet org.apache.struts.action.Action

Embed Size (px)

Citation preview

4.4 Tutorial de Jakarta Struts

¿ Qué es Struts ?

n Framework OpenSource para implementar aplicaciones web con servlets y JSP según el patrón arquitectónico Model-View-Controller

n Subproyecto de Jakartan Autor principal: Craig R. McClanahan

n Funciona sobre cualquier servidor de aplicaciones web que implemente las APIs de servlets y JSP

n Julio 2001: versión 1.0n Ha ganado gran relevancia en el mundo de las

aplicaciones web Javan Paquetizado en un fichero .jar

¿ Qué proporciona Struts ?

n Un servlet Front Controller y clases relacionadasn Un gran número de acciones JSP

n View Helpersn La mayor parte de las que se necesitan en una situación real

n Un pool genérico de conexiones a una BD relacionaln Implementa javax.sql.DataSource

El patrón Front Controller en Struts (1)

javax.servlet.http.HttpServlet

org.apache.struts.action.Action

+ perform

ActionN

0..n

Action1...

org.apache.struts.action.ActionServlet

# doGet# doPost

org.apache.struts.action.ActionForm

+ reset+ validate

<<instantiate>>

ActionFormNActionForm1... <<use>>

<<use>>

El patrón Front Controller en Struts (2)

n ActionServletn Servlet Front Controllern En web.xml se especifica que todas las URLs que impliquen

procesamiento (por GET o POST) vayan a este servletn Ej.: las URLs que termine en .do

n Clases ActionFormn Si el programador lo desea, puede acceder a los parámetros de la

request a través de un JavaBean que extiende ActionFormn Especialmente útil en formularios

n Clase Action => método performn Accede a los parámetros de la request, directamente o vía el

ActionForm correspondienten Realiza la operación invocando un método de un Session

Facade del modelo o una fachada del controladorn Deja el resultado devuelto por el método en la request o en la

sesiónn Devuelve un objeto ActionForward, que representa la URL que

hay que visualizar a continuación (sendRedirect o forward)

El patrón Front Controller en Struts (3)

n Fichero de configuraciónn Clases ActionForm que usa nuestra aplicación

n Nombre lógico (ej.: loginForm)

n Nombre completo de la clase (ej.: es.udc.fbellas.j2ee.strutstutorial.portal3.http.view.actionforms.LoginForm)

n URLs que implican procesamienton URL de tipo path relativo a contexto (ej.: /Login)

n No llevan el .do final

n Nombre completo de la clase Action (ej.: es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction)

n Nombre lógico de la clase ActionForm asociada

El patrón Front Controller en Struts (y 4)

n Fichero de configuración (cont)n Definiciones de nombres lógicos de URLs

n Nombre que usan las acciones cuando devuelven un ActionForward (ej.: ShowMainPage)

n sendRedirect o forwardn URL a invocar (ej.: /MainPage.jsp)

n Cuando el servlet ActionServlet arranca (init), lee el fichero de configuración

n Crea una única instancia de cada clase Actionn No se crea una instancia de una clase Action por cada

petición que se reciben Tienen que ser thread-safen Misma situación que cuando se trabaja con servlets

Acciones JSP

n Beann Imprimir el valor de las propiedades de JavaBeans de

manera seguran Soporte para internacionalización de mensajes

n HTMLn Generación de HTML básico

n Campos de entrada en formulariosn Enlaces (con URL rewriting)

n Logicn Si mayor que, si menor que, etc.n Iteración sobre colecciones de objetos

n Templaten Caso particular del patrón Composite Viewn Lo veremos con MiniBank y MiniPortal

Arquitectura MVC con Struts

n Modelon Clases independientes de la vista y el controlador

n Controladorn Quizás se necesite extender el servlet ActionServletn Conjunto de clases Actionn Interactúan con el modelo y seleccionan la siguiente vista

(dejándole los datos en uno de los cuatro posibles ámbitos, normalmente request o session)

n Vistan Conjunto de clases ActionFormn Conjunto de páginas JSP

n No contienen código Javan Sólo visualizan datosn Usan acciones JSP (las de Struts, las estándares y quizás

algunas desarrolladas a medida) para recuperar los valores a mostrar y formatearlos

Demo Portal-3 (1)

Lanzar el navegador

Acceder a Portal-3 main page

Demo Portal-3 (2)

Clic Login

Demo Portal-3 (y 3)

Portal-3 main page(Welcome to Portal-3)

Clic en LogoutTerminar y lanzar el navegador dos días más tarde

Acceder a Portal-3 main page

Estructura de paqueteses.udc.fbellas.j2ee.util.struts.action

es.udc.fbellas.j2ee.strutstutorial.portal3

http

controller

actions

model

userfacade

delegate

exceptions

view

actionforms

messages

tar tvf StrutsTutorial.war (1)

MainPage.jsp

InternalError.jsp

Login.jsp

Index.jspWEB-INF/Struts/struts-bean.tld

WEB-INF/Struts/struts-html.tld

WEB-INF/Struts/struts-logic.tld

WEB-INF/Struts/struts-config.xml

WEB-INF/lib/struts.jar

WEB-INF/lib/crimson.jarWEB-INF/lib/jaxp.jar

WEB-INF/lib/StandardUtil.jar

WEB-INF/lib/WebUtil.jar

tar tvf StrutsTutorial.war (y 2)

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/model/

userfacade/delegate/UserFacadeDelegate.class

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/model/

userfacade/exceptions/IncorrectPasswordException.classWEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/

controller/actions/LoginManager.class

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/

controller/actions/LogoutAction.class

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/

controller/actions/LoginAction.classWEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/

controller/actions/MainPageAction.class

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/view/

actionforms/LoginForm.class

WEB-INF/classes/es/udc/fbellas/j2ee/strutstutorial/portal3/http/view/

messages/Messages.propertiesWEB-INF/web.xml

Comentarios

n WEB-INF/Strutsn Ficheros *.tld: descriptores de las librerías de las acciones

proporcionadas por Strutsn struts-config.xml: configuración de Struts para la

aplicación del tutorial

n WEB-INF/libn struts.jar: ficheros .class de Strutsn crimson.jar y jaxp.jar: Struts usa JAXP para parsear

el fichero struts-config.xmln StandarUtil.jar y WebUtil.jar: subsistema Util de

J2EE-Examplesn WEB-INF/classes/es/.../Messages.properties

n Internacionalización de mensajes

WEB-INF/web.xml (1)<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>

<distributable/>

<!-- ========================= Servlets ========================= -->

<!-- == Standard Action Servlet Configuration (with debugging) == -->

<servlet>

<servlet-name>action</servlet-name>

<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

WEB-INF/web.xml (2)<init-param>

<param-name>application</param-name>

<param-value>es.udc.fbellas.j2ee.strutstutorial.portal3.http.

view.messages.Messages</param-value>

</init-param><init-param>

<param-name>config</param-name>

<param-value>/WEB-INF/Struts/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>detail</param-name>

<param-value>2</param-value>

</init-param><load-on-startup>2</load-on-startup>

</servlet>

WEB-INF/web.xml (3)<!-- ================== Servlet mapping ========================== -->

<servlet-mapping>

<servlet-name>action</servlet-name>

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

<!-- ========================= Session ========================== -->

<session-config>

<session-timeout>30</session-timeout></session-config>

<!-- ======================= Welcome page ======================= -->

<welcome-file-list>

<welcome-file>Index.jsp</welcome-file></welcome-file-list>

WEB-INF/web.xml (y 4)<!-- ================= Struts Tag Library Descriptors ============ -->

<taglib>

<taglib-uri>/struts-bean.tld</taglib-uri>

<taglib-location>/WEB-INF/Struts/struts-bean.tld</taglib-location></taglib>

<taglib>

<taglib-uri>/struts-html.tld</taglib-uri>

<taglib-location>/WEB-INF/Struts/struts-html.tld</taglib-location>

</taglib>

<taglib>

<taglib-uri>/struts-logic.tld</taglib-uri>

<taglib-location>/WEB-INF/Struts/struts-logic.tld</taglib-location>

</taglib>

</web-app>

Comentarios (1)

n Servlet org.apache.struts.actions.ActionServletn Aparecen dos tags que no hemos usado hasta ahora

n init-param

n Permite definir un parámetro de configuración y su valorn Accesible vía Servlet.getServletConfig().getInitParameter()

n load-on-startup

n Indica que el servlet se debería cargar cuando el servidor arranque la aplicación web

n El valor (opcional) indica el orden relativo de carga con respecto a otros servlets (cuanto menor sea el valor, antes se carga)

n Parámetros de inicializaciónn Véase JavaDoc de org.apache.struts.actions.ActionServletn application

n Nombre del fichero de mensajes (sin sufijo .properties)n Debe estar debajo de WEB-INF/classes y usar un nombre

consistente con su ubicación (como si de una clase se tratase)

Comentarios (2)

n Servlet org.apache.struts.actions.ActionServletn Parámetros de inicialización (cont)

n config

n Path de tipo relativo a contexto del fichero de configuración de Struts

n debug

n Nivel de detalle en los mensajes de depuración que escribe Strutscon el método ServletContext.log

n detail

n Nivel de detalle en los mensajes de depuración que escribe Strutsen System.out

Comentarios (y 3)

n Librerías de tags proporcionadas por Strutsn Aparece un tag que no hemos usado hasta ahora, taglib,

que contiene los elementosn taglib-uri: URI a usar en la directiva taglib de JSP (para

importar la librería)n taglib-location: path relativo a contexto del fichero .tld

(Tag Library Descriptor) de la librería de tags

WEB-INF/Struts/struts-config.xml (1)

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config

PUBLIC "-//Apache Software Foundation//DTD Struts Configuration

1.0//EN""http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">

<struts-config>

<!-- ============ Form Bean Definitions =========================== -->

<form-beans>

<form-bean name="loginForm"

type="es.udc.fbellas.j2ee.strutstutorial.portal3.http.view.actionforms.

LoginForm"/>

</form-beans>

WEB-INF/Struts/struts-config.xml (2)<!-- ============ Global Forward Definitions ====================== -->

<global-forwards><forward name="MainPage" path="/MainPage.do" redirect="true"/><forward name="InternalError" path="/InternalError.jsp" redirect="true"/>

</global-forwards>

<!-- ============ Action Mapping Definitions ====================== -->

<action-mappings>

<action path="/MainPage"type="es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.MainPageAction">

<forward name="ShowMainPage" path="/MainPage.jsp"/></action>

<action path="/Login"type="es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction"

name="loginForm"scope="request"input="/Login.jsp"validate="true"/>

WEB-INF/Struts/struts-config.xml (y 3)<action path="/Logout"

type="es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.

actions.LogoutAction"/>

<!-- =================================================================The standard administrative actions available with Struts. These

must be either omitted or protected by security in a real

application deployment. ================================================================ -->

<action path="/admin/addFormBean"

type="org.apache.struts.actions.AddFormBeanAction"/>

...

<action path="/admin/removeMapping"

type="org.apache.struts.actions.RemoveMappingAction"/>

</action-mappings>

</struts-config>

Comentarios (1)

n Definiciones de nombres lógicos de URLsn Se usan en la implementación de las acciones para devolver

un ActionForward y en algunas acciones JSPn Se especifican con forward

n Atributos documentados en JavaDoc de org.apache.struts.action.ActionForward

n name: Nombre lógicon path: path relativo a contexto de la URL a la que se invocarán redirect: true (sendRedirect) o false (forward)

n false por defecto

n Pueden ser globales (global-forwards) o particulares a una acción (action)

Comentarios (y 2)

n actionn Atributos documentados en JavaDoc de org.apache.struts.action.ActionMapping

n type: nombre completo de la clase Actionn path: URL (path relativo a contexto) que provocará la

invocación de la acciónn ¡ Se especifican sin el sufijo .do !

n name: nombre del ActionForm (definido por form-bean) que captura los parámetros de la invocación

n scope: ámbito (request o session) del ActionFormn En general, request

n input: path relativo a contexto del formulario de entradan validate: true si el Front Controller tiene que llamar al

método validate del ActionFormn En general, true

WEB-INF/classes/es/.../Messages.properties (1)

Buttons.login=Login

ErrorMessages.loginName.notFound=Login name not found

ErrorMessages.mandatoryField=Mandatory fieldErrorMessages.password.incorrect=Incorrect password

ErrorMessages.retry=Please, check if the operation has been performed, \

and retry if necessary

errors.footer=</b></font>

errors.header=<font color="red"><b>

InternalError.title=Internal error

WEB-INF/classes/es/.../Messages.properties (y 2)

Login.loginName=Login name

Login.password=Password

Login.rememberMyPassword=Remember my password (cookies must be enabled)

Login.title=Portal-3 login form

MainPage.hello=Hello

MainPage.login=Login

MainPage.logout=Logout

MainPage.title=Portal-3 main page

MainPage.welcome=Welcome to Portal-3

Comentarios (1)

n Asocia parares <identificadorMensaje, mensaje>n Convenios de nombrado para los identificadores de mensajesn Ordenados alfabéticamenten errors.footer y errors.header son dos identificadores

especiales que entiende la acción html:errors de Strutsn Messages.properties

n Mensajes en el lenguaje por defecto del servidorn Messages_xx.properties

n Mensajes en el lenguaje cuyo código ISO es xxn Códigos ISO en

http://www.ics.uci.edu/pub/ietf/http/related/iso639.txtn en: Inglésn es: Españoln gl: Gallego

n Etc.

Comentarios (2)

n Messages.properties sólo resuelve un aspecto particular de la internacionalización de aplicaciones: impresión de mensajes en distintos idiomasn En una aplicación más compleja puede ser necesario tener

trozos de páginas en distintos idiomas (con gran cantidad de texto estático) y seleccionarlas o incluirlas dinámicamente desde otras en función del idioma

n Otros aspectos en internacionalizaciónn Formatear y tratar fechas, horas, números, cantidades

monetariasn Paquetes java.text y java.util

n Puede requerir tablas para almacenar contenido en distintos idiomasn Ej.: un servicio de noticias

es.udc.fbellas.j2ee.strutstutorial.portal3.model.userfacade.delegate

n Simula la facha del modelo que proporciona las operaciones relativas a la interacción del usuario con el portal

UserFacadeDelegate

+ UserFacadeDelegate()

+ login(loginName : String, password : String, passwordIsEncrypted : boolean) : void

es.udc.fbellas.j2ee.util.struts.action (1)

Act ion

(from action)

DefaultAction

+ perform(m : ActionMapping, f : ActionForm, rq : HttpServletRequest, rp : HttpServletResponse) : ActionForward# doPerform(m : ActionMapping, f : ActionForm, rq : HttpServletRequest, rp : HttpServletResponse) : ActionForward# doOnInternalError(m : ActionMapping, f : ActionForm, rq : HttpServletRequest, rp : HttpServletResponse) : ActionForward

PropertyValidator

es.udc.fbellas.j2ee.util.struts.action (y 2)

n DefaultActionn Problema

n En general, las clases Action invocarán una operación sobre un Business Delegate del modelo o una fachada del controlador, que puede lanzar InternalErrorException

n Es necesario (1) capturarla, (2) imprimirla en un log (para depuración) y (3) ir a una página que indique error interno

n Las clases Action derivarán de DefaultActionn Implementa perform (Template Method) en términos de doPerform y doOnInternalError

n Las clases hijas implementan doPerform, que tiene la misma signatura que perform, pero puede lanzar adicionalmente InternalErrorException

n PropertyValidatorn Clase utilidad para validar campos de entrada comunes

(double, long, String, etc.)

es.udc.fbellas.j2ee.util.struts.action.DefaultAction (1)

package es.udc.fbellas.j2ee.util.struts.action;

import java.io.IOException;

import javax.servlet.ServletContext;

import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;

import javax.servlet.ServletException;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;import org.apache.struts.action.ActionError;

import org.apache.struts.action.ActionErrors;

import es.udc.fbellas.j2ee.util.exceptions.InternalErrorException;

es.udc.fbellas.j2ee.util.struts.action.DefaultAction (2)

public abstract class DefaultAction extends Action {

public ActionForward perform(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException {

try {

return doPerform(mapping, form, request, response);

} catch (InternalErrorException e) {

return doOnInternalErrorException(mapping, form, request,response, e);

}

}

protected abstract ActionForward doPerform(ActionMapping mapping,ActionForm form, HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException, InternalErrorException;

es.udc.fbellas.j2ee.util.struts.action.DefaultAction (y 3)

protected ActionForward doOnInternalErrorException(

ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response,

InternalErrorException internalErrorException)

throws IOException, ServletException {

/*

* Log error, even with debug level <= 0, because it is a

* severe error.

*/

ServletContext servletContext = servlet.getServletConfig().getServletContext();

servletContext.log(internalErrorException.getMessage(),

internalErrorException);

/* Redirect to input page. */

return mapping.findForward("InternalError");

}

}

es.udc.fbellas.j2ee.util.struts.action.PropertyValidator (1)

public final class PropertyValidator {

private final static String INCORRECT_VALUE =

"ErrorMessages.incorrectValue";private final static String MANDATORY_FIELD =

"ErrorMessages.mandatoryField";

public final static long validateLong(ActionErrors errors,

String propertyName, String propertyValue, boolean mandatory,

long lowerValidLimit, long upperValidLimit) {

long propertyValueAsLong = 0;

if (validateMandatory(errors, propertyName, propertyValue,

mandatory)) {

boolean propertyValueIsCorrect = true;

es.udc.fbellas.j2ee.util.struts.action.PropertyValidator (2)

try {

propertyValueAsLong =

new Long(propertyValue).longValue();

if ( (propertyValueAsLong < lowerValidLimit) ||

(propertyValueAsLong > upperValidLimit) ) {propertyValueIsCorrect = false;

}

} catch (NumberFormatException e) {

propertyValueIsCorrect = false;

}

if (!propertyValueIsCorrect) {

errors.add(propertyName,

new ActionError(INCORRECT_VALUE));

}

}

return propertyValueAsLong;

}

es.udc.fbellas.j2ee.util.struts.action.PropertyValidator (y 3)

public final static boolean validateMandatory(ActionErrors errors,

String propertyName, String propertyValue) {

if ((propertyValue == null) || (propertyValue.length() == 0)) {

errors.add(propertyName, new ActionError(MANDATORY_FIELD));return false;

} else {

return true;

}

}

// Resto de métodos validateXXX => Análogos ...

Comentarios

n org.apache.struts.action.ActionMappingn Permite acceder a los valores configurados en struts-config.xml para la acción en ejecución (inclusive a los forwards globales)

n org.apache.struts.action.ActionErrorsn Juega el papel del mapa de errores que hemos empleado en

apartado anterioresn El mensaje de error es un org.apache.struts.action.ActionError, que dispone de un constructor que permite especificar el identificador del mensaje de error (en Messages.properties)

n org.apache.struts.action.ActionForwardn Representa la siguiente URL a la que hay que irn El Front Controller lo invocará después de llamar al método perform sobre la acción

es.udc.fbellas.j2ee.strutstutorial.portal3.http.view.actionforms.LoginForm (1)

public class LoginForm extends ActionForm {

private String loginName;

private String password;private boolean rememberMyPassword;

public LoginForm() {

reset();

}

public String getLoginName() {

return loginName;

}

public void setLoginName(String loginName) {

this.loginName = loginName.trim();}

es.udc.fbellas.j2ee.strutstutorial.portal3.http.view.actionforms.LoginForm (2)

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public boolean getRememberMyPassword() {

return rememberMyPassword;}

public void setRememberMyPassword(boolean rememberMyPassword) {

this.rememberMyPassword = rememberMyPassword;

}

es.udc.fbellas.j2ee.strutstutorial.portal3.http.view.actionforms.LoginForm (y 3)

public void reset(ActionMapping mapping, HttpServletRequest request) {reset();

}

public ActionErrors validate(ActionMapping mapping,HttpServletRequest request) {

ActionErrors errors = new ActionErrors();

PropertyValidator.validateMandatory(errors, "loginName",loginName);PropertyValidator.validateMandatory(errors, "password", password);

return errors;

}

private void reset() {loginName = null;password = null;rememberMyPassword = false;

}

}

Comentarios

n LoginFormn Juega el mismo papel que la clase vista en el apartado

anteriorn Hereda de org.apache.struts.action.ActionForm

n Generalmente interesa redefinir reset y validaten reset

n El Front Controller lo llama antes de dar valor a las propiedadesn validate

n Permite validar las propiedades después de que el Front Controller les haya dado valores

n Sólo se invoca si se ha especificado validate="true" para la acción correspondiente en struts-config.xml

n Si devuelve un ActionErrors no vacío, el Front Controller (1) no invocará el método perform sobre la acción correspondiente, (2) insertará un atributo con los errores en larequest, y (3) hará un forward a la URL que especifica el atributo input del action correspodiente en struts-config.xml (formulario de entrada)

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions

DefaultAction

(from action)

LoginAction LogoutActionMainPageAction

LoginManager

UserFacadeDelegate

(from delegate)

<<use>><<use>>

<<use>>

<<use>>

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction (1)

public class LoginAction extends DefaultAction {

public ActionForward doPerform(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/* Get data. */

LoginForm loginForm = (LoginForm) form;

String loginName = loginForm.getLoginName();

String password = loginForm.getPassword();boolean rememberMyPassword = loginForm.getRememberMyPassword();

/* Do login. */

ActionErrors errors = new ActionErrors();

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction (y 2)

try {

LoginManager.login(request, response, loginName, password,rememberMyPassword);

} catch (InstanceNotFoundException e) {errors.add("loginName", new ActionError(

"ErrorMessages.loginName.notFound"));} catch (IncorrectPasswordException e) {

errors.add("password", new ActionError("ErrorMessages.password.incorrect"));

}

/* Return ActionForward. */if (errors.empty()) {

return mapping.findForward("MainPage");} else {

saveErrors(request, errors); return new ActionForward(mapping.getInput());

}

}

}

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LogoutAction

public class LogoutAction extends DefaultAction {

public ActionForward doPerform(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/* Do logout. */

LoginManager.logout(request, response);

/* Return ActionForward. */ return mapping.findForward("MainPage");

}

}

Comentarios

n Las acciones utilizan el método saveErrors(heredado de org.struts.apache.action.Action) para insertar un atributo con los errores en la request

MainPage.jsp (1)

<%@ taglib uri="/struts-bean.tld" prefix="bean" %>

<%@ taglib uri="/struts-html.tld" prefix="html" %>

<%@ taglib uri="/struts-logic.tld" prefix="logic" %>

<html>

<head>

<title><bean:message key="MainPage.title"/></title>

</head>

<body text="#000000" bgcolor="#ffffff" link="#000ee0" vlink="#551a8b" alink="#000ee0">

MainPage.jsp (2)<%-- Welcome --%>

<h1>

<logic:notPresent name="loginName" scope="session"><bean:message key="MainPage.welcome"/>

</logic:notPresent>

<logic:present name="loginName" scope="session">

<bean:message key="MainPage.hello"/>

<bean:write name="loginName" scope="session"/></logic:present>

</h1>

<%-- Some <br>'s --%>

<br>

<br>

<br>

MainPage.jsp (y 3)<%-- Links to Login or Logout --%>

<logic:notPresent name="loginName" scope="session">

<html:link href="Login.jsp">

<bean:message key="MainPage.login"/></html:link>

</logic:notPresent>

<logic:present name="loginName" scope="session">

<html:link href="Logout.do">

<bean:message key="MainPage.logout"/></html:link>

</logic:present>

</body>

</html>

Login.jsp (1)<%@ taglib uri="/struts-bean.tld" prefix="bean" %><%@ taglib uri="/struts-html.tld" prefix="html" %>

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

<body text="#000000" bgcolor="#ffffff">

<html:form action="Login.do">

<table width="100%" border="0" align="center" cellspacing="12">

<%-- Login name --%>

<tr> <th align="right" width="50%">

<bean:message key="Login.loginName"/></th><td align="left">

<html:text property="loginName" size="16" maxlength="16"/><html:errors property="loginName"/>

</td></tr>

Login.jsp (2)<%-- Password --%>

<tr> <th align="right" width="50%">

<bean:message key="Login.password"/></th><td align="left">

<html:password property="password" size="16"maxlength="16"/>

<html:errors property="password"/></td>

</tr>

<%-- Remember my password --%>

<tr> <th align="right" width="50%">

<bean:message key="Login.rememberMyPassword"/></th><td align="left">

<html:checkbox property="rememberMyPassword"/></td>

</tr>

Login.jsp (y 3)<%-- Login button --%>

<tr>

<td width="50%"></td>

<td align="left" width="50%"><html:submit>

<bean:message key="Buttons.login"/>

</html:submit>

</td>

</tr>

</table>

</html:form>

</body>

</html>

Comentarios

n html:text, html:password y html:checkboxrecuperan el valor de la propiedad asociada a través del método getXXX (property="XXX") sobre la instancia de LoginForm enganchada a la requestn Saben que el ActionForm asociado es de tipo LoginForm

dado que el atributo action de html:form es igual a Login.do

n struts-config.xml especifica LoginForm como la clase ActionForm para la URL /Login.do

n html:errorsn Imprime el mensaje de error asociado a la propiedad

especificada si figura en el ActionErrors enganchado a la request

n El mensaje vendrá flanqueado por errors.header y errors.footer (Messages.properties)

InternalError.jsp<%@ taglib uri="/struts-bean.tld" prefix="bean" %>

<html>

<head>

<title><bean:message key="InternalError.title"/></title></head>

<body text="#000000" bgcolor="#ffffff">

<h3><div align="center"><font color="red">

<bean:message key="InternalError.title"/>.<bean:message key="ErrorMessages.retry"/>

</font></div></h3>

</body>

</html>

Un pequeño problema

n Situaciónn Imaginemos que la página de bienvenida fuese MainPage.jspn En realidad es Index.jsp

n Un usuario hace el login y selecciona “Remember my password”

n Termina la sesiónn Accede dos días después tecleando la URL de la aplicación

en su navegador (ej.: http://www.acme.org/MiniPortal)n La sesión no contendrá el atributo loginName, dado que no

se ha ejecutado LoginManager.getLoginNamen Se le redirige a la página de login

Un solución

n El navegador nunca invocará a /MainPage.jspdirectamente, sino a /Index.jsp o /MainPage.don Index.jsp

n Página de bienvenidan Hace un forward a /MainPage.do => se ejecuta MainPageAction

n MainPageActionn LoginManager.getLoginName y forward a

/MainPage.jsp

n Cuando se haga un sendRedirect a la página principal se hará siempre con la URL /MainPage.do y nunca con /MainPage.jspn /MainPage.jsp nunca aparecerá en la caja de diálogo del

navegador, de manera que el usuario nunca hará un bookmark a esa página, sino a /MainPage.do o /Index.jsp

n En MiniPortal volveremos a discutir este problema

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.MainPageAction

public class MainPageAction extends DefaultAction {

public ActionForward doPerform(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/*

* "LoginManager.getLoginName" creates an appropriate session

* if the session had expired, or the user had not logged in,

* but he/she had selected "remember my password" in the last* login.

*/

LoginManager.getLoginName(request);

/* Return ActionForward. */

return mapping.findForward("ShowMainPage");

}

}

Index.jsp

<jsp:forward page="MainPage.do"/>