Documentos de Académico
Documentos de Profesional
Documentos de Cultura
javax.servlet.http.HttpServlet
org.apache.struts.action.ActionServlet org.apache.struts.action.Action
0..n
# doGet + perform
# doPost
<<use>> <<instantiate>>
org.apache.struts.action.ActionForm
ActionForm1 ActionFormN
... <<use>>
El patrón Front Controller en Struts (2)
n ActionServlet
n Servlet Front Controller
n En web.xml se especifica que todas las URLs que impliquen
procesamiento (por GET o POST) vayan a este servlet
n Ej.: las URLs que termine en .do
n Clases ActionForm
n Si el programador lo desea, puede acceder a los parámetros de la
request a través de un JavaBean que extiende ActionForm
n Especialmente útil en formularios
n Clase Action => método perform
n Accede a los parámetros de la request, directamente o vía el
ActionForm correspondiente
n Realiza la operación invocando un método de un Session
Facade del modelo o una fachada del controlador
n Deja el resultado devuelto por el método en la request o en la
sesión
n 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ón
n 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 procesamiento
n 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 Bean
n Imprimir el valor de las propiedades de JavaBeans de
manera segura
n Soporte para internacionalización de mensajes
n HTML
n Generación de HTML básico
n Campos de entrada en formularios
n Enlaces (con URL rewriting)
n Logic
n Si mayor que, si menor que, etc.
n Iteración sobre colecciones de objetos
n Template
n Caso particular del patrón Composite View
n Lo veremos con MiniBank y MiniPortal
Arquitectura MVC con Struts
n Modelo
n Clases independientes de la vista y el controlador
n Controlador
n Quizás se necesite extender el servlet ActionServlet
n Conjunto de clases Action
n 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 Vista
n Conjunto de clases ActionForm
n Conjunto de páginas JSP
n No contienen código Java
n Sólo visualizan datos
n 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
Clic Login
Demo Portal-3 (y 3)
Clic en Logout
Terminar y lanzar el navegador dos días más tarde
es.udc.fbellas.j2ee.strutstutorial.portal3
http
controller
actions
view
actionforms
messages
model
userfacade
delegate
exceptions
tar tvf StrutsTutorial.war (1)
MainPage.jsp
InternalError.jsp
Login.jsp
Index.jsp
WEB-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.jar
WEB-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.class
WEB-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.class
WEB-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.properties
WEB-INF/web.xml
Comentarios
n WEB-INF/Struts
n Ficheros *.tld: descriptores de las librerías de las acciones
proporcionadas por Struts
n struts-config.xml: configuración de Struts para la
aplicación del tutorial
n WEB-INF/lib
n struts.jar: ficheros .class de Struts
n crimson.jar y jaxp.jar: Struts usa JAXP para parsear
el fichero struts-config.xml
n StandarUtil.jar y WebUtil.jar: subsistema Util de
J2EE-Examples
n 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/>
<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-config>
<session-timeout>30</session-timeout>
</session-config>
<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.ActionServlet
n Aparecen dos tags que no hemos usado hasta ahora
n init-param
n Permite definir un parámetro de configuración y su valor
n 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ón
n Véase JavaDoc de org.apache.struts.actions.ActionServlet
n 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.ActionServlet
n 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 Struts
con el método ServletContext.log
n detail
n Nivel de detalle en los mensajes de depuración que escribe Struts
en System.out
Comentarios (y 3)
n Librerías de tags proporcionadas por Struts
n Aparece un tag que no hemos usado hasta ahora, taglib,
que contiene los elementos
n 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-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-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 URLs
n Se usan en la implementación de las acciones para devolver
un ActionForward y en algunas acciones JSP
n Se especifican con forward
n Atributos documentados en JavaDoc de
org.apache.struts.action.ActionForward
n name: Nombre lógico
n 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 action
n Atributos documentados en JavaDoc de
org.apache.struts.action.ActionMapping
n type: nombre completo de la clase Action
n path: URL (path relativo a contexto) que provocará la
invocación de la acción
n ¡ 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 ActionForm
n En general, request
n input: path relativo a contexto del formulario de entrada
n validate: true si el Front Controller tiene que llamar al
método validate del ActionForm
n En general, true
WEB-INF/classes/es/.../Messages.properties (1)
Buttons.login=Login
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 mensajes
n Ordenados alfabéticamente
n errors.footer y errors.header son dos identificadores
especiales que entiende la acción html:errors de Struts
n Messages.properties
n Mensajes en el lenguaje por defecto del servidor
n Messages_xx.properties
n Mensajes en el lenguaje cuyo código ISO es xx
n Códigos ISO en
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
n en: Inglés
n es: Español
n 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 idiomas
n 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ón
n Formatear y tratar fechas, horas, números, cantidades
monetarias
n Paquetes java.text y java.util
n Puede requerir tablas para almacenar contenido en distintos
idiomas
n Ej.: un servicio de noticias
es.udc.fbellas.j2ee.strutstutorial.portal3.model.userfacade.delegate
UserFacadeDelegate
+ UserFacadeDelegate()
+ login(loginName : String, password : String, passwordIsEncrypted : boolean) : void
Action
(from action)
DefaultAction
PropertyValidator
es.udc.fbellas.j2ee.util.struts.action (y 2)
n DefaultAction
n 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 DefaultAction
n 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 PropertyValidator
n 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)
try {
return doPerform(mapping, form, request, response);
} catch (InternalErrorException e) {
return doOnInternalErrorException(mapping, form, request,
response, e);
}
/*
* Log error, even with debug level <= 0, because it is a
* severe error.
*/
ServletContext servletContext =
servlet.getServletConfig().getServletContext();
servletContext.log(internalErrorException.getMessage(),
internalErrorException);
}
es.udc.fbellas.j2ee.util.struts.action.PropertyValidator (1)
long propertyValueAsLong = 0;
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 LoginForm() {
reset();
}
PropertyValidator.validateMandatory(errors, "loginName",loginName);
PropertyValidator.validateMandatory(errors, "password", password);
return errors;
}
Comentarios
n LoginForm
n Juega el mismo papel que la clase vista en el apartado
anterior
n Hereda de org.apache.struts.action.ActionForm
n Generalmente interesa redefinir reset y validate
n reset
n El Front Controller lo llama antes de dar valor a las propiedades
n 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 la
request, 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)
MainPageAction
LoginAction LogoutAction
<<use>>
<<use>> <<use>>
LoginManager
<<use>>
UserFacadeDelegate
(from delegate)
es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction (1)
/* 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 {
} 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
/* 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>
<h1>
</h1>
<br>
<br>
<br>
MainPage.jsp (y 3)
<%-- Links to Login or Logout --%>
</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>
<html:form action="Login.do">
<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>
<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:checkbox
recuperan el valor de la propiedad asociada a través
del método getXXX (property="XXX") sobre la
instancia de LoginForm enganchada a la request
n 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:errors
n 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>
</html>
Un pequeño problema
n Situación
n Imaginemos que la página de bienvenida fuese
MainPage.jsp
n En realidad es Index.jsp
n Un usuario hace el login y selecciona “Remember my
password”
n Termina la sesión
n 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.getLoginName
n Se le redirige a la página de login
Un solución
n El navegador nunca invocará a /MainPage.jsp
directamente, sino a /Index.jsp o /MainPage.do
n Index.jsp
n Página de bienvenida
n Hace un forward a /MainPage.do => se ejecuta
MainPageAction
n MainPageAction
n 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.jsp
n /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
/*
* "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"/>