4.5 caso de estudio: diseño e implementación de las capas ... · n los ejemplos acceden a los...

88
4.5 Caso de estudio: diseño e implementación de las capas controlador y vista de MiniBank con JSTL y Jakarta Struts. Patrones usados

Upload: duongthu

Post on 27-Oct-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

4.5 Caso de estudio: diseño e implementación de las capas controlador y vista de MiniBank con JSTL

y Jakarta Struts. Patrones usados

Page 2: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Introducción (1)

Page 3: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Introducción (2)

n En este apartado estudiaremos el diseño e implementación de las capas controlador y vista de MiniBank, fijándonos en unos cuantos problemas representativosn Acceso a objetos javax.sql.DataSourcen Un ejemplo de aplicación de un caso particular del patrón

Composite Viewn Dotar de una misma estructura a un conjunto de páginas

n Un ejemplo de una acción que realiza una operación que no visualiza resultadosn Transferencia bancaria

n Un ejemplo de una acción que realiza una operación y visualiza el resultado de la operaciónn Búsqueda de cuentas bancarias por identificador de cuenta (resultado

en una página) o de usuario (resultado en varias páginas)

n Algo más sobre internacionalizaciónn Formateo de balances y fechas según el idioma y paísn Selección de idioma (Gallego, Español e Inglés) y país (España, USA)

Page 4: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Introducción (y 3)

n Orden de exposiciónn Arquitectura global del controlador y la vista

n Estructura de paquetesn PlainMiniBank.war

n web.xml

n Extensiones a es.udc.fbellas.j2ee.util.struts

n Plantillas (caso particular del patrón Composite View)n Transferencia bancarian Búsqueda de cuentasn Selección de idioma y paísn Otros aspectos

Page 5: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Estructura de paqueteses.udc.fbellas.j2ee.util

es.udc.fbellas.j2ee.minibank

http

controller

actions

model

view

actionforms

messages

frontcontroller

applicationobjects

requestobjects

Page 6: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms

DefaultActionForm

(from action)

AddWithdrawForm

CreateAccountForm

FindAccountOperationsByDateForm

FindAccountsForm RemoveAccountForm

SelectLocaleForm

TransferForm

Page 7: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions

DefaultAction

(from action)

AddWithdrawAction

CreateAccountAction

EditLocaleAction

FindAccountOperationsByDateAction

FindAccountsAction

RemoveAccountAction

SelectLocaleAction

TransferAction

Page 8: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

jar tvf PlainMiniBank.war (1)DefaultFooter.jsp

DefaultHeader.jsp

...

AccountOperationsByDateContent.jsp

SelectLocaleContent.jspWEB-INF/Struts/struts-html.tld

WEB-INF/Struts/struts-template.tld

WEB-INF/Struts/plain-struts-config.xml

WEB-INF/StdTagLibs/fmt.tld

WEB-INF/StdTagLibs/c.tld

WEB-INF/Database/MySQLCreateTables.sqlWEB-INF/Database/PostgreSQLCreateTables.sql

WEB-INF/lib/standard.jar

WEB-INF/lib/jstl.jar

WEB-INF/lib/jaxen-full.jar

WEB-INF/lib/saxpath.jar

WEB-INF/lib/struts.jarWEB-INF/lib/commons-*.jar

WEB-INF/lib/<<Driver JDBC>>

WEB-INF/lib/StandardUtil.jar

WEB-INF/lib/WebUtil.jar

Page 9: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

jar tvf PlainMiniBank.war (y 2)WEB-INF/classes/es/udc/fbellas/j2ee/minibank/model/accountoperation/

dao/SQLAccountOperationDAO.class

WEB-INF/classes/es/udc/fbellas/j2ee/minibank/model/accountoperation/

dao/AbstractSQLAccountOperationDAO.class

...WEB-INF/classes/es/udc/fbellas/j2ee/minibank/http/controller/actions/

EditLocaleAction.class

WEB-INF/classes/es/udc/fbellas/j2ee/minibank/http/controller/

frontcontroller/FrontController.class

WEB-INF/classes/es/udc/fbellas/j2ee/minibank/http/view/messages/

Messages.propertiesWEB-INF/classes/es/udc/fbellas/j2ee/minibank/http/view/messages/

Messages_es.properties

WEB-INF/classes/es/udc/fbellas/j2ee/minibank/http/view/messages/

Messages_gl.properties

WEB-INF/web.xml

Page 10: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

web.xml

...

<resource-ref>

<res-ref-name>jdbc/J2EE-ExamplesDS</res-ref-name>

<res-type>javax.sql.DataSource</res-type>

<res-auth>Container</res-auth></resource-ref>

...

<env-entry>

<env-entry-name>AccountFacadeDelegateFactory/delegateClassName</env-entry-name>

<env-entry-value>es.udc.fbellas.j2ee.minibank.model.accountfacade.

plain.PlainAccountFacadeDelegate</env-entry-value>

<env-entry-type>java.lang.String</env-entry-type>

</env-entry>

...

Page 11: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

resource-ref

n Como se explicó en el tema 2, dentro de un contenedor de aplicaciones web o de EJBs, es posible definir objetos DataSource y localizarlos por JNDIn Normalmente implementan pool de conexionesn Requiere configuración en el contenedor (driver, URL,

nombre, contraseña, parámetros específicos al pool, etc.)n Ej.: En Tomcat se definen en conf/server.xml

n Se acceden vía JNDI en el contexto java:comp y se recomienda declararlos bajo el subcontexto jdbcn El DataSource del ejemplo se accedería con el nombre

JNDI java:comp/jdbc/J2EE-ExamplesDS

n Los ejemplos acceden a los objetos DataSource vía es.udc.fbellas.j2ee.util.sql.DataSourceLocator

Page 12: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

env-entry (1)

n Como se explicó en el tema 2, se pretende que la configuración de aplicaciones J2EE esté disponible en servidores de información accesibles vía JNDI, y no en ficheros planosn Especialmente importante en clusters

n Salvo para configuraciones muy complejas, los parámetros de configuración que necesiten las clases que conforman una aplicación web deben estar especificados en web.xml mediante tags env-entry

Page 13: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

env-entry (2)

n Cuando el servidor de aplicaciones web arranca, pone disponible vía JNDI la información de configuración especificada por los tags env-entryn La información residirá bajo el contexto java:comp/envn La implementación del servidor de aplicaciones web puede

usar cualquier tipo de servicio accesible vía JNDI para mantener la información (LDAP, uno propietario, etc.)

n Ejemplo de acceso a un parámetro de configuraciónContext context = new javax.naming.InitialContext();

String generatorClassName =

(String) context.lookup("java:comp/env/" +

" AccountFacadeDelegateFactory/delegateClassName");

Page 14: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

env-entry (3)

n Como vimos en el tema 2, para no depender de la fuente de la que se leen los parámetros de configuración, todas las clases acceden a los parámetros mediante

ConfigurationParametersManager

<<stat ic>> - parameters : Map

- ConfigurationParametersManager()<<static>> + getParameter(name : String) : String

(en es.udc.fbellas.j2ee.util.configuration)

n Permite leer los parámetros de configuración del fichero ConfigurationParameters.properties o vía JNDI

n ConfigurationParameters.properties sólo debería usarse en tests de unidad desde la línea de comandos

Page 15: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

env-entry (y 4)

n ConfigurationParametersManagern Incluye bloque static para tratar de leer ConfigurationParameters.properties

n Si lo puede leer, inserta los parámetros en el mapa parameters

n Si no lo puede leer, asume configuración vía JNDIn getParameter comprueba si el parámetro está en el mapa

n En caso afirmativo, lo devuelven En caso negativo, lo recupera vía JNDI (prefijándole java:comp/env/ al nombre pasado como parámetro) y lo deja cacheado en el mapa parameters

Page 16: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.util.struts.action.DefaultActionForm: Motivación (1)

n java.util.Localen Un objeto Locale representa una asociación idioma y país

(y opcionalmente una variante), que se puede usar paran Imprimir correctamente fechas, números, monedas, etc. según

el Locale seleccionadon 19/4/02 en Español/España es 4/19/02 en Inglés/USAn Ej.: 12.345,67 en Español/España es 12,345.67 en Inglés/USA

n Aceptar entrada de datos sensible al idioma y paísn 12.345,67 ó 12345,67 en Español/España son correctos (e

iguales) como doubles

n Seleccionar el fichero de mensajes en las aplicaciones que usan ficheros de mensajes

n Struts mantiene una instancia de Locale en la sesiónn Atributo org.apache.struts.Globals.LOCALE_KEYn Cada usuario conectado a la aplicación web puede tener un Locale distinto

Page 17: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.util.struts.action.DefaultActionForm: Motivación (y 2)

n Típicamente es necesario acceder al Locale del usuario en los ActionForms y en las accionesn org.apache.struts.action.Action dispone del

método getLocale(HttpServletRequest)n org.apache.struts.action.ActionForm no dispone

de este método

n es.udc.fbellas.j2ee.util.action.DefaultActionFormn Por comodidad, define el método getLocale(HttpServletRequest)

n Todos los ActionForms derivarán de DefaultActionForm

Page 18: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

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

public abstract class DefaultActionForm extends ActionForm {

protected Locale getLocale(HttpServletRequest request) {

HttpSession session = request.getSession(false);

if (session == null) {return Locale.getDefault();

}

Locale locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);

if (locale == null) {return Locale.getDefault();

} else {return locale;

}

}

}

Page 19: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Plantillas (1)

n En MiniBank, todas las páginas JSP tienen un mismo layout (disposición)

Título

Cabecera

Lista de enlaces Contenido

Pie de página

Page 20: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Plantillas (2)

n La cabecera, la lista de enlaces y el pie de página son iguales en todas las páginas, pero podrían ser distintos

n En principio, todas las páginas JSP podrían tener esta estructuran Títulon Tabla (ancho = 100%) con una fila y una columna, que hace

un <%@ include file=“DefaultHeader.jsp”>

n Tabla (ancho = 100%) con una fila y dos columnasn Columna 1: ancho = 17%, alto=470, <%@ includefile=“DefaultSidebar.jsp”>

n Columna 2: ancho = 83%, alto=470, contenido propio

n Tabla (ancho = 100%) con una fila y una columna, que hace un <%@ include file=“DefaultFooter.jsp”>

Page 21: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Plantillas (3)

n Probleman Una vez en producción, se decide cambiar el layout

Título

Cabecera

Lista de enlaces

Contenido

Pie de página

n Ahora la segunda tabla tiene dos filas y una columnan ¡ Necesitamos cambiar todas las páginas JSP !

Page 22: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Plantillas (y 4)

n ¿ Cuál es la causa del problema ?n Se ha hecho copy-n-paste del layout en cada página JSP

n ¿ Cuál es la solución ?n Tags JSP que permitan

n Definir una plantilla (template), es decir, un layout parametrizable

n Construir instancias de la plantilla

n Caso particular del patrón Composite View (Core J2EE Patterns)

n Struts proporciona un sencillo conjunto de tags que permite definir e instanciar plantillas

n En una aplicación grande, normalmente habrá varias plantillas

Page 23: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

DefaultTemplate.jsp (1)<%-- Struts tag libraries. --%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %><%@ taglib prefix="template" uri="/struts-template.tld" %><%@ taglib prefix="html" uri="/struts-html.tld" %>

<%-- Start of HTML. --%>

<html:html locale="true">

<fmt:setLocalevalue='${sessionScope["org.apache.struts.action.LOCALE"]}'scope="session"/>

<%-- HTML header. --%>

<head><title><template:get name="title"/>

</title><meta http-equiv="Content-Type“

content="text/html; charset=iso-8859-1"></head>

Page 24: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

DefaultTemplate.jsp (2)<%-- Start of HTML body. --%>

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

alink="#000ee0">

<%-- Body header. --%>

<table width="100%" border="0">

<tr>

<td>

<template:get name="header"/></td>

</tr>

</table>

<hr>

Page 25: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

DefaultTemplate.jsp (3)<%-- Sidebar and body content. --%>

<table width="100%" border="0">

<tr valign="top">

<td width="17%" height="470" bgcolor="#CCFFCC"> <template:get name="sidebar"/>

</td>

<td width="83%" height="470">

<table width="100%" border="0">

<tr valign="middle">

<td height="470"><template:get name="content"/>

</td>

</tr>

</table>

</td>

</tr></table>

<hr>

Page 26: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

DefaultTemplate.jsp (y 4)<%-- Body footer. --%>

<table width="100%" border="0">

<tr>

<td><template:get name="footer"/>

</td>

</tr>

</table>

<%-- End of HTML body. --%>

</body>

<%-- End of HTML. --%>

</html:html>

Page 27: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Welcome.jsp<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

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

<template:insert template="DefaultTemplate.jsp">

<template:put name="title" direct="true"><fmt:message key="Welcome.title"/>

</template:put>

<template:put name="header" content="DefaultHeader.jsp" />

<template:put name="sidebar" content="DefaultSidebar.jsp" />

<template:put name="content" direct="true">

<div align="center"><font face="Arial, Helvetica, sans-serif" size="+3"

color="#000099">

<fmt:message key="Welcome.welcome"/></font>

</div>

</template:put>

<template:put name="footer" content="DefaultFooter.jsp" />

</template:insert>

Page 28: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (1)

n DefaultTemplate.jsp define y parametriza la plantilla mediante tags template:get

n Welcome.jsp usa el tag template:insert para instanciaruna página JSP (en tiempo de ejecución) a partir de la plantilla, especificando el contenido de cada una de sus partes (tag template:put)

n Es importante observar que los tags de HTML: html, head y body sólo aparecen en la plantillan Si apareciesen en el resto de páginas, las páginas resultantes

serían incorrectas en HTMLn <html:html locale="true">

n Aparte de generar el correspondiente tag HTML, inserta el Localeen la sesión (si no lo estaba ya, y creando la sesión si es preciso) en base a la cabecera Accept-Language de la petición HTTPn Los navegadores se pueden configurar para que envíen en las

peticiones HTTP una lista de idiomas (en orden de preferencia)

Page 29: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (y 2)

n fmt:setLocalen Permite fijar un Localen En el código se usa para fijar el Locale que usa JSTL al

mismo valor que usa Strutsn Véase el código fuente de DefaultTemplate.jsp en J2EE-

Examples para más información

n Este truco dejará de ser necesario cuando Struts esté integrado con JSTL

n Tiles (Struts 1.1)n Versión mejorada de la librería “template”n Permite definir “pantallas” en XML (con herencia)n Evita la típica necesidad de escribir “dos páginas JSP por

cada pantalla” (ver más adelante)

Page 30: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo transferencia (1)

Page 31: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo transferencia (y 2)

Page 32: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Implementación transferencia

n Formularion Transfer.jsp: instancia la plantillan TransferContent.jsp: sección content

n Convenio seguido en los ejemplos para formularios y páginas de visualización de resultadosn XXX.jsp (instancia plantilla) y XXXContent.jsp (sección content),

excepto que la sección content sea muy pequeña (ej.: Welcome.jsp)

n ActionFormn es.udc.fbellas.j2ee.minibank.http.view.actionforms

.TransferForm

n Acciónn es.udc.fbellas.j2ee.minibank.http.controller.actio

ns.TransferAction

n Usa la fachada del modelo para realizar la transferencian Si error => forward a Transfer.jspn En otro caso => sendRedirect a SuccessfulOperation.jsp

Page 33: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Transfer.jsp<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

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

<template:insert template="DefaultTemplate.jsp">

<template:put name="title" direct="true"><fmt:message key="Transfer.title"/>

</template:put>

<template:put name="header" content="DefaultHeader.jsp" />

<template:put name="sidebar" content="DefaultSidebar.jsp" />

<template:put name="content" content="TransferContent.jsp"/>

<template:put name="footer" content="DefaultFooter.jsp" /></template:insert>

Page 34: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

TransferContent.jsp (1)<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %><%@ taglib prefix="html" uri="/struts-html.tld" %>

<div align="center"><html:errors property="org.apache.struts.action.GLOBAL_ERROR"/></div>

<p><p>

<html:form action="Transfer.do" focus="sourceAccountIdentifier">

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

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

<fmt:messagekey="TransferContent.sourceAccountIdentifier"/>

</th><td align="left" width="50%">

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

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

</tr>

Page 35: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

TransferContent.jsp (y 2)<tr>

<th align="right" width="50%"><fmt:message

key="TransferContent.destinationAccountIdentifier"/></th><td align="left" width="50%">

<html:text property="destinationAccountIdentifier“size="16" maxlength="16"/>

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

</tr>

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

<fmt:message key="AccountAttributes.amount"/></th><td align="left" width="50%">

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

</td></tr>

...

Page 36: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms.TransferForm (1)

public class TransferForm extends DefaultActionForm {

private String sourceAccountIdentifier;

private Long sourceAccountIdentifierAsLong;

private String destinationAccountIdentifier;private Long destinationAccountIdentifierAsLong;

private String amount;

private double amountAsDouble;

public TransferForm() {

reset();}

public String getSourceAccountIdentifier() {

return sourceAccountIdentifier;

}

public Long getSourceAccountIdentifierAsLong() {

return sourceAccountIdentifierAsLong;

}

Page 37: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms.TransferForm (2)

public void setSourceAccountIdentifier(

String sourceAccountIdentifier) {

this.sourceAccountIdentifier = sourceAccountIdentifier.trim();

}

public String getDestinationAccountIdentifier() {

return destinationAccountIdentifier;

}

public Long getDestinationAccountIdentifierAsLong() {

return destinationAccountIdentifierAsLong;}

public void setDestinationAccountIdentifier(

String destinationAccountIdentifier) {

this.destinationAccountIdentifier =destinationAccountIdentifier.trim();

}

Page 38: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms.TransferForm (3)

public String getAmount() {

return amount;

}

public double getAmountAsDouble() {

return amountAsDouble;

}

public void setAmount(String amount) {

this.amount = amount.trim();}

public void reset(ActionMapping mapping,

HttpServletRequest request) {

reset();

}

public ActionErrors validate(ActionMapping mapping,

HttpServletRequest request) {

ActionErrors errors = new ActionErrors();

Page 39: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms.TransferForm (y 4)

sourceAccountIdentifierAsLong = new Long(PropertyValidator.validateLong(errors,

"sourceAccountIdentifier", sourceAccountIdentifier,true, 1, Long.MAX_VALUE));

destinationAccountIdentifierAsLong = new Long(PropertyValidator.validateLong(errors,

"destinationAccountIdentifier",destinationAccountIdentifier, true, 1, Long.MAX_VALUE));

amountAsDouble = PropertyValidator.validateDouble(errors,"amount", amount, true, 0.01, Double.MAX_VALUE,getLocale(request));

return errors;

}

private void reset() {sourceAccountIdentifier = null;sourceAccountIdentifierAsLong = null;destinationAccountIdentifier = null;destinationAccountIdentifierAsLong = null;amount = null;

}

}

Page 40: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (1)

n Se ha usado String como tipo en los métodos getXXX/setXXX para las propiedades sourceAccountIdentifier, destinationAccountIdentifier y amountn En general, se debe hacer así cuando el usuario teclea la

entradan Si se hubiesen utilizado los tipos lógicos (Long, Long y double), y el usuario teclea un número en formato no apropiado para los correspondientes editores de propiedades (ej.: números erróneos, blancos al principio, blancos al final, signos separadores de miles y decimales, etc.), la invocación del método setXXX haría que la propiedad tomase valor 0

n Se han definido métodos getXXXAsYYY para facilitar la implementación de las acciones

Page 41: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (y 2)

n Se permite usar los separadores de miles y decimales (según el idioma y país seleccionado) en el campo amountn En validate se usa PropertyValidator.validateDouble para el campo amount

n PropertyValidator.validateDouble usa java.text.NumberFormat para parsear el String

NumberFormat numberFormatter = NumberFormat.getNumberInstance(locale);

propertyValueAsDouble =

numberFormatter.parse(propertyValue).doubleValue();

Page 42: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.TransferAction (1)

public class TransferAction extends DefaultAction {

public ActionForward doExecute(ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/* Get data. */TransferForm transferForm = (TransferForm) form;Long sourceAccountIdentifier =

transferForm.getSourceAccountIdentifierAsLong();Long destinationAccountIdentifier =

transferForm.getDestinationAccountIdentifierAsLong();double amount = transferForm.getAmountAsDouble();

/* Transfer. */ActionErrors errors = new ActionErrors();

try { AccountFacadeDelegateFactory.getDelegate().transfer(

sourceAccountIdentifier, destinationAccountIdentifier,amount);

Page 43: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.TransferAction (2)

} catch (InstanceNotFoundException e) {

Long key = (Long) e.getKey();

if (key.equals(sourceAccountIdentifier)) {errors.add("sourceAccountIdentifier",

new ActionError("ErrorMessages.account.notFound"));

} else {

errors.add("destinationAccountIdentifier",

new ActionError("ErrorMessages.account.notFound"));

}

} catch (InsufficientBalanceException e) {

NumberFormat numberFormatter =

NumberFormat.getNumberInstance(getLocale(request));

errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("ErrorMessages.balance.insufficientBalanceInSource",

numberFormatter.format(e.getCurrentBalance())));

}

Page 44: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.TransferAction (y 3)

/* Return ActionForward. */

if (errors.isEmpty()) {

return mapping.findForward("Success");

} else {saveErrors(request, errors);

return new ActionForward(mapping.getInput());

}

}

}

Page 45: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios

n Cuando se detecta un error que no es específico a un campo del formulario, sino a la ejecución de la acción, se usa ActionErrors.GLOBAL_ERRORcomo nombre de propiedad en el ActionErrors

Page 46: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo búsqueda de cuentas (1)

Page 47: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo búsqueda de cuentas (2)

Page 48: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo búsqueda de cuentas (3)

Page 49: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo búsqueda de cuentas (y 4)

Page 50: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Implementación búsqueda de cuentas

n Formularion FindAccounts.jspn FindAccountsContent.jsp

n ActionFormn es.udc.fbellas.j2ee.minibank.http.view.actionforms.FindAccountsForm

n Acciónn es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction

n Usa la fachada del modelo para realizar una búsqueda por identificador de cuenta (una cuenta) o por identificador de usuario (una colección de cuentas)

n Si error => forward a FindAccounts.jspn En otro caso, deja el resultado en la request y hace un forward a AccountDetails.jsp o UserAccounts.jsp

Page 51: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

FindAccountsContent.jsp (1)<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

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

<html:form action="FindAccounts.do" focus="identifier">

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

<html:hidden property="startIndex" value="1"/>

<html:hidden property="count" value="10"/>

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

<fmt:message key="FindAccountsContent.identifier"/>

</th>

<td align="left" width="50%">

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

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

</tr>

Page 52: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

FindAccountsContent.jsp (y 2)<tr>

<th align="right" width="50%"><fmt:message key="FindAccountsContent.findBy"/>

</th><td align="left" width="50%">

<html:select property="identifierType"><html:option value="ACC_ID">

<fmt:messagekey="AccountAttributes.accountIdentifier"/>

</html:option><html:option value="USR_ID">

<fmt:messagekey="AccountAttributes.userIdentifier"/>

</html:option></html:select><html:errors property="identifierType"/>

</td></tr>

...

Page 53: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios

n html:hiddenn Genera un tag input de tipo hidden en HTML (no es

visible al usuario)n Ej.: <input type="hidden" name="startIndex" value="1">

n En el ejemplo se usan para dar valor a los parámetros startIndex y count, necesarios para realizar búsquedas de cuentas por identificador de usuarion La primera pantalla de resultados empezará en el índice 1 y

tendrá 10 resultados como máximo

n html:select y html:option generan los tags HTML select y option, con el valor actualmente seleccionado (property="identifierType")

Page 54: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.view.actionforms.FindAccountsForm

n startIndex y count no se han definido como Strings dado que el usuario no los tecleará

FindAccountsForm

- identifier : String

- identifierAsLong : Long

- identifierType : String

- startIndex : int

- count : int

+ FindAccountsForm()

+ getIdentifier() : String

+ getIdentifierAsLong() : Long

+ setIdentifier(identifier : String) : void

+ getIdentifierType() : String

+ setIdentifierType(identifierType : String) : void

+ getStartIndex() : int

+ setStartIndex(startIndex : int) : void

+ getCount() : int

+ setCount(count : int) : void

+ reset(mapping : ActionMapping, request : HttpServletRequest) : void

+ validate(mapping : ActionMapping, request : HttpServletRequest) : ActionErrors

- reset() : void

Page 55: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

AccountDetailsContent.jsp (1)<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %><%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %><%@ taglib prefix="html" uri="/struts-html.tld" %>

<table width="35%" border="1" align="center" cellspacing="6">

<tr><th align="left">

<fmt:message key="AccountAttributes.accountIdentifier"/></th><td align="left">

<c:out value="${requestScope.account.accountIdentifier}"/></td>

</tr>

<tr><th align="left">

<fmt:message key="AccountAttributes.userIdentifier"/></th><td align="left">

<c:out value="${requestScope.account.userIdentifier}"/></td>

</tr>

Page 56: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

AccountDetailsContent.jsp (y 2)<tr>

<th align="left">

<fmt:message key="AccountAttributes.balance"/>

</th>

<td align="left"><fmt:formatNumber value="${requestScope.account.balance}"/>

</td>

</tr>

</table>

Page 57: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios

n AccountDetails.jsp(AccountDetailsContent.jsp) espera que en la request exista el objeto account, con atributosn accountIdentifier

n userIdentifier

n balance

n Internacionalizaciónn Queremos que balance se muestre con separadores de

miles y decimalesn fmt:formatNumber formatea un número de acuerdo al Locale seleccionado

Page 58: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

UserAccountsContent.jsp (1)<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %><%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %><%@ taglib prefix="html" uri="/struts-html.tld" %>

<c:choose>

<c:when test="${empty requestScope.accounts}"><div align="center"><fmt:message key="UserAccountsContent.noAccounts"/></div>

</c:when>

<%-- Print current account chunk. --%>

<c:otherwise>

<table width="50%" border="0" align="center" cellspacing="6"><tr>

<th align="center"><fmt:message key="AccountAttributes.accountIdentifier"/>

</th><th align="center">

<fmt:message key="AccountAttributes.balance"/></th>

</tr>

Page 59: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

UserAccountsContent.jsp (2)<c:forEach var="account" items="${requestScope.accounts}"><tr>

<td align="center">

<c:url var="accountDetailsURL" value="FindAccounts.do"><c:param name="identifierType" value="ACC_ID"/><c:param name="identifier“

value="${account.accountIdentifier}"/></c:url>

<a href="<c:out value='${accountDetailsURL}'/>"><c:out value="${account.accountIdentifier}"/>

</a>

</td><td align="center">

<fmt:formatNumber value="${account.balance}"/></td>

</tr></c:forEach></table></c:otherwise></c:choose>

Page 60: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

UserAccountsContent.jsp (y 3)<%-- "Previous" and "Next" links. --%><table width="70%" border="0" align="center" cellspacing="6"><tr>

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

<td align="left"><html:link href="FindAccounts.do" name="previous">

<fmt:message key="Links.previous"/></html:link>

</td>

</c:if>

<c:if test="${!empty requestScope.next}">

<td align="right"><html:link href="FindAccounts.do" name="next">

<fmt:message key="Links.next"/></html:link>

</td></c:if>

</tr></table>

Page 61: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios

n UserAccounts.jsp(UserAccountsContent.jsp) espera que en la request existan (opcionalmente) los objetosn accounts

n Collection de objetos con propiedades accountIdentifier y balance

n previousn Map con los parámetros que requiere el enlace previous

n nextn Map con los parámetros que requiere el enlace next

n NOTAn La generación del enlace para visualizar los detalles de una

cuenta ha quedado algo complejan Implementar un tag JSP a medida habría sido una

alternativa más elegante

Page 62: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (1)

public class FindAccountsAction extends DefaultAction {

public ActionForward doExecute(ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/* Get data. */FindAccountsForm findAccountsForm = (FindAccountsForm) form;String identifierType = findAccountsForm.getIdentifierType();Long identifier = findAccountsForm.getIdentifierAsLong();

/* Do action. */if (FindAccountsForm.ACCOUNT_IDENTIFIER.equals(identifierType)) {

return doFindAccountByAccountIdentifier(mapping, identifier,request);

} else {return doFindAccountsByUserIdentifier(mapping, identifier,

findAccountsForm.getStartIndex(),findAccountsForm.getCount(), request);

}

}

Page 63: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (2)

private ActionForward doFindAccountByAccountIdentifier(ActionMapping mapping, Long accountIdentifier, HttpServletRequest request) throws InternalErrorException {

try {

AccountVO accountVO =AccountFacadeDelegateFactory.getDelegate().

findAccount(accountIdentifier); request.setAttribute("account", accountVO);

return mapping.findForward("FindAccountByAccountIdentifierSuccess");

} catch (InstanceNotFoundException e) {

ActionErrors errors = new ActionErrors(); errors.add("identifier",

new ActionError("ErrorMessages.account.notFound"));saveErrors(request, errors);

return new ActionForward(mapping.getInput());

}}

Page 64: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (3)

private ActionForward doFindAccountsByUserIdentifier(ActionMapping mapping, Long userIdentifier, int startIndex,int count, HttpServletRequest request) throws InternalErrorException {

/* Find accounts by user identifier. */ Collection accountVOs =

AccountFacadeDelegateFactory.getDelegate().findAccountsByUserIdentifier(userIdentifier,

startIndex, count);

if (accountVOs.size() > 0) {request.setAttribute("accounts", accountVOs);

}

/* Generate parameters for previous and next links. */Map previousLinkParameters =

getPreviousLinkParameters(userIdentifier, startIndex,count);

if (previousLinkParameters != null) {request.setAttribute("previous", previousLinkParameters);

}

Page 65: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (4)

Map nextLinkParameters = getNextLinkParameters(userIdentifier, startIndex, count, accountVOs.size());

if (nextLinkParameters != null) {request.setAttribute("next", nextLinkParameters);

}

/* Return ActionForward. */ return mapping.findForward(

"FindAccountsByUserIdentifierSuccess"); }

private Map getPreviousLinkParameters(Long userIdentifier,int startIndex, int count) {

Map linkAttributes = null;

if ( (startIndex-count) > 0 ) {linkAttributes = getCommonPreviousNextLinkParameters(

userIdentifier, startIndex, count);linkAttributes.put("startIndex",

new Integer(startIndex-count));}

return linkAttributes; }

Page 66: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (5)

private Map getNextLinkParameters(Long userIdentifier,

int startIndex, int count, int currentChunkSize) {

Map linkAttributes = null;

if (currentChunkSize == count) {

linkAttributes = getCommonPreviousNextLinkParameters(

userIdentifier, startIndex, count);

linkAttributes.put("startIndex",

new Integer(startIndex+count));

}

return linkAttributes;

}

Page 67: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.FindAccountsAction (y 6)

private Map getCommonPreviousNextLinkParameters(

Long userIdentifier, int startIndex, int count) {

Map linkAttributes = new HashMap();

linkAttributes.put("identifierType",

FindAccountsForm.USER_IDENTIFIER);

linkAttributes.put("identifier", userIdentifier);

linkAttributes.put("count", new Integer(count));

return linkAttributes;

}

}

Page 68: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo selección de idioma y país (1)

Page 69: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Demo selección de idioma y país (y 2)

Page 70: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Implementación selección de idioma y país (1)

n Cuando se hace clic en “Select locale” debe aparecer el formulario de cambio de idioma y país, mostrando los valores anteriormente seleccionadosn Hasta ahora, los formularios estudiados mostraban las

entradas en blanco o con valores por defecto la primera vez que se accedía a ellos

n Esta nueva situación es muy frecuente cuando se permite modificar datos a través de un formulario (ej.: información de registro en una aplicación con usuarios registrados)

Page 71: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Implementación selección de idioma y país (y 2)

n “Select locale” es un enlace a EditLocale.don EditLocale.do

n Acción: EditLocaleAction

n ActionForm: SelectLocaleForm

n EditLocaleAction establece los valores anteriormente seleccionados (Locale actual) en el SelectLocaleForm y hace un forward a SelectLocale.jsp (formulario)

n La URL que invoca el formulario SelectLocale.jspes SelectLocale.don SelectLocale.do

n Acción: SelectLocaleAction

n ActionForm: SelectLocaleForm

n SelectLocaleAction cambia el Locale según los nuevos valores de SelectLocaleForm

Page 72: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

SelectLocaleContent.jsp (1)<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

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

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

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

<tr>

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

<fmt:message key="SelectLocaleContent.language"/>

</th><td align="left" width="50%">

<html:select property="language">

<html:options collection="languages" property="value"

labelProperty="label" />

</html:select>

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

</tr>

Page 73: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

SelectLocaleContent.jsp (y 2)<tr>

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

<fmt:message key="SelectLocaleContent.country"/>

</th>

<td align="left" width="50%"><html:select property="country">

<html:options collection="countries" property="value"

labelProperty="label" />

</html:select>

<html:errors property="country"/>

</td></tr>

...

Page 74: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios

n Aparte de la instancia de SelectLocaleForm, SelectLocale.jsp(SelectLocaleContent.jsp) espera que en la request existan los objetos languages y countries en html:optionsn Cada uno es una Collection de objetos que disponen de

las propiedades value (valor lógico) y label (valor visual)n Se podrían haber usado “n” tags html:option, como en FindAccountsContent.jsp, pero las opciones no aparecerían ordenadas alfabéticamente en el idioma actual, lo que es necesario cuando pueden ser muchas

Page 75: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.EditLocaleAction (1)

public class EditLocaleAction extends DefaultAction {

public ActionForward doExecute(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/*

* Fill "form" (ActionForm) with the values of the user's

* current locale (this way the form (JSP page) presented to

* the user will display his/her current selection).*/

SelectLocaleForm selectLocaleForm = (SelectLocaleForm) form;

Locale locale = getLocale(request);

selectLocaleForm.setLanguage(locale.getLanguage());

selectLocaleForm.setCountry(locale.getCountry());

Page 76: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.EditLocaleAction (y 2)

/*

* Insert list of languages and countries (ordered by current

* language) as attributes in the "request".

*/

request.setAttribute("languages", Languages.getLanguages(locale.getLanguage()));

request.setAttribute("countries",

Countries.getCountries(locale.getLanguage()));

/* Return an "ActionForward" to the form page. */

return mapping.findForward("SelectLocaleForm");

}

}

Page 77: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (1)

n Countries y Languages en es.udc.fbellas.j2ee.minibank.http.view.applicationobjects

n LabelValue en es.udc.fbellas.j2ee.util.struts.view

Languages

<<final, static>> - LANGUAGES : Map<<final, static>> - LANGUAGES_en : List<<final, static>> - LANGUAGES_es : List<<final, static>> - LANGUAGES_gl : List

- Languages()+ getLanguages(languageCode : String) : List

Countries

<<final, static>> - COUNTRIES : Map<<final, static>> - COUNTRIES_en : List<<final, static>> - COUNTRIES_es : List<<final, static>> - COUNTRIES_gl : List

- Countries()+ getCountries(languageCode : String) : List

LabelValue

- label : String- value : String

+ LabelValue(label : String, value : String)+ getLabel() : String+ setLabel(label : String) : void+ getValue() : String+ setValue(value : String) : void

(from view)

n

languageCode : String

n

languageCode : StringlanguageCode : String

languageCode : String

n

n

COUNTRIES

LANGUAGES

Page 78: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (2)public class Languages {

private final static List LANGUAGES_en = Arrays.asList(new LabelValue[] {

new LabelValue("English", "en"),new LabelValue("Galician", "gl"),new LabelValue("Spanish", "es") });

private final static List LANGUAGES_es = ...private final static List LANGUAGES_gl = ...

static {LANGUAGES = new HashMap();LANGUAGES.put("en", LANGUAGES_en);LANGUAGES.put("es", LANGUAGES_es);LANGUAGES.put("gl", LANGUAGES_gl);

}

...

public final static List getLanguages(String languageCode) {return (List) LANGUAGES.get(languageCode);

}}

Page 79: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Comentarios (y 3)

n En una aplicación más realista, los códigos y nombres visuales en los distintos idiomas y países podrían leerse de la BD en el bloque staticn Languages y Countries actuarían como cachén Cada vez que se añadiese un nuevo idioma o país, habría

que recargar la aplicación n Cuando no suele haber cambios, esto no es un probleman En otro caso, es mejor no hacer caché (la implementación de

los métodos getLanguages y getCountries leería de BD)

Page 80: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

es.udc.fbellas.j2ee.minibank.http.controller.actions.SelectLocaleAction

public class SelectLocaleAction extends DefaultAction {

public ActionForward doExecute(ActionMapping mapping,ActionForm form, HttpServletRequest request,HttpServletResponse response)throws IOException, ServletException, InternalErrorException {

/* Get data. */SelectLocaleForm selectLocaleForm = (SelectLocaleForm) form;String language = selectLocaleForm.getLanguage();String country = selectLocaleForm.getCountry();

/* Change locale. */Locale locale = new Locale(language, country);setLocale(request, locale);

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

}

}

Page 81: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (1)

n FindAccountOperationsByDateContent.jspn Requiere desplegables para permitir seleccionar día, mes y

año de las fechas de inicio y fin

<html:select property="startDay">

<html:options name="dateRanges" property="days"/>

</html:select>

Page 82: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (2)

n FindAccountOperationsByDateContent.jsp (cont)n Esta variante de html:options requiere el objeto dateRanges

con la propiedad days, que devuelve una lista (List) con los números correspondientes (se asume que valor visual = valor lógico)n es.udc.fbellas.j2ee.minibank.http.view.applicationobjets.DateRanges

n Dado que los valores visuales son iguales para todos los idiomas, dateRanges puede ser un objeto con scope = application

DateRanges

- days : List

- months : L is t

- years : List

+ DateRanges()

+ getDays() : L ist

+ getMonths() : List

+ getYears() : List

Page 83: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (3)

n FindAccountOperationsByDateContent.jsp (cont)n ¿ Cómo creamos el objeto dateRanges ?

n Alternativa 1:<jsp:useBean id="dateRanges" scope="application"

class="es.udc.fbellas.j2ee.minibank.http.view.applicationobjects.DateRanges"/>

n Desventaja: hay que acordarse de usar este tag en todas las páginas que permitan especificar fechas

n Alternativa 2:n Especializar el Front Controller para que cree el objeto y lo registre

en el ámbito aplicaciónn Es la alternativa usada en el ejemplo

Page 84: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (4)

n FindAccountOperationsByDateContent.jsp (cont)

public class FrontController extends ActionServlet {

public void init() throws ServletException {super.init();

registerApplicationObjects();

}

private void registerApplicationObjects() {

registerApplicationObject("dateRanges", new DateRanges());}

private void registerApplicationObject(String key, Object object) {

getServletConfig().getServletContext().setAttribute(key,

object);

}

}

Page 85: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (5)

n Agrupación de páginas JSP, ficheros HTML, imágenes, etc.n En MiniBank, todos estos componentes cuelgan del

directorio raízn En una aplicación grande es normal agruparlos en

directoriosn Ej.: en un portal personalizable “My”, se podrían tener los

directorios: wizards, services, images, etc.

Page 86: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (6)

n Transferencia bancarian Si la operación se realiza correctamente, se visualiza una

página de “Operación realizada con éxito”n ¿ Y si quisiésemos que esa página informase sobre el nuevo

balance de ambas cuentas ?n Opción 1: Desde TransferAction (controlador) invocamos

sobre la fachada del modelo a transfer (para realizar la acción propiamente dicha) y dos veces a findAccount (para recuperar el nuevo estado de ambas cuentas)

n Opción 2: Refactorizamos transfer para que devuelva el nuevo balance de ambas cuentas en un Custom Value Object o un mapa

n La opción 2 es la correctan Evita copy-n-paste en aplicaciones con varias vistasn Permite ejecutar código transaccionalmenten Es más eficiente en una arquitectura en 3 capasn Una operación de un Session Facade corresponde a un caso de

uso (y no a un “trozo de un caso de uso”)

Page 87: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (7)

n Encontrar cuentas por identificador de usuarion Por cada cuenta se muestra su identificador y su balancen La operación invocada de la fachada del modelo, findAccountsByUserIdentifier, devuelve una colección de AccountVOsn Lo más puro sería que devolviese una colección de Custom

Value Objects o mapas con los atributos requeridos por la vistan Si no hay mucha diferencia entre lo que requiere la vista y el

Domain Value Object (AccountVO, en este caso), es razonable usar este último

Page 88: 4.5 Caso de estudio: diseño e implementación de las capas ... · n Los ejemplos acceden a los objetos DataSourcevía es.udc.fbellas.j2ee.util.sql.DataSource Locator. env-entry (1)

Otros aspectos (y 8)

n Autenticaciónn Proporcionada por el contenedor (servidor de aplicaciones)

n Útil cuando es posible tener un conjunto fijo de usuarios/roles,creados al margen de la aplicación web (ej.: LDAP)

n En web.xml es posible definir roles (ej.: administrador, usuario, etc.) y especificar que a un conjunto de páginas sólo puedan acceder determinados roles

n En el servidor de aplicaciones se configuran las asociaciones <usuario, rol>

n En MiniBank se podría haber usado este mecanismo

n Proporcionada por la aplicaciónn Necesaria cuando la aplicación permite registrar usuarios (ej.:

MiniPortal)n El programador tiene que implementar la lógica de

autenticación