Anda di halaman 1dari 89

4.4 Tutorial de JSP 2.

0, JSTL y Apache
Struts

JSP 2.0 (1)

Qu aade JSP 2.0 frente a JSP 1.x?

Lenguaje de expresiones

Documentos JSP

Anteriormente slo estaba disponible en JSTL


Pginas JSP en sintaxis XML
JSP 1.2 tambin permita escribir documentos JSP, pero de una
manera ms incmoda

Implementar tags a medida utilizando la propia tecnologa


JSP

Se implementan en pginas JSP


Ms sencillo que el API de extensin de tags
(javax.servlet.jsp.tagext), pero menos potente
til para tags orientados a presentacin, para tags que hagan
uso de libreras existentes y para desarrolladores de pginas
JSP que no dispongan de conocimientos de Java

JSP 2.0 (y 2)

Compatibilidad con JSP 1.x

Un contenedor de JSP 2.0 tiene que poder ejecutar


aplicaciones con sintaxis JSP 1.x
Es posible migrar una aplicacin JSP 1.x a sintaxis JSP 2.0
pgina a pgina

En este apartado, y en los dos siguientes, se ilustran


la sintaxis de los documentos JSP y el lenguaje de
expresiones

Lenguaje de expresiones (1)

En JSP 1.x si se desea dar valor a un atributo de un


tag, es preciso usar una expresin <%= ... %>

Ejemplo

<jsp:useBean id="shoppingCart" scope="session"


class="org.acme.ShoppingCart"/>
<xxx:if test="<%= shoppingCart.getNumberOfProducts() > 0 %>">
...
</xxx:if>

JSP 2.0 proporciona un lenguaje de expresiones para


facilitar su construccin

Ejemplo

<xxx:if test="${sessionScope.shoppingCart.numberOfProducts > 0}">


...
</xxx:if>

Lenguaje de expresiones (2)

Expresiones y literales

Las expresiones tienen que ir rodeadas por ${ y }.


Cualquier valor que no empiece por ${, se considera un
literal

Los literales que incluyen el smbolo ${, han de escaparlo


rodendolo de ${' y '}
Ejemplo:

<xxx:aTag att="This literal includes ${'${'} character"/>

Acceso a atributos de objetos Java en expresiones

Se puede acceder a las propiedades de un JavaBean, y a


objetos de un Map, List o vector

Lenguaje de expresiones (3)

Acceso a atributos de objetos Java en expresiones


(cont)

Ejemplos

${user.firstName} = user.getFirstName()
${user.address.city} = user.getAddress().getCity()
${user.preferencesMap["shipping"]} =
user.getPreferencesMap().get("shipping")
${user.preferencesList[0]} = user.getPreferencesList().get(0)

Unifica el tratamiento de los operadores . y []

${user.firstName} es

equivalente a ${user["firstName"]}
${user.preferencesMap["shipping"]} es equivalente a
${user.preferencesMap.shipping}

Para determinados casos, es preciso usar el operador []

${user.preferencesMap["book.fiction"]} es equivalente
user.getPreferencesMap().get("book.fiction")

${user.preferencesMap[product.category]} es equivalente
user.getPreferencesMap().get(product.getCategory())

Lenguaje de expresiones (4)

Objetos implcitos

Entre otros

pageScope (Map)
requestScope (Map)
sessionScope (Map)
applicationScope (Map)
param (Map que mapea nombres de parmetros univaluados a
String)
paramValues (Map que mapea nombres de parmetros
multivaluados a String[])

Cuando se usa un objeto sin especificar su mbito (el objeto


implcito en el que est contenido), se busca en los mbitos
page, request, session y application (en este orden)

Ejemplo

<xxx:if test="${shoppingCart.numberOfProducts > 0}">


...
</xxx:if>

Lenguaje de expresiones (y 5)

Literales

Boolean (true y false)


Numricos
Cadenas de caracteres (entre comillas simples o dobles)
null

Operadores

Aritmticos: +,-, *, /, div, %, mod


Lgicos: &&, and, ||, or, !, not
Relacionales: ==, eq, !=, ne, <, lt, >, gt, <=, le, >=, ge
empty: permite comprobar si un valor es null

Ejemplos

<xxx:if test="${!empty requestScope.previous}">


...
</xxx:if>
<xxx:if test="${sessionScope.shoppingCart.numberOfProducts > 0}">
...
</xxx:if>

Se pueden usar parntesis

JSTL (1)

En el pasado existan numerosas libreras de tags JSP


que permitan

Iterar sobre colecciones


Imprimir valores de propiedades de JavaBeans de forma
segura
Internacionalizacin de mensajes, nmeros, fechas, etc.
Generacin de URLs aplicando URL rewriting
Acceso a documentos XML
Etc

Por ello, se decidi estandarizar una librera general


de tags, llamada JSTL (JSP Standard Tag Library)

JSTL (2)

Tags en JSTL

Core

I18n (internacionalizacin)

Control de flujo
Soporte para URLs
Soporte para internacionalizacin: establecimiento del Locale,
generacin de mensajes, formateo de nmeros, cantidades
monetarias, fechas, etc.

XML

Parsing de un documento XML


Flujo de control para recorrer un documento XML (alternativa a
XSL para casos sencillos)
Tags para lanzar transformaciones XSL

JSTL (y 3)

Tags en JSTL (cont)

Acceso a BDs

Funciones

JSP 2.0 define un mecanismo para aadir funciones al


lenguaje de expresiones
JSTL 1.1 define un conjunto de funciones estndar

Permiten lanzar sentencias SQL a BDs relacionales


Slo deberan usarse para prototipado rpido o
aplicaciones muy simples

length (aplicable a Collection y String), toLowerCase,


toUpperCase, substring, contains, etc

En este apartado y en los dos siguientes se ilustran


parte de los tags de los grupos Core e I18n

Qu es Struts ?

Framework OpenSource para implementar


aplicaciones web con servlets y JSP segn el patrn
arquitectnico Model-View-Controller
Proyecto de Apache

Autor original: Craig R. McClanahan

Funciona sobre cualquier servidor de aplicaciones


web que implemente las APIs de servlets y JSP
Ha ganado gran relevancia en el mundo de las
aplicaciones web Java

Versin 1.0 estable en Julio 2001


Posteriormente, surgieron otros framework MVC

Qu proporciona Struts ?

Un framework que da soporte para implementar las


capas controlador y vista de una aplicacin web

Servlet Front Controller y clases relacionadas


Sistema de plantillas
Validacin de parmetros
Una librera de tags JSP muy completa

El patrn Front Controller en Struts (1)


javax.servlet.http.HttpServlet

org.apache.struts.action.ActionServlet
0..n

# doGet
# doPost

org.apache.struts.action.Action
+ execute

<<use>> <<instantiate>>

org.apache.struts.action.ActionForm
+ reset
+ validate

ActionForm1

Action1

...

...

ActionFormN
<<use>>

ActionN

El patrn Front Controller en Struts (2)

ActionServlet

Servlet Front Controller


En web.xml se especifica que todas las URLs que impliquen
procesamiento (por GET o POST) vayan a este servlet

Clases ActionForm

Si el programador lo desea, puede acceder a los parmetros de la


request a travs de un JavaBean que extiende ActionForm

Ej.: las URLs que termine en .do

Especialmente til en formularios

Clase Action => mtodo execute

Accede a los parmetros de la request, directamente o va el


ActionForm correspondiente
Realiza la operacin invocando un mtodo de un Session
Facade del modelo o una fachada del controlador
Deja el resultado devuelto por el mtodo en la request o en la
sesin
Devuelve un objeto ActionForward, que representa la URL que
hay que visualizar a continuacin (sendRedirect o forward)

El patrn Front Controller en Struts (3)

Fichero de configuracin

Clases ActionForm que usa nuestra aplicacin

Nombre lgico (ej.: loginForm)


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

URLs que implican procesamiento

URL de tipo path relativo a contexto (ej.: /Login)

No llevan el .do final

Nombre completo de la clase Action (ej.:


es.udc.fbellas.j2ee.strutstutorial.portal3.http
.controller.actions.LoginAction)
Nombre lgico de la clase ActionForm asociada

El patrn Front Controller en Struts (y 4)

Fichero de configuracin (cont)

Definiciones de nombres lgicos de URLs

Nombre que usan las acciones cuando devuelven un


ActionForward (ej.: ShowMainPage)
sendRedirect o forward
URL a invocar (ej.: /MainPage.jsp)

Cuando el servlet ActionServlet arranca (init), lee el


fichero de configuracin
Crea una nica instancia de cada clase Action

No se crea una instancia de una clase Action por cada


peticin que se recibe
Tienen que ser thread-safe
Misma situacin que cuando se trabaja con servlets

La librera de tags de Struts (1)

Bean

Logic

Imprimir el valor de las propiedades de JavaBeans de


manera segura
Soporte para internacionalizacin de mensajes
No los usaremos, dado que JSTL ofrece una alternativa
estndar
Control de flujo
No los usaremos, dado que JSTL ofrece una alternativa
estndar

HTML

Generacin de HTML bsico

Campos de entrada en formularios


Enlaces (con URL rewriting)

La librera de tags de Struts (y 2)

Tiles

Caso particular del patrn Composite View

Sistema de plantillas para pginas JSP

Reemplaza a Template

El sistema de plantillas que se usaba con Struts 1.0

Arquitectura MVC con Struts

Modelo

Controlador

Clases independientes de la vista y el controlador


Conjunto de clases Action
Interactan con el modelo y seleccionan la siguiente vista
(dejndole los datos en uno de los cuatro posibles mbitos,
normalmente request o session)

Vista

Conjunto de clases ActionForm

Conjunto de pginas JSP

No contienen cdigo Java


Slo visualizan datos
Usan acciones JSP 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 en Login

Clic en el botn Login

Demo Portal-3 (3)

Clic en Logout
Terminar y lanzar el navegador dos das ms tarde

Acceder a Portal-3 main page

Portal-3 main page


(Welcome to Portal-3)

Demo Portal-3 (4)

Este ejemplo, al igual que los siguientes, usa XHTML


1.0 Estricto y CSS 2.0
XHTML

Versin XML de HTML (ej.: todos los tags tienen que


cerrarse, los valores de los atributos tienen que
entrecomillarse, tags en minsculas, etc)

CSS

El XHTML generado slo contiene contenido estructurado


El formato (fuentes, colores, posicionamiento, etc) se
especifica en una hoja (fichero) de estilos CSS
El aspecto grfico de la aplicacin puede cambiarse
modificando la hoja CSS

Demo Portal-3 (y 5)

CSS (cont)

Tambin puede ser interesante tener un conjunto de hojas


CSS con distintos formatos para una misma aplicacin web

Visualizacin en ordenador de sobremesa


Visualizacin en PDA (ej.: no muestra o resume cabecera,
sidebar y pi de pgina)
Printer-friendly pages
Etc

Se procura huir del uso de tablas, excepto para la


presentacin de datos que siempre han de
visualizarse de manera tabular (ej.: las cuentas de un
usuario en una aplicacin bancaria)

CSS tiene sus propios mecanismos de posicionamiento

Estructura de paquetes
es.udc.fbellas.j2ee.util.struts.action
es.udc.fbellas.j2ee.strutstutorial.portal3
http
controller
actions
view
actionforms
messages
model
userfacade
delegate
exceptions

jar tvf StrutsTutorial.war (1)


Index.jspx
InternalError.jspx
Login.jspx
MainPage.jspx
css/styles.css
WEB-INF/Struts/struts-config.xml
WEB-INF/lib/jstl.jar
WEB-INF/lib/standard.jar
WEB-INF/lib/antlr.jar
WEB-INF/lib/commons-*.jar
WEB-INF/lib/jakarta-oro.jar
WEB-INF/lib/struts.jar
WEB-INF/lib/StandardUtil.jar
WEB-INF/lib/WebUtil.jar

jar tvf StrutsTutorial.war (y 2)


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/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/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/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/view/
messages/Messages.properties
WEB-INF/web.xml

Comentarios (1)

Documentos JSP

Existen varios mtodos para especificar que una pgina JSP


es un documento JSP
Quizs la manera ms natural consiste en usar un descriptor
de la aplicacin web conforme a Servlet 2.4 (como ya
hicimos en anteriores apartados) y usar jspx como
extensin de las pginas JSP que sean documentos JSP

WEB-INF/Struts

struts-config.xml: configuracin de Struts para la


aplicacin del tutorial

Comentarios (y 2)

WEB-INF/lib

struts.jar, commons-*.jar: Struts


standard.jar, jstl.jar, jakarta-oro.jar,
antlr.jar: Jakarta Standard TagLibs (implementacin
OpenSource de JSTL)
StandardUtil.jar y WebUtil.jar: subsistema Util de
J2EE-Examples
WEB-INF/classes/es/.../Messages.properties

Internacionalizacin de mensajes

WEB-INF/web.xml (1)
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<distributable/>
<!-- =============== Standard TagLibs configuration ============= -->
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>es.udc.fbellas.j2ee.strutstutorial.portal3.http.
view.messages.Messages</param-value>
</context-param>

WEB-INF/web.xml (2)
<!-- ================= Front controller configuration =========== -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet
</servlet-class>
<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 (y 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.jspx</welcome-file>
</welcome-file-list>
</web-app>

Comentarios (1)

context-param

Permite definir un parmetro de configuracin global a toda


la aplicacin web
Accesible va
Servlet.getServletConfig().getServletContext
().getInitParameter()
En el ejemplo se utiliza para dar valor al parmetro de
configuracin
javax.servlet.jsp.jstl.fmt.localizationContext

Lo usan los tags de internacionalizacin de mensajes de JSTL


Nombre del fichero de mensajes (sin sufijo .properties)
Debe estar debajo de WEB-INF/classes y usar un nombre
consistente con su ubicacin (como si de una clase se tratase)

Comentarios (2)

Servlet org.apache.struts.actions.ActionServlet

Aparecen dos tags que no hemos usado hasta ahora

init-param

Permite definir un parmetro de configuracin especfico al servlet


y su valor
Accesible va
Servlet.getServletConfig().getInitParameter()

load-on-startup

Indica que el servlet se debera cargar cuando el servidor


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

Comentarios (y 3)

Servlet org.apache.struts.actions.ActionServlet

Parmetros de inicializacin

config

detail

Path de tipo relativo a contexto del fichero de configuracin de


Struts
Nivel de detalle en los mensajes de depuracin durante el parsing
de los ficheros de configuracin

debug

Nivel de detalle en los mensajes de depuracin de


ActionServlet

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.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.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.jspx"
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.jspx"/>
</action>
<action path="/Login"
type="es.udc.fbellas.j2ee.strutstutorial.portal3.http.
controller.actions.LoginAction"
name="loginForm" scope="request" input="/Login.jspx"
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-mappings>
<!-- ============ Message Resources Definitions =================== -->
<message-resources parameter="es.udc.fbellas.j2ee.strutstutorial.
portal3.http.view.messages.Messages"/>
</struts-config>

Comentarios (1)

En el fichero struts-config.xml se usa

<!DOCTYPE struts-config PUBLIC


"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd">

El especificador PUBLIC permite especificar un identificador


y una URI para la ubicacin del DTD
El procesador del documento XML (en este caso, Struts)
puede usar el identificador para recuperar un DTD
localmente almacenado, y en consecuencia, no usar la URI
especificada

struts.jar incluye el DTD

Comentarios (2)

Definiciones de nombres lgicos de URLs

Se usan en la implementacin de las acciones para devolver


un ActionForward y en algunas acciones JSP
Se especifican con forward

Atributos documentados en JavaDoc de


org.apache.struts.action.ActionForward
name: nombre lgico
path: path relativo a contexto de la URL a la que se invocar
redirect: true (sendRedirect) o false (forward)

false por defecto

Pueden ser globales (global-forwards) o particulares a


una accin (action)

Comentarios (3)

action

Atributos documentados en JavaDoc de


org.apache.struts.config.ActionConfig
type: nombre completo de la clase Action
path: URL (path relativo a contexto) que provocar la
invocacin de la accin

name: nombre del ActionForm (definido por form-bean)


que captura los parmetros de la invocacin
scope: mbito (request o session) del ActionForm

Se especifican sin el sufijo .do !

En general, request

input: path relativo a contexto del formulario de entrada


validate: true si el Front Controller tiene que llamar al
mtodo validate del ActionForm

En general, true

Comentarios (y 4)

message-resources

Especifica la ubicacin del fichero de mensajes


Actualmente Struts no est integrado con JSTL

WEB-INF/classes/es/.../Messages.properties (1)
Buttons.login=Login
ErrorMessages.loginName.notFound=Login name not found
ErrorMessages.mandatoryField=Mandatory field
ErrorMessages.password.incorrect=Incorrect password
ErrorMessages.retry=Please, check if the operation has been performed, \
and retry if necessary
errors.footer=</span>
errors.header=<span class="errorMessage">
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)

Asocia pares <identificadorMensaje, mensaje>

Messages.properties

Convenios de nombrado para los identificadores de mensajes


Ordenados alfabticamente
errors.footer y errors.header son dos identificadores
especiales que entiende la accin html:errors de Struts
Mensajes en el lenguaje por defecto del servidor

Messages_xx.properties

Mensajes en el lenguaje cuyo cdigo ISO es xx


Cdigos ISO en
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt

en: Ingls
es: Espaol
gl: Gallego

Etc

Comentarios (y 2)

Messages.properties slo resuelve un aspecto


particular de la internacionalizacin de aplicaciones:
impresin de mensajes en distintos idiomas

En una aplicacin ms compleja puede ser necesario tener


trozos de pginas en distintos idiomas (con gran cantidad de
texto esttico) y seleccionarlos o incluirlos dinmicamente
en funcin del idioma

Otros aspectos en internacionalizacin

Formatear y tratar fechas, horas, nmeros, cantidades


monetarias

JSTL proporciona tags para ello


Tambin paquetes java.text y java.util

Puede requerir tablas para almacenar contenido en distintos


idiomas

Ej.: un servicio de noticias

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

UserFac adeDelegate
+ UserFacadeDelegate()
+ login(l oginNam e : S tring, password : S t ri ng, pas swordIsE ncrypte d : boo lean) : void

Simula la fachada del modelo que proporciona las


operaciones relativas a la interaccin del usuario con
el portal

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

A ction
(from action)

Def aul tA ct io n
+ execute(actionM apping, actionForm , request, response) : A ctionForward
# doE xecute(actionMapping, actionForm , request, response) : A ctionForward
# doOnInternalE rror(actionM apping, actionForm , request, response, internalE rrorE xception) : A ctionForw...

P rope rt yV alidat or

Comentarios

DefaultAction

Problema

Es necesario (1) capturarla, (2) imprimirla en un log (para


depuracin) e (3) ir a una pgina que indique error interno

Las clases Action derivarn de DefaultAction

En general, las clases Action invocarn una operacin sobre


un Business Delegate del modelo o una fachada del
controlador, que puede lanzar InternalErrorException

Implementa execute (Template Method) en trminos de


doExecute y doOnInternalError
Las clases hijas implementan doExecute, que tiene la misma
signatura que execute, pero puede lanzar adicionalmente
InternalErrorException

PropertyValidator

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
import
import
import
import
import
import
import
import

java.io.IOException;
javax.servlet.ServletContext;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.ServletException;
org.apache.struts.action.Action;
org.apache.struts.action.ActionMapping;
org.apache.struts.action.ActionForm;
org.apache.struts.action.ActionForward;

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 execute(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
try {
return doExecute(mapping, form, request, response);
} catch (Exception e) {// Any exception thrown by "doExecute",
// including instances of
// "RuntimeException".
return doOnException(mapping, form, request,
response, e);
}
}
protected abstract ActionForward doExecute(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException, InternalErrorException;

es.udc.fbellas.j2ee.util.struts.action.DefaultAction (y 3)
protected ActionForward doOnException(
ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response,
Exception exception)
throws IOException, ServletException {
/*
* Log error, even with debug level <= 0, because it is a
* severe error.
*/
ServletContext servletContext =
servlet.getServletConfig().getServletContext();
servletContext.log(exception.getMessage(), exception);
/* 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";
private PropertyValidator() {}
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 ActionMessage(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 ActionMessage(MANDATORY_FIELD));
return false;
} else {
return true;
}
}
private final static boolean validateMandatory(ActionErrors errors,
String propertyName, String propertyValue, boolean mandatory) {
if (mandatory) {
return validateMandatory(errors, propertyName,
propertyValue);
} else {
return true;
}
}
// Resto de mtodos validateXXX => Anlogos ...
}

Comentarios

org.apache.struts.action.ActionMapping

Permite acceder a los valores configurados en strutsconfig.xml para la accin en ejecucin (inclusive a los forwards
globales)

org.apache.struts.action.ActionErrors

Juega el papel del mapa de errores que hemos empleado en


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

ActionMessage se introdujo en Struts 1.2, y reemplaza a


ActionError

org.apache.struts.action.ActionForward

Representa la siguiente URL a la que hay que ir


El Front Controller lo invocar despus de llamar al mtodo
execute sobre la accin

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

LoginForm

Juega el mismo papel que la clase vista en el apartado 4.2


Hereda de org.apache.struts.action.ActionForm

Generalmente interesa redefinir reset y validate

reset

El Front Controller lo llama antes de dar valor a las propiedades

validate

Permite validar las propiedades despus de que el Front


Controller les haya dado valores
Slo se invoca si se ha especificado validate="true" para
la accin correspondiente en struts-config.xml
Si devuelve un ActionErrors no vaco, el Front Controller (1)
no invocar el mtodo execute sobre la accin
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 correspondiente en strutsconfig.xml (formulario de entrada)

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions
Defaul tAc tion
(from ac tion)

M ai nP ageA c t ion

< < us e> >

LoginA c t ion

< <us e>>

LogoutA c tion

< < use> >

LoginM anager

<< us e>>
Us erFacadeDelegate
(from delegate)

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LoginAction (1)
public class LoginAction extends DefaultAction {
public ActionForward doExecute(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. */
ActionMessages errors = new ActionMessages();

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 ActionMessage(
"ErrorMessages.loginName.notFound"));
} catch (IncorrectPasswordException e) {
errors.add("password", new ActionMessage(
"ErrorMessages.password.incorrect"));
}
/* Return ActionForward. */
if (errors.isEmpty()) {
return mapping.findForward("MainPage");
} else {
saveErrors(request, errors);
return new ActionForward(mapping.getInput());
}
}
}

Comentarios

Las acciones utilizan el mtodo saveErrors


(heredado de org.struts.apache.action.Action)
para insertar un atributo con los errores en la
request
org.apache.struts.action.ActionMessages

Se introdujo en Struts 1.2


Similar a ActionErrors
Existen dos versiones del mtodo saveErrors, una que
acepta ActionErrors (deprecated) y otra que acepta
ActionMessages (el usado en el ejemplo)

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.LogoutAction
public class LogoutAction extends DefaultAction {
public ActionForward doExecute(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException, InternalErrorException {
/* Do logout. */
LoginManager.logout(request, response);
/* Return ActionForward. */
return mapping.findForward("MainPage");
}
}

MainPage.jspx (1)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
xmlns:html="http://struts.apache.org/tags-html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<jsp:output doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
omit-xml-declaration="true" />
<jsp:directive.page contentType="text/html; charset=iso-8859-1" />
<head>
<title><fmt:message key="MainPage.title" /></title>
<c:url var="stylesURL" value="/css/styles.css" />
<link rel="StyleSheet" href="${stylesURL}"
type="text/css" media="all" />
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>

MainPage.jspx (2)
<!-- Welcome -->
<div id="header">
<c:choose>
<c:when test="${empty sessionScope.loginName}">
<fmt:message key="MainPage.welcome" />
</c:when>
<c:otherwise>
<fmt:message key="MainPage.hello" />
<c:out value=" ${sessionScope.loginName}" />
</c:otherwise>
</c:choose>
</div>

MainPage.jspx (y 3)
<!-- Links to Login or Logout -->
<p>
<c:choose>
<c:when test="${empty sessionScope.loginName}">
<c:url var="loginURL" value="Login.jspx" />
<a href="${loginURL}">
<fmt:message key="MainPage.login" />
</a>
</c:when>
<c:otherwise>
<html:link action="Logout.do">
<fmt:message key="MainPage.logout" />
</html:link>
</c:otherwise>
</c:choose>
</p>
</body>
</html>

Comentarios (1)

La pgina JSP es un documento XML bien formado


Importacin de libreras

En el tag raz aprovechamos para importar las libreras de


tags que se precisan, especificando sus espacios de nombres
El espacio de nombres por defecto es el correspondiente a
los tags de XHTML (http://www.w3.org/1999/xhtml)
Libreras

http://java.sun.com/JSP/Page (jsp)

http://java.sun.com/jsp/jstl/fmt (fmt)

Tags I18n de JSTL

http://struts.apache.org/tags-html (html)

Tags estndar de JSP (proporcionados por el contenedor)

Tags HTML de Struts

http://java.sun.com/jsp/jstl/core (c)

Tags Core de JSTL

Comentarios (2)

Importacin de libreras (cont)

Cuando se importa una librera, el contenedor busca


automticamente su descriptor (fichero .tld) en

WEB-INF (y sus subdirectorios)


En los ficheros .jar que usa la aplicacin

Dentro del fichero .jar busca debajo de META-INF (y sus


subdirectorios)

El descriptor especifica, entre otras cosas,

La URI del espacio de nombres (que es lo que utiliza el


contenedor para saber que ste es el descriptor de la librera)
Los nombres de los tags que proporciona la librera y los
nombres de las clases que los implementan
En el servlet generado por el contenedor, por cada aparicin de
un tag de una librera, se crea una instancia la clase
correspondiente y se invocan los mtodos necesarios a travs
de un interfaz estndar

Comentarios (3)

Importacin de libreras (cont)

Cuando el contenedor encuentra un tag no JSP (ej.: html),


que importa libreras JSP (ej.: xlmns:fmt="... "), en la
respuesta generada no incluye los xlmns:xxx
correspondientes

Ej.: Para ...

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
xmlns:html="http://struts.apache.org/tags-html"
xmlns:c="http://java.sun.com/jsp/jstl/core">

... genera ...

<html xmlns="http://www.w3.org/1999/xhtml">

Comentarios (4)

En MainPage.jspx se utiliza

<jsp:output doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
omit-xml-declaration="true" />

... lo que genera ...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

... y se genera en el lugar adecuado, es decir, antes de que


se genere el tag raz html
omit-xml-declaration="true" provoca que no se
genere la declaracin XML

Por defecto, el contenedor aade la declaracin XML al


principio del documento generado por un documento JSP
Lo lgico sera generar la declaracin XML (dado que todo
documento XML debera tenerla), sin embargo causa
problemas en algunos navegadores

Comentarios (5)

Tags jsp:directive.XXX

Equivalentes a las directivas <%@ XXX ... %>, con sus


mismos atributos
En MainPage.jspx se utiliza

<jsp:directive.page contentType="text/html; charset=iso-8859-1" />

Permite especificar el contentType de la respuesta HTTP


En un documento JSP, el contentType por defecto es
text/xml, lo que provoca que algunos navegadores (ej.:
Internet Explorer) visualicen la respuesta como un documento
XML (y no como una pgina HTML)
En una pgina JSP (que no sea un documento JSP), el
contentType por defecto es text/html, y por eso nunca lo
hemos tenido que especificar en los ejemplos anteriores

Comentarios (6)
En el ejemplo se usa

<c:url var="stylesURL" value="/css/styles.css" />


<link rel="StyleSheet" href="${stylesURL}"
type="text/css" media="all" />

Alternativamente se podra haber usado

<link rel="StyleSheet" href="css/styles.css"


type="text/css" media="all" />

Pero esto resultara tedioso y propenso a errores en una


aplicacin web grande con pginas JSP en directorios con
cierto nivel de anidamiento (ej.:
href="../../../css/styles.css")

Usar

<link rel="StyleSheet" href="/css/styles.css"


type="text/css" media="all" />

No funcionara, dado que la URL /css/styles.css no


existe

Comentarios (7)
Usar

<link rel="StyleSheet" href="/StrutsTutorial/css/styles.css"


type="text/css" media="all" />

Sera una mala idea, dado que el administrador del servidor


de aplicaciones web podra querer instalar la aplicacin web
con otro nombre

El ejemplo usa el tag c:url

Aplica URL rewriting si el navegador no acepta cookies


(aunque en este caso no es til)
Si la URL es de tipo path relativo a contexto (ej.:
/css/styles.css), le antepone el nombre de la
aplicacin web, de manera que la URL resultante es de tipo
path absoluto (ej.:.
/StrutsTutorial/css/styles.css)

Comentarios (y 8)

html:link

Genera el enlace HTML (<a href= ... </a>)


Cuando se utiliza el atributo action, aplica URL rewriting si
el navegador no acepta cookies

El atributo action tiene que especificar la URL de una


accin de Struts

NOTA: tambin dispone (alternativamente) del atributo


href

La URL puede apuntar a cualquier sitio


No se aplica URL rewriting

Login.jspx (1)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
xmlns:html="http://struts.apache.org/tags-html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<jsp:output doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
omit-xml-declaration="true" />
<jsp:directive.page contentType="text/html; charset=iso-8859-1" />
<head>
<title><fmt:message key="Login.title" /></title>
<c:url var="stylesURL" value="/css/styles.css" />
<link rel="StyleSheet" href="${stylesURL}"
type="text/css" media="all" />
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>

Login.jspx (2)
<!-- Struts tags must render XHML -->
<html:xhtml/>
<!-- Print login form -->
<html:form action="Login.do">
<!-- Login name -->
<div class="field">
<span class="label">
<fmt:message key="Login.loginName" />
</span>
<span class="entry">
<html:text property="loginName" size="16" maxlength="16" />
<html:errors property="loginName" />
</span>
</div>

Login.jspx (3)
<!-- Password -->
<div class="field">
<span class="label">
<fmt:message key="Login.password" />
</span>
<span class="entry">
<html:password property="password" size="16"
maxlength="16" />
<html:errors property="password" />
</span>
</div>
<!-- Remember my password -->
<div class="field">
<span class="label">
<fmt:message key="Login.rememberMyPassword" />
</span>
<span class="entry">
<html:checkbox property="rememberMyPassword" />
</span>
</div>

Login.jspx (y 4)
<!-- Login button -->
<div class="button">
<html:submit><fmt:message key="Buttons.login" /></html:submit>
</div>
</html:form>
</body>
</html>

Comentarios (1)

html:xhtml

Causa que los tags de Struts de la librera HTML que se usen


en esa pgina generen XHTML en vez de HTML (por defecto,
algunos tags, como html:text, html:password o
html:checkbox generan los tags sin cerrarlos, mientras
que otros s los cierran, como por ejemplo, html:link)

html:text, html:password y html:checkbox


recuperan el valor de la propiedad asociada a travs
del mtodo getXXX (property="XXX") sobre la
instancia de LoginForm enganchada a la request
(con nombre loginForm)

Saben que el ActionForm asociado se llama loginForm,


dado que el atributo action de html:form es igual a
Login.do
struts-config.xml especifica loginForm como el
nombre del ActionForm para la URL /Login.do

Comentarios (y 2)

html:errors

Imprime el mensaje de error asociado a la propiedad


especificada si figura en el ActionErrors/
ActionMessages enganchado a la request
El mensaje vendr flanqueado por errors.header y
errors.footer (Messages.properties)

InternalError.jspx (1)
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<jsp:output doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
omit-xml-declaration="true" />
<jsp:directive.page contentType="text/html; charset=iso-8859-1" />
<head>
<title><fmt:message key="InternalError.title" /></title>
<c:url var="stylesURL" value="/css/styles.css" />
<link rel="StyleSheet" href="${stylesURL}"
type="text/css" media="all" />
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1" />
</head>
<body>

InternalError.jspx (y 2)
<p>
<fmt:message key="InternalError.title" />.
<fmt:message key="ErrorMessages.retry" />
</p>
</body>
</html>

Un pequeo problema

Situacin

Imaginemos que la pgina de bienvenida fuese


MainPage.jspx

Un usuario se autentica seleccionando Remember my


password
Termina la sesin
Accede dos das despus tecleando la URL de la aplicacin
en su navegador (ej.: http://www.acme.org/StrutsTutorial)

En realidad es Index.jspx

Se ejecuta MainPage.jspx

La sesin no contendr el atributo loginName, dado que no


se ha ejecutado LoginManager.getLoginName

Una solucin

El navegador nunca invocar a /MainPage.jspx


directamente

Index.jspx

MainPageAction

LoginManager.getLoginName y forward a
/MainPage.jspx

Cuando se haga un sendRedirect a la pgina principal se


har siempre con la URL /MainPage.do y nunca con
/MainPage.jspx

Pgina de bienvenida
Hace un forward a /MainPage.do => se ejecuta
MainPageAction

/MainPage.jspx nunca aparecer en la caja de dilogo del


navegador, de manera que el usuario nunca har un bookmark
a esa pgina, sino a /MainPage.do

En MiniPortal volveremos a discutir este problema

es.udc.fbellas.j2ee.strutstutorial.portal3.http.controller.actions.MainPageAction
public class MainPageAction extends DefaultAction {
public ActionForward doExecute(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.jspx
<jsp:forward xmlns:jsp="http://java.sun.com/JSP/Page"
page="MainPage.do" />