Descripción: Desarrollo de Aplicaciones Móviles Web
2015
Descripción completa
Descripción completa
En los últimos años se está dando un cambio de rumbo en la programación de aplicaciones informáticas: el paso de aplicaciones de escritorio a aplicaciones web. Esto responde por una parte a …Descripción completa
Prueba de Aplicaciones Web-pressmanDescripción completa
Informatica
Descripción completa
Descripción completa
Descripción completa
libro VII desarrollo de aplicaciones conjunto de libros uptDescripción completa
desarrollo de aplicacionesDescripción completa
Xyz DamDescripción completa
Descripción completa
Descripción completa
desarrollo de aplicacionesDescripción completa
vba
Exploración de los problemas particulares de seguridad que presentan las aplicaciones web, y enumeración de los distintos tipos de ataques o amenazas externas a las que se puede enfrentar. D…Descripción completa
Desar sar rol ro l l o de de Ap A p l i c aci ac i o n es Web I
2
DESARROLLO DE APLICACIONES WEB I
ÍNDICE
3
Página
Presentación
5
Red de contenidos
6
Unidad de aprendizaje 1: 1: Modelo Vist a Control ador – Patró Patró n MVC 1.1 Tema 1
: Fundamentos de Struts 2
9
1.1.1. : Arquitectura y Configuración de aplicaciones
Unidad de aprendi zaje zaje 2: Persist encia de datos – Framework Framework IBATIS IBATIS
: Introducción a IBATIS
101
2.1.1. : IBATIS – Introducción
101
2.1.2. : Operaciones básicas de de acceso acceso a base de de datos con
110
2.1 Tema 3
IBATIS 2.2 Tema 4
: Otras operaciones con IBATIS
119
2.2.1. : Otras operaciones y características de IBATIS
119
2.2.2. : Tópicos avanzados de IBATIS IBATIS e Integración Integración con
128
Struts 2
Unidad de aprendi zaje zaje 3: Reportes en Sist emas empresariales 3.1 Tema 5
: Reportes con JasperReport
139
4
3.1.1. : Diseño e implementación de reportes con la
141
herramienta Ireport 3.2 Tema 6
: Struts 2 y JasperReport
3.2.1. : Integración de Struts 2 y JasperReport
142 142
Anexo 1
157
Anexo 2
167
Anexo 3
172
DESARROLLO DE APLICACIONES WEB I
5
PRESENTACIÓN Desarrollo de Aplicaciones Web I pertenece a la línea de Programación y
Desarrollo de Aplicaciones. Es un curso curso de especialidad sólo sólo en la carrera de Computación e Informática. Permite al estudiante concretizar proyectos informáticos web, aplicando conocimientos previos aprendidos en diferentes cursos y poniendo en práctica la teoría adquirida. De esta manera, consolida conocimientos de diversos cursos de especialidad. Es práctico y desarrollado en laboratorio. Se implementarán soluciones web que utilizarán los Frameworks Struts 2 e IBATIS en forma combinada. combinada. El manual para el curso ha sido diseñado bajo la modalidad de unidades de aprendizaje, las que se desarrollan durante semanas determinadas. En cada una de ellas, hallará los logros, que debe alcanzar al final de la unidad; el tema tratado, el cual será ampliamente desarrollado; y los contenidos, que debe desarrollar, es decir, los subtemas. Por último, encontrará las actividades que deberá desarrollar en cada sesión, que le permitirán reforzar lo aprendido en la clase.
El curso es eminentemente práctico y se desarrolla íntegramente en laboratorio. En primer lugar, se inicia con el reconocimiento de los principales patrones de arquitectura de software, destacándose el patrón Model View Controller (MVC). Luego, continúa con la presentación del Framework MVC Struts 2. Se profundiza en sus principales características y componentes. Después, se desarrollan conceptos de persistencia de datos utilizando para ello el Framework IBATIS. Por último, se concluye con la elaboración de reportes empresariales, utilizando la herramienta IReport, el lenguaje jasperReport e integrándolos a aplicaciones web creadas con Struts 2.
6
RED DE CONTENIDOS
Desarrollo De sarrollo de Aplicacion es Web Web 1
Modelo Vista Modelo Vist a Controlador – Patrón MVC
Fundame ntos de Struts 2
Otras Características Struts 2
Persist Pe rsist encia de datos – Framework IBATIS
Introducción a IBATIS
Otras operaciones IBATIS
Reportes en sistemas empresariales
Tema 5 JasperReport
Tema 6 Struts 2 y Jasper
DESARROLLO DE APLICACIONES WEB I
7
UNIDAD DE APRENDIZAJE
1
MODELO VISTA CONTROLADOR – P ATRÓN MVC L OGRO DE LA UNIDAD DE APRENDIZAJE •
•
Al finalizar la unidad, el alumno, utilizando el framework MVC STRUTS 2, implementa una aplicación web que contenga, en su estructura, el componente Action, las principales etiquetas del framework y acceso a base de datos a través de un pool de conexiones. Al finalizar la unidad, unidad, el alumno se integra a un equipo de trabajo trabajo que refleja en su estructura los roles de un equipo de proyecto de desarrollo de software.
TEMARIO
1.1 Tema 1 : Fundamentos de Struts 2 1.1.1. : Arquitectura y Configuración de aplicaciones 1.1.2. : La clase Action 1.1.3. : Librerías de etiquetas de Struts 2 1.1.4. : Internacionalización Internacionalización – I18N 1.2 Tema 2 : Acceso optimizado a base de datos y otras características características de Struts 2
1.2.1. : Uso de un un Pool de conexiones para acceso acceso a la fuente fuente de datos 1.2.2. : Librería de Etiquetas de Struts 2 – Principales componentes. 1.2.3. : Patrón Composite View – Struts 2 Tiles ACTIVIDADES CTIVIDADES PROPUESTAS PROPUESTAS •
Los alumnos implementan una aplicación web básica, utilizando las principales características del framework MVC Struts 2.
1.1 1.1 Fundamentos Fundamentos de Strut Strutss 2
8
Struts 2 es un framework que implementa el patrón de arquitectura MVC en Java.
Éste organiza de manera independie independiente nte las capas: Model (Objetos del Modelo Modelo del Negocio), View View (interfaz con con el usuario usuario u otro sistema) y la capa Controller (controlador del flujo de la aplicación. Se muestra, a continuación, el esquema básico de funcionamiento de esta arquitectura. La capa Model en Struts 2 inicia con los componentes Action. Debajo de éstos, se tendrán diversos componente componentes: s: 9 9
Services (Lógica pura de negocio) DAOs (objetos de persistencia de datos), entre otros.
Se muestra, a continuación, el esquema básico de la arquitectura MVC implementado por el framework Struts 2.
Figura 1.1
Una característica típica de la capa View de Struts 2 es el uso de unos componentes especiales denominados Results. Éstos normalmente son representados por una página JSP; sin embargo, puede constituir, también, flujos de bytes, objetos del framework Tiles, etc.
1.1. 1.1.1. 1. Arqu itectura itectu ra y conf igur ación de aplicaciones aplicacio nes La arquitectura MVC funciona en Struts 2 básicamente de la siguiente manera: a través de un navegador se genera una solicitud. Ésta es capturada por la capa Controller (implementada por el componente FilterDispathcher representado por un único filtro especializado). Este filtro analizará la solicitud y verificará si el componente invocado se encuentra registrado en el archivo de configuración XML de Struts 2. Éste tiene por defecto el nombre struts.xml.
DESARROLLO DE APLICACIONES WEB I
9
El componente invocado, normalmente un Action de Struts 2, instanciará y/o utilizará diversos objetos de negocio para concretar la tarea solicitada. Según el resultado que retorne el componente Action, la capa Controller derivará la respuesta generada a un objeto Result (normalmente una página JSP).
1.1.1.1. Ejercicio 1: Aplicación web básica de Struts 2 Se probará una aplicación web con los componentes mínimos para el correcto funcionamiento funcionamiento del framework Struts 2. a) Paso 1: mportar el archivo struts2-blank-2.1.8.1.war struts2-blank-2.1.8.1.war Al descargar el framework struts2 ,se tendrá acceso a una aplicación web de prueba, que cuenta con las características mínimas para que pueda ser ejecutada. Esta aplicación viene empaquetada empaquetad a dentro del archivo struts2-blank-2.1.8.1.war. struts2-blank-2.1.8.1.war. Luego, de importarla, se visualizará un proyecto web, tal como se muestra a continuación: continuación:
1
2
Notas: 1) El principal archivo de configuración del Framework es el archivo struts.xml. En él, se registrarán sus principales
10
componentes. Se inicia esta sesión con el registro de la clase Action. 2) Puede observar las librerías mínimas con las que todo proyecto basado en Struts 2 debería contar. Dentro de ellas, destaca el archivo struts2-core-2.1.8.1.jar. struts2-core-2.1.8.1.jar.
b) Paso 2: Revisar el archivo web.xml
xml ver si on="1.0" en encod codii ng ng= ="UTF-8"? > St r ut s Bl Bl ank di spl ay ay-- na nam me> s t r u t s 2< 2 f i l t er - name> or g. apache che. st r ut s2. s2. di spa spat che cher . ng. f i l t er . St r ut sPr sPr epar eAndExecut cut eFi l t er f i l t er er - c l as s > f i l t er er > s t r u t s 2< 2 f i l t er - name> n>/ * ur l - pat t er n> n> f i l t er - mappi ng> i ndex. dex. ht ml wel co com me- f i l e> wel c om ome- f i l e- l i s t > web- app app> >
Notas: 1) Note el registro del filtro controlador del framework Struts 2. Este componente “atrapará” todas las solicitudes (request) generadas desde un cliente, dado que tiene como alias /*.
c) Paso 3: Ejecutar la aplicación
1
DESARROLLO DE APLICACIONES WEB I
d) Paso 4: ¡Excelente!, ha culminado culminado el proceso de probar probar exitosamente la aplicación web struts2-blank-2.1.8.1 struts2-blank-2.1.8.1
1.1.2. La clase Ac ti on
11
12
Un action es, en Struts 2, el primer componente de la capa Model dentro de la arquitectura MVC. Un actions realiza básicamente tres pasos dentro de una aplicación web. En primer lugar, recibe las solicitudes ( request) enviadas por un cliente y realiza el trabajo inicial para atenderla. Es el componente que interactúa con la capa controladora controladora y la capa capa view. En segundo lugar, lugar, actúa como un transportador natural de datos entre el objeto request y los componentes de la capa view, esto gracias a las características de transferencia automática de datos que tiene struts 2 entre estos. Finalmente, apoya al framework determinando qué result será retornado en la respuesta que se genere a la solicitud realizada. Se detalla, a continuación, un ejercicio, en el cual se apreciarán los principales componentes componentes de la arquitectura MVC utilizando Struts 2. 1.1.2.1. Ejercicio 1: Funcionalidad de Logueo Versión 1 Se simulará la funcionalidad de logueo con los componentes básicos del framework Struts 2 y sin acceso a base de datos. a) Paso 1: Copiar las principales librerías y archivos de configuración configuración al proyecto web funcionalidadLogueov funcionalidadLogueov1_Inicial 1_Inicial
1
2
DESARROLLO DE APLICACIONES WEB I
13
Notas: 1) Observe que solo se puede copiar el archivo struts.xml dentro de la carpeta src, utilizando la vista Navigator . 2) Distinga las principales principales librerías librerías y archivos de configuración configuración en las ubicaciones correctas: librerías en la carpeta lib lib y archivo de configuración struts.xml en la carpeta src junto a los archivos fuente. b) Paso 2: Registrar el filtro controlador de Struts 2 dentro del archivo web.xml s t r u t s 2< 2 f i l t er - name> or g. apache che. st r ut s2. s2. di spa spat che cher . ng. f i l t er . St r ut sPr sPr epar eAndExecut cut eFi l t er f i l t er er - c l as s > f i l t er er > s t r u t s 2< 2 f i l t er - name> n>/ * ur l - pat t er n> n> f i l t er - mappi ng>
c) Paso 3: Crear el primer componente Struts 2 de la aplicación, la clase LogueoAction
1
Notas: 1) Agregue el paquete aprendamos.java.action y, dentro de él, genere la clase LogueoAction. La clase LogueoAction debe contar con la siguiente lógica:
14
endamos. j ava. ava. act act i on; package apr end public class Logue LogueoA oAct ct i on {
sua ar i o; private St r i ng usu private St r i ng cl ave; suar i o( ) { public St r i ng get Usua sua ar i o; return usu } set Usua suar i o( St r i ng usua suar i o) { public void set sua ar i o = usuar usuar i o; this. usu } public St r i ng get Cl ave( ) { return cl ave;
} set Cl ave( St r i ng cl cl ave) { public void set ave; this. cl ave = cl ave; } xecutt e( ) { public St r i ng execu St r i ng vi s t a =" ex exi t o" ; a; return vi s t a; } }
d) Paso 4: Registrar la clase LogueoAction en el archivo struts.xml 1 package package> >
>/ l ogueo. j s p r es ul ul t > >/ bi enveni da. j s p r es ul ul t >
Notas: 1) El “alias” de la clase action es logueo; por lo tanto, debe modificar el archivo logueo.jsp. Ya no invocará a la clase LogueoServlet sino a LogueoAction.
DESARROLLO DE APLICACIONES WEB I
15
e) Paso 5: Ejecutar la aplicación web 1
Notas: 1) Se puede observar en el url que el alias invocado es logueo. Recuerde que en Struts 2 todas las solicitudes son atrapadas por el filtro controlador del framework . Éste invocará al action respectivo sobre la base del registro realizado en el archivo struts.xml. f) Paso 6: ¡Bien!, ha culminado la funcionalidad de logueo
versión 1
1.1.2.2. Ejercicio 2: Funcionalidad Funcionalidad de Logueo Versión Versión 2 Se efectúa la funcionalidad de logueo con los componentes básicos del framework e implementando los patrones de diseño DAO (Data Access Object), Service y Business Delegate . a) Paso 1: Modificar la clase MySqlClienteDAO y verificar su correcta relación con las clases que implementan el patrón de diseño DAO.
16
Dentro de la clase MySqlClienteDAO, debe modificar el método buscaPorUsuario. Complete el código con la lógica mostrada a continuación: / / ej ec ecu ut amos Resul esul t Set r s=pst . exec execu ut eQuery( ) ; / / si hay da dat os, r ecu cup per amos un un r egsi t r o if( r s . next ( ) ) { obj obj obj obj obj obj obj obj
Cl Cl Cl Cl Cl Cl Cl
i i i i i i i
ent ent eDTO = new Cl i ent eDTO( ) ; ent eDTO. set set Usua suar i o( r s. get St r i ng( 1) ) ; ent eDTO. set set Cl ave( r s. get St r i ng( 2) ) ; ent eDTO. set set Nombr e( r s. get St r i ng( 3) ) ; ent eDTO. set set Suel do( r s. get Doubl e( 4) ) ; ent eDTO. set set Sexo( r s. get St r i ng( 5) ) ; ent eDTO. set set Fecn Fecna ac( r s. get Dat e( 6) ) ;
} c n. n. c l os e( e( ) ;
9
El patrón de diseño DAO ( Data Access Object) permite que un componente pueda acceder a diferentes orígenes de datos de manera independiente y transparente. En este proyecto, se cuentan con componentes DAO para acceder al motor de base de datos MySql. Adicionalmente, se podrían contar con DAOs para acceder a otros orígenes de datos, tales como Oracle, Microsoft SQL Server , archivos XML, etc.
9
Por cada entidad dentro del modelo de datos, se debe crear un componente DAO.
Verifique si existe la interface ClienteDAO. Ésta debe ser implementada implementad a por la clase MySqlClienteDAO: ent eDAO { public interface Cl i ent public int r egi st r aCl i ent e( Cl i ent eDTO obj Cl i ent e) throws
Excep xcept i on; scaPor Usuar suar i o( St r i ng usuar suar i o) throws public Cl i ent eDTO buscaPo Excep xcept i on; . . . }
DESARROLLO DE APLICACIONES WEB I
9
17
Una interface permite exponer “al mundo” las operaciones de la clase que la implementa.
Verifique si MySqlClienteDAO es retornado por la fábrica de DAOs para MySql: public class MySql DAOFact or y extends DAOFact or y {
/ / Est a es es una una f ab abrr i ca qu que cr ea DAOs especi especi f i cos par par a Mysq ysqll @Over r i de ent eDAO get get Cl i ent ent eDAO( ) { public Cl i ent / / TODO Aut o- ge gene nerr at ed met ho hod d st ub ySql Cl i ent ent eDAO( ) ; return new MySq }
Verifique si la clase MySqlClienteDAO ha sido “registrada” en la “fábrica de fábricas” DAOFactory:
public abstract class DAOFact or y { public public public public public
static static static static static
final final final final final
int int int int int
MYSQL = 1; ORACLE = 2; DB2 = 3; SQLSERVER = XML = 5;
4;
/ / Ex Exii st i r á un un mét od odo o p por or cad cada a DA DAO qu que e pue pueda da ser cr ea eado do.. / / Ej empl o: / / publ i c ab abst r act Ar t i cu cull oDAO get Ar t i cu cull oDAO( ) ; / / r egi st r amos nuest nuest r os dao daos s ent eDAO get get Cl i ent ent eDAO( ) ; public abstract Cl i ent / / publ i c abst r ac actt Pr oduct oDAO get Pr oduct oDAO( ) ;
chFact ct or y) { public static DAOFact or y get DAOFact or y( int whi chFa chFact ct or y) { switch( whi chFa case MYSQL: return new MySql ySql DAOFact or y( ) ; case XML: return new Xml DAOFact or y( ) ; : case ORACLE Fact or y( ) ; return new Or acl eDAOFact
1
18
Notas: 1) El registro de la clase MySqlClienteDAO MySqlClie nteDAO es la creación de un método abstracto en la clase DAOFactory que retorna a la interface que que implementa implementa MySqlClienteDAO. MySqlClienteDAO.
b) Paso 2: Crear la clase LogueoService y la interface LogueoService_I
1
2 LogueoS eoSer vi ce implements Log LogueoSe oSer vi ce_I ce_I public class Logu
{
/ / Ref er en enci ci amos a l a f ab abrr i ca de de dao daos s par par a mysq ysqll DAOFact or y f abr i c a = DAOFact Fac t or y. getDAOFactory ( DAOFact or y. MYSQL) ; / / Ref er enci amos al dao de l a ent i dad cl i ent e Cl i ent ent eDAO obj Cl i en entt eDAO = f abr i c a. get Cl i ent eDAO( ) ; val i daUsua suar i o( Cl i ent eDTO cl i ent e) throws Excep xcept i on { public Cl i ent eDTO val / / aq aqu ui podr i amos t ener mas l og ogii ca scaPor Usua suar i o( cl i ent e. get Usua suar i o( ) ) ; return obj Cl i ent eDAO. buscaP } }
DESARROLLO DE APLICACIONES WEB I
19
Notas: 1) Agregue el paquete aprendamos.java.action aprendamos.ja va.action y dentro de él genere la clase LogueoAction. 2) Un servicio es un componente, que pertenece a la capa Model del patrón de diseño MVC. Representa, en la programación, programació n, el inicio de la lógica de negocio. Por cada caso de uso de sistema identificado en la aplicación, se debe implementar un un servicio. Éste puede invocar invocar a uno o más más DAOs.
Debe “exponer” las operaciones de la clase LogueoService; por lo tanto, debe crear la interface LogueoService_I LogueoService_I
LogueoServi oServi ce_I ce_I public interface Log
{
val i daUsua suar i o( Cl i ent eDTO cl i ent e) public abstract Cl i ent eDTO val xcept i on; on; throws Excep }
c) Paso 3: Crear la clase PaqueteBusinessDelegate PaqueteBusinessDelegate
1
20
2 Paquet et eBusi eBusi ness ness Del egat egat e { public class Paqu Paquet uet eBusi eBusi nessDel essDel egat egat e( ) { private Paq / / TODO Aut o- gener at ed co con nst r uct or st ub } LogueoS eoSer vi ce_I ce_I get Log LogueoS eoServi ce( ce( ) { public static Log LogueoS eoSer vi ce( ce( ) ; return new Log } / / agr egar aq aqu ui mas l l amad ada as a ot ot r os ser vi ci os }
Notas: 1) Dentro del paquete aprendamos.ja aprendamos.java.service, va.service, genere genere la clase PaqueteBusinessDelegate. 2) Por cada paquete de un modelo de análisis, se debe tener un componente componente BusinessDelegate. BusinessDelegate. Esta clase será invocada invocada por los actions y retornará componentes componentes tipo Service. d) Paso 4: Invocar los componentes de lógica de negocio, desde la clase LogueoService, y crear la sesión web. Genere, dentro dentro de la clase clase LogueoAction, LogueoAction, el el atributo mensaje para poder visualizar posibles “mensajes de error” en la capa de presentación. No debe olvidar crear los métodos setter y getter para el nuevo atributo. LogueoA oAct ct i on { public class Logue sua ar i o; private St r i ng usu private St r i ng cl ave; private St r i ng mensaj e;
public St r i ng get Mensaj saj e( ) { return mensaj e;
} public void set Mensaj e( St r i ng mensaj e) { this. mensaj e = mens aj e;
}
DESARROLLO DE APLICACIONES WEB I
21
Agregue la lógica que permitirá validar los datos ingresados y almacenarlos en la sesión web. xecutt e( ) { public St r i ng execu St r i ng vi s t a =" ex exi t o" ; Syst Sys t em. out. pr i nt l n( " dent r o de de nu nuest r o pr pr i mer act i on on"" ) ; Syst Sys t em. out. pr i nt l n( this. get Us ua uar i o( ) ) ; Syst Sys t em. out. pr i nt l n( this. get Cl ave( ) ) ; / / i nvo voca cam mos a nu nuest r o ser ser vi ci o (l ogi ca de ne negoci o) Log LogueoSe oSer vi ce_I ce_I l ogueoser eoser vi ce = Paqu Paquet et eBusi eBusi ness ness Del egat egat e. getLogueoService ( ) ; Cl i ent ent eDTO usuar suar i oCan oCandi di dat dat o= ent eDTO( ) ; new Cl i ent usua suar i oCandi dat o. set set Usua suar i o( this. get Us ua uar i o( ) ) ; Cl i ent ent eDTO obj obj Usuar suar i o=null; try { obj Usua suar i o = l ogueoser ser vi ce. ce. val val i daUsua suar i o( usua suar i oCandi dat o) ; } catch ( Exce xcept i on e) { / / TODO Aut o- gen enerat erat ed ca catt ch bl bl oc ock k e. pr i nt St ackT ckTr ace( ce( ) ; } suar i o! =null) { if( obj Usua suar i o. get Cl ave( ve( ) . equal s( this. get Cl ave( ) ) ) { if( obj Usua sesi si on web al est i l o st r ut s 2 / / cr ea eam mos l a se Map< ap l asesi asesi on= on= Act i onC onCont ext . getContext ( ) . get Ses s i on( ) ; l asesi sesi on. put ( " b_usu _usua ar i o" , obj Usua suar i o) ; }else{ vi s t a= a=" e r r o r "; "; ensaj e( " Lo se sen nt i mos, l a cl cl ave es this. set Mensaj i nco corr r ecta" cta")) ; } }else{ vi s t a= a=" e r r o r "; "; ensaj e( "Es un una pe pena, el usu sua ar i o no no exi exi st e! " ) ; this. set Mensaj } a; return vi s t a; }
22
Recuerde que debe utilizar Expression Language (EL) en el JSP logueo.jsp para visualizar el mensaje de error definido en la clase LogueoAction. ${r ${r eque equest st Scope. Scope. mensaj ensaj e} t d> t r >
Recuerde que debe utilizar Expression Language (EL) en el JSP bienvenida.jsp para visualizar los datos del cliente cargados en la sesión web. ${r ${r eque equest st Scope. Scope. mensaj ensaj e} t d> t r >
e) Paso 5: Ejecutar la aplicación Primero, ingrese un usuario inválido.
DESARROLLO DE APLICACIONES WEB I
Luego, ingrese el usuario correcto, pero la clave equivocada.
Por último, ingrese los datos correctamente.
¡Excelente!, ha culminado la funcionalidad de logueo versión 2
23
24
1.1. 1.1.3. 3. Libr erías erías de etiq etiquetas uetas de Struts 2 1.1.3.1. Ejercicio 1: Funcionalidad Funcionalidad de de Logueo Versión Versión 3 Agregue una nueva funcionalidad al logueo implementado, implementado , a través del uso de archivos de recursos y nuevas características del framework Struts 2. a) Paso 1: Definir el archivo de recursos recursos para Struts 2 Se copia el archivo struts.properties dentro de la carpeta src del proyecto.
Se puede observar que, a través de la key struts.custom.i18n.resources, se define la ubicación del archivo de recursos. st r ut s. cust cust om. i 18n. r esou sour ces= ces=ap aprr en end damos. j av ava. a. r ecu ecurr sos. Mi sR sRecu ecurr sos st r ut s. ui . t heme=si mpl e st r ut s. acti on. ext ensi on=acti on, , dudu
b) Paso 2: Agregar nuevas keys al archivo de recursos MisRecursos.properties Puede agregar las keys correspondientes a los mensajes de error del logueo.
DESARROLLO DE APLICACIONES WEB I
25
# Def i ni r emos keys keys y sus r esp espe ect i vo vos s val or es # Una ke key es es un i dent i f i ca cad dor aso asoci ci ad ado o a al guna de descr i pci on #key keys s par par a el l og ogue ueo o : compl et ar l ogueo. t i t ul o = Pa Pag gi na de I ni c i o - Que f ac i l es J EE : ) : ) l ogueo. mensaj saj e. er r or . usua suar i o=Lo sent i mos, el usu sua ar i o i ngr esad sado o no exi s t e : ( l ogueo. mensaj saj e. er r or . cl ave= ve=Es una pena, l a cl ave i ngr esad sada a no
c) Paso 3: Referenciar las keys dentro de la clase LogueoAction Para poder referenciar las keys, la clase LogueoAction debe heredar de la clase ActionSupport. ActionSuppor t. Esto permitirá incluir funcionalidad adicional dentro de la misma.
apr endamos. j ava. va. act act i on; on; package apr import j ava. ut i l . Map;
opensym symphon phony. y. xwor k2. Act i onC onCont ont ext ; import com. open opensym symphon phony. y. xwor k2. Act i onSu onSupp ppor or t ; import com. open apr enda endam mos. j ava. ava. bean bean.. Cl i ent ent eDTO; import apr endamos. j ava. ava. ser vi ce. ce. Log LogueoS eoSer vi ce_I ce_I ; import apr end apr end endamos. j ava. ava. ser vi ce. Paqu Paquet et eBusi eBusi nessDel essDel egat egat e; import apr LogueoA eoAct i on extends Act i onSuppor t { public class Logu sua ar i o; private St r i ng usu private St r i ng cl ave; private St r i ng mensaj e;
Invoque el método getText, heredado de la clase ActionSupport. ActionSupport.
. . . }else{ vi s t a= a=" e r r o r "; "; ensaj e( this. get Text ( this. set Mensaj "l ogueo. mensa sajj e. er r or . cl ave" ) ) ; } }else{ vi s t a= a=" e r r o r "; "; sajj e. er r or . usu sua ar i o" ) ) this. set Mensaj e( this. get Text ( "l ogueo. mensa ; } . . .
26
d) Paso 4: Modificar Modificar el el JSP logueo.jsp Debe referenciar a la librería de etiquetas de struts 2.
<%@ taglib prefix="s" uri="/struts-tags" %>
Transforme las etiquetas html en sus equivalentes equivalentes de Struts 2.
met hod hod= ="post"
>
t d> t r > t d> t d> t r > t d> t d> t r > t d> t r > ${r ${r eque equest st Scope. Scope. mensaj ensaj e} t d> t r > t d> t r > t abl e> s : f o r m>
DESARROLLO DE APLICACIONES WEB I
9
27
Note que se han modificado los nombres de los campos usuario y clave por cliente.usuario y cliente.clave.
e) Paso 5: Referenciar a los campos cliente.usuario y cliente.clave dentro de la clase LogueoAction Agregue el atributo cliente en la clase LogueoAction. LogueoA oAct ct i on extends Act i onSupport { public class Logue
ent eDTO c l i ent e= e =null; private Cl i ent public Cl i ent eDTO get Cl i ent e( ) { e; return c l i ent e;
} set Cl i ent e( Cl i ent eDTO cl i ent e) { public void set this. c l i ent e = cl i ent e; }
Modifique el método execute. xecutt e( ) { public St r i ng execu St r i ng vi s t a =" ex exi t o" ; Syst Sys t em. out. pr i nt l n( " den entt r o d de e nu nuest r o pr pr i mer ac actt i on on"" ) ; Syst Sys t em. out. pr i nt l n( this. c l i ent e e.. get Us ua uar i o( ) ) ; Syst Sys t em. out. pr i nt l n( this. c l i ent e. e . get Cl ave( ) ) ; / / i nvo voca cam mos a n nu uest r o ser ser vi ci o ( l ogi ca de ne negoci o) Log LogueoS eoSer vi ce_I ce_I l ogueoser eoser vi ce = Paqu Paquet et eBusi eBusi ness ness Del egat egat e. getLogueoService ( ) ; Cl i ent ent eDTO usuar suar i oCan oCandi di dat dat o= ent eDTO( ) ; new Cl i ent usua suar i oCandi dat o. set set Usua suar i o( this. get Cl i ent e( ) . get Us ua uar i o( ) ) ; Cl i ent ent eDTO obj obj Usuar suar i o=null; try { obj Usua suar i o = l ogueoser ser vi ce. ce. val val i daUsua suar i o( usua suar i oCandi dat o) ; } catch ( Exce xcept i on e) { / / TODO Aut o- gen enerat erat ed cat cat ch b bll ock e. pr i nt St ackT ckTr ace( ce( ) ; Notas: }
2
suar i o! =null) { if( obj Usua Cl ave if ob Us uar i o. et Cl
. e ual s this. et Cl Cl i en e nt e
. et Cl Cl ave
1
28
1) Los datos son obtenidos a partir del nuevo atributo cliente. 2) Se obtienen nuevamente los datos a partir del atributo cliente. Esta vez invocando al método getCliente(). f) Paso 6: Ejecutar la aplicación Primero, ingrese un usuario inválido.
Luego, ingrese el usuario correcto, pero la clave equivocada.
Por último, ingrese los datos correctamente.
DESARROLLO DE APLICACIONES WEB I
g) Paso 7: ¡Muy ¡Muy buen trabajo!
29
30
1.1.3.2. Ejercicio 2: Funcionalidad Funcionalidad Registro Registro de cliente cliente Se implementa la funcionalidad funcionalid ad indicada, haciendo uso de de las utilidades incluidas en el framework para procesar archivos (en el ejemplo la imagen del cliente) a través de un formulario HTML y gestionarlos dentro de la aplicación web implementada. implementada. a) Paso 1: Importar el proyecto FuncionalidadRegistraImag FuncionalidadRegistraImagen_Inicial.war en_Inicial.war
web
1
Notas: 1) Note que, dentro dentro del proyecto, proyecto, cuenta con el el script de base base de datos FacilitoBaseDatos.sql. En él, se debe verificar que la tabla tbcliente cuenta con un tipo de dato adecuado para almacenar un archivo de cualquier modelo.
DESARROLLO DE APLICACIONES WEB I
31
b) Paso 2: Verificar que la la tabla tbcliente cuente con un campo de tipo longblog
ATABASE SE I F NOT EXISTS f ac a c i l i t o; o; CREATE DATABA USE f ac i l i t o; -- - Def i ni t i on of t abl e ` t bc b c l i ent e` -DROP TABLE I F EXISTS ` t bc l i ent e` ; CREATE TABLE ` t bc l i ent e` ( ` nombr e` varchar( 100) 100) DEFAULT DEFAULT NULL NULL, `suel `suel do` double DEFAULT DEFAULT NULL NULL, `sexo` char( 1) DEFAULT DEFAULT NULL NULL, `f ecnac cnac`` dat et i me DEFAULT DEFAULT NULL NULL, `usu `usua ar i o` varchar ( 15) NOT NOT NULL NULL DEFAULT ' ' , `cl ave` varchar( 15) NOT NOT NULL NULL DEFAULT ' ' , DEFAULT NULL NULL, `f ot o` l ongbl ob DEFAULT `usua ar i o`) PRIMARY KEY ( `usu ) ENG ENGI NE=I nnoDB AU AUTO TO__ I NCREM CREMENT= ENT=5 DEFAULT
1
CHARSET= SET=l at i n1; n1;
Notas: 1) Observe que, en el campo “foto”, se almacenará la imagen asociada al cliente que registrará en su aplicación web.
32
c) Paso 3: Modificar Modificar el archivo archivo nuevoCliente.jsp nuevoCliente.jsp Dentro de la página nuevoCliente.jsp, se debe modificar el formulario HTML. Complete el código con la lógica mostrada a continuación:
1
enct en ct yp ype e="multipart/form-data"
>
Regi st r o de Cl i ent es t d> t r > t d> t d> t r >
. . .
. . . Fot Fot ogr af í a: t d> va t d> t r > t abl e> s : f o r m>
/ > t d>
Notas: 1) Debe utilizar el atributo enctype del formulario con el valor multipart/form-data. multipart/form-data. De esta manera,se habilita el formulario formulario para soportar soportar campos tipo File. File. 2) Agregue la etiqueta file de Struts 2., cuyo nombre es cliente.foto, es decir, hará referencia a un objeto de nombre cliente que cuente con con un atributo llamado llamado foto.
2
DESARROLLO DE APLICACIONES WEB I
33
d) Paso 4: Registrar el alias ingresaCliente ingresaCliente en el archivo struts.xml
1
>/ l i s t ad ado. j s p r es ul ul t >
ac t i on>
Notas: 1) El alias ingresaCliente fue definido en el formulario de la página nuevoCliente.jsp. Note que al invocar este alias se ejecutará dentro de la clase ClienteAction el método registrar. e) Paso 5: Crear el método registrar en la clase ClienteAction ClienteAction
La clase ClienteAction debe contar con la siguiente lógica: apr endamos. j ava. va. act i on; on; package apr import j ava. ut i l . L i s t ;
apr enda endam mos. j ava. ava. bean bean.. Cl i ent ent eDTO; import apr ser vi ce. ce. Cl i ent eSer vi ce_I ce_I ; import apr endamos. j ava. ser apr enda endam mos. j ava. ava. ser vi ce. Paq Paquet uet eBusi eBusi nessDel essDel egat egat e; import apr public class Cl i ent eAct i on {
/ / cr eamos un un at r i but o de t i po Li st a de Cl i ent es Cl i ent ent eDTO c l i ent e; e; Li st c l i ent es ;
...
1
34
... Cl i ent eSer vi ce_I ce_I s er er v i c i oCl i ent e = Paqu Paquet et eBusi eBusi ness ness Del egat egat e. getClienteService ( ) ; regi st r a / / cr ea eam mos el met odo regi e gi s t r a( ) { public St r i ng r eg St r i ng vi s t a =" ex exi t o" ;
2
3 4
try {
s er er vi c i oCl i ent e. r e gi gi s t r aEl Cl i ent e( c l i ent e) e) ; / / l o r et or nado por el se serr vi ci o l o asi gnamos al al at r i but o de t i po Li st a de cl i ent es c l i ent e. e . set Nombr e( " " ) ; c l i ent es = s er er vi c i oCl i ent e. l i st aCl i ent esPor sPor Nombr e( c l i ent e. e . get Nombr e( ) ) ; } catch ( Exce xcept i on e) { / / TODO Aut o- gener at ed cat cat ch bl bl ock e. pr i nt St ackT ckTr ace( ce( ) ; } a; return vi s t a; }
Notas: 1) Se ha definido la variable cliente de tipo ClienteDTO. De manera automática, el Framework instancia el objeto y almacena en él los datos que llegan desde la página nuevoCliente.jsp. Note que en la página nuevoCliente.jsp todos los campos llevan como prefijo en el nombre la palabra cliente, la cual hace referencia a la variable definida en ClienteAction. 2) El objeto servicioCliente es un componente de la lógica de negocio y expone las operaciones que puede realizar la clase ClienteAction. 3) Note que el método método registraCliente registraCliente recibe como como parámetro parámetro el objeto cliente. Dentro de él, deben existir los campos necesarios para poder gestionar la imagen del cliente seleccionada en la página nuevoCliente.jsp nuevoCliente.jsp 4) Una vez registrado el nuevo cliente se “blanquea” el atributo nombre del objeto cliente y se invoca la funcionalidad de listado antes de retornar a la vista respectiva.
DESARROLLO DE APLICACIONES WEB I
35
f) Paso 6: Modificar la clase ClienteDTO La clase ClienteDTO debe contar con la siguiente lógica: public class Cl i ent eDTO implements Ser i al i z ab abl e {
private static final long serialVersionUID = 1L; private private private private private private
St r i ng nombr e; Dat e f ecn ecnac ac;; St r i ng sexo sexo;; sue el do; double su St r i ng usu sua ar i o; St r i ng cl ave;
o; private F i l e f o t o; oCon ontt en entt Ty Typ pe; private St r i ng f ot oC oFii l eName; private St r i ng f ot oF Fot o; private I nput St r eam i s Fo Fot oCont ent ent Type ype( ) { public St r i ng get Fot oCon ontt en entt Ty Type pe;; return f ot oC } Fot oCo oCont ent ent Type( ype( St r i ng f ot oCont ont ent Typ Type) { public void set Fot oCon ontt en entt Ty Type pe = f ot oCon oContt ent ent Type; Type; this. f ot oC }
. . .
Notas: 1) Dado que en la página página nuevoCliente.jsp nuevoCliente.jsp se ha definido definido un campo tipo file con el nombre cliente.foto, es necesario definirlo en la clase ClienteDTO, de modo que se pueda recepcionar la imagen enviada desde el formulario. 2) Es necesario, necesario, también, también, por requerimiento requerimiento del del Framework, definir los campos fotoContentType y fotoFileName. Ambos se “cargarán” de manera automática y proporcionarán importante información relacionada con la variable foto. Adicionalmente, se define la variable isFoto de tipo InputStream, debido a que ésta será utilizada utilizada por el componente MySqlClienteDAO en el registro de la imagen en la tabla tbcliente.
1 2
36
g) Paso 7: Modificar Modificar la la clase clase ClienteService ClienteService La clase ClienteService debe contar con la siguiente lógica en el método registraElCliente: registraElCliente:
obj Cl i ent e) throws Excep xcept i on { public int r egi st r aEl Cl i ent e( Cl i ent eDTO ob / / aqui aqui ag agrr emos u un n poco poco de l og ogii ca / / co com mo sab sabemos que que el el at r i but o i sFo sFott o est est a l l eg egan and do nu nul o / / l o gener amos a par t i r del at r i but o f ot o ( de t i po Fi l e) if( obj Cl i ent e. get Fot o( ) ! =null) {
I nput put St r eam eam t empo = new Fi l eI nput St r eam( obj Cl i ent e. get Fot o( ) ) ; obj Cl i ent e. set set I sFot sFot o( t empo) ; } objj Cl i ent eDAO. r e gi gi s t r aCl i ent e( obj Cl i ent e) ; return ob }
Notas: 1) Si el cliente seleccionó en la página nuevoCliente.jsp nuevoClient e.jsp una imagen, el atributo foto debe ser diferente del valor null. De ser el caso, se crea un objeto temporal de tipo InputStream en base al atributo foto. Luego, se asigna el objeto tempo al atributo isFoto (utilizado en la clase MySqlClienteDAO para grabar la imagen en la tabla tbcliente).
9
Recuerde que el método registraElCliente debe ser “expuesto” registrándolo en la interface ClienteService_I. La clase ClienteService implementa la interface ClienteService_I. ClienteService_I.
1
DESARROLLO DE APLICACIONES WEB I
37
h) Paso 8: Modificar la cla clase se MySqlClienteDAO MySqlClienteDAO La clase MySqlClienteDAO MySqlClienteDAO debe implementar implementar la siguiente lógica lógica en el método registraCliente: xcept i on{ public int r egi st r aCl i ent e( Cl i ent eDTO obj Cl i ent e) throws Excep esul t ado ado =0; int r esul Connect i on cn = MySql DBConn. obtenerConexion ( ) ; St r i ng s ql ql = "i nse serr t i nt o t bcl i ent e( nombr e, su sue el do, se sex xo, f ecn cna ac, " + " us us ua uar i o, c l ave, f ot o) va val ues ( ? , ? , ? , ? , ? , ? , ? ) " ; Pr epar epar edS edSt at ement ent pst = cn. pr epar epar eSt eSt at ement ent ( sql ) ;
1
/ / asi gnamos val val or es a l as i nt er r ogant es pst . set set St r i ng( 1, obj Cl i ent e. get Nombr e( ) ) ; pst . set set Doubl e( 2, obj Cl i ent e. get Suel do( ) ) ; ps t . s et et St r i ng( 3, obj Cl i ent e. get Sexo( ) ) ;
2
/ / no ol vi demos i nse serr t ar l a f ech cha a :) j ava. s ql . Dat e bdf echa= sql . Dat e( obj Cl i ent e. get Fecna cnac() . get Ti me( ) ) ; new j ava. sql pst . set set Dat e( 4, bdf echa cha) ; ps t . s et et St r i ng( 5, obj Cl i ent e. get Us ua uar i o( ) ) ; ps t . s et et St r i ng( 6, obj Cl i ent e. get Cl ave( ) ) ; pst . set set Bi nar ySt ySt r eam( 7, null, 0) ; if( obj Cl i ent e. get Fot o( ) ! =null) {
pst . set set Bi nar ySt ySt r eam( 7, obj Cl i ent e. get I s Fo Fot o( ) , obj Cl i ent e. get I s Fo Fot o( ) . avai l abl e( ) ) ; } / / ej ec ecu ut amos l a se sen nt enci a r esul esul t ado = pst . exec execu ut eUpdat e( ) ; c n. n. c l os e( e( ) ; sul t ado; return r esul }
Notas: 1) Recuerde que para insertar una fecha en base de datos debe convertir las fechas de tipo java.util.Date al tipo java.sql.Date. 2) Por defecto, se asume que no insertará ninguna imagen en el campo foto:
38
pst.setBinaryStream(7, pst.setBinaryStream(7, null,0); Sin embargo, si el valor del atributo es diferente de null, registra la imagen, tomando como base al atributo de tipo InputStream isFoto: pst.setBinaryStream(7, objCliente.getIsFoto(), objCliente.getIsFoto().available());
9
El método
available()
de un objeto de tipo InputStream retorna la cantidad de bytes (el tamaño), en este caso, de la imagen a insertar en la tabla. De esta manera, se envía como tercer parámetro del método setBinaryStream().
DESARROLLO DE APLICACIONES WEB I
i) Paso 9: Ejecutar la aplicación web
Seleccione del listado de Clientes el enlace Nuevo Cliente:
39
40
En la pantalla mostrada, ingrese los campos solicitados.
DESARROLLO DE APLICACIONES WEB I
41
Al hacer clic sobre el botón Registrar, se grabará un nuevo registro en la base de datos y se visualizará nuevamente el listado de Clientes.
42
Se puede verificar el correcto registro de la imagen, utilizando la herramienta MySql Query Browser:
1
Notas: 1) Al hacer clic sobre la lupa, visualizará en una nueva ventana la imagen registrada en la tabla tbcliente. j) Paso 10: ¡Bien!, ha culminado la funcionalidad funcionalidad “registra imagen” exitosamente.
DESARROLLO DE APLICACIONES WEB I
43
1.1.4. 1.1.4. Internacio Intern acionali nalización zación – I18n I18n Tradicionalmente, los desarrolladores de software se centran en construir aplicaciones que resuelvan en forma inmediata problemas de negocio. Mientras hacen eso es fácil y a veces necesario realizar asunciones acerca del lenguaje o lugar de residencia de los usuarios. En muchos casos, estas asunciones son válidas y no hay preguntas sobre quién será la audiencia. Sin embargo, es probable, alguna vez, que se deba reconstruir una aplicación, porque estas asunciones fueron incorrectas. Internacionalización ( I18N) es el proceso de diseñar su software con soporte en tiempo real de múltiples lenguajes y regiones. Dada esta característica, no será necesario rediseñar nuestras aplicaciones cada vez que se necesite soporte para un nuevo lenguaje. Una aplicación que dice tener soporte para internacionalización debe contar con las siguientes características: •
•
•
• •
Puede soportar lenguajes adicionales sin requerir cambios adicionales de código. Los elementos de texto, mensajes e imágenes son almacenados externamente al código fuente. Dependencia culturales de datos, tales como fecha y hora, y valores decimales son correctamente formateados para el lenguaje del usuario y localización geográfica. Caracteres no estándares son soportados. La aplicación puede ser fácilmente adaptada a nuevos lenguajes y regiones.
Cuando se internacionaliza una aplicación, no se puede producirla para elegir qué opciones desea soportar. Se deben implementar todas ellas o el proceso colapsará. Si un usuario visita un sitio web y todos sus textos, imágenes y botones están en el lenguaje correcto, pero los números y fechas no son formateados correctamente, ésta será una experiencia desagradable para el usuario. Asegurar que una aplicación puede soportar múltiples lenguajes y regiones solo es el primer paso. Se deben crear versiones localizadas de la aplicación para cada lenguaje específico y región que debe soportar. Afortunadamente, aquí es donde los beneficios de I18N en la plataforma java se ejecutan. Para aplicaciones aplicaciones que están siendo apropiadamente apropiadamente internacionalizadas, todo el trabajo para soportar nuevos lenguajes o naciones, son externas al código fuente. Una clase locale es una región (usualmente geográfica, pero no necesariamente) que comparte personalizaciones, cultura y lenguaje. Aplicaciones que son escritas para una sola localización son comúnmente referenciadas referenciadas como miopes. miopes . Localización ( L10N) es el proceso de adaptar su aplicación, la cual ha sido internacionalizada apropiadamente con la específica. Para aplicaciones donde el soporte I18N no ha sido planeado o incorporado, incorporado, esto usualmente significa cambios cambios de texto, imágenes imágenes y mensajes que son son incluidos dentro dentro
44
del código fuente. Después de los cambios aplicados, éste debe de ser recopilado. Imagine hacer eso cada vez para una nueva localización soportada. De acuerdo con Richard Gillam, miembro del Grupo de Tecnología Unicote (autor del diseño de muchas de las librerías Java para soporte que los productos que que utilizan trabajen trabajen para I18N), los usuarios esperarán que ellos en su lenguaje nativo. Se pueden obtener experiencias negativas si los usuarios no están satisfechos cuando las asunciones que se realizan son incorrectas. Se debe iniciar planificando, en forma temprana, el soporte para I18N en las aplicaciones.
1.1.4.1. Ejercicio 1: Funcionalidad Funcionalidad Registra imagen con i18N Se agregará nueva funcionalidad al registro de imágenes implementado. La aplicación web soportará el uso de tres idiomas distintos. a) Paso 1: Importar el proyecto FuncionalidadRegistraImag FuncionalidadRegistraImagenI18N_Inicial.war enI18N_Inicial.war
web
1
Notas: 1) Note que, dentro del proyecto, cuenta con el paquete aprendamos.java.recursos y dentro de él cuenta con tres archivos de recursos (archivos .properties) que soportan los
DESARROLLO DE APLICACIONES WEB I
45
idiomas italiano (it), portugués (pt) y español. El primero está configurado en el archivo sin indicador de idioma. Note que los prefijos it y pt o cualquier otro que se desea usar deben ser códigos ISO 639-1.
b) Paso 2: Editar los archivos archivos .properties. Se crearán, crearán, como ejemplos, las keys que serán utilizadas en la página bienvenida.jsp. Defina las keys para el idioma portugués en el archivo MisRecursos_pt.properties
#ke keys ys par par a l a pag pagii na de de bi bi en enve ven ni da key key. usua suar i o = Usu suá ár i o: key. nombr e = No Nom me: key. key. f ecna cnac = dat a de nasci men entt o: key. key. sexo sexo = sexo sexo:: key. key. sal udo = Bem- vi nd ndo o Car Car o usu usuár ár i o, seus dad dados os são:
#keys par a el menu menu. enu. bi enven envenii da = I r à pág ágii na i ni c i al menu. enu. l ogueo ogueo = Vá par a a en entt r ad ada a menu. l i st ado = I r par a a l i s t a
46
Defina las keys para el idioma italiano en el archivo MisRecursos_it.properties
#ke keys ys par par a l a pag pagii na de de bi bi en enve ven ni da key key. usua suar i o = Ut ent e: key. nombr e = No Nom me: key. key. f ecna cnac = Dat a di Nasci t o: key. key. sexo sexo = sesso sesso:: key. key. sal udo = Benven envenut ut o Car o ut ent e, i dat i sono sono::
#keys par a el menu menu. enu. bi enven envenii da = Vai al l a pag agii na di ben benvenu venutt o menu. enu. l ogueo ogueo = I r al l oguei ni menu. l i st ado = I r al l i s t ad a di ni
Defina las keys para el idioma español en el archivo MisRecursos.properties MisRecursos.properties (archivo de recursos por defecto).
#ke keys ys par par a l a pag pagii na de de bi bi en enve ven ni da key key. usua suar i o = Usu sua ar i o: key. nombr e = Nombr e: key. key. f ecna cnac = Fecha de Naci mi en entt o: key. key. sexo sexo = Sexo Sexo:: key. key. sal udo= Bi en enve ven ni do est i mad ado o usu sua ar i o, s us dat os s on on::
#keys par a el menu menu. enu. bi enven envenii da = I r a l a pági na de Bi enve ven ni da menu. enu. l ogueo ogueo = I r al l og ogu ueo menu. l i st ado = I r al l i s t a ad do
1
DESARROLLO DE APLICACIONES WEB I
47
Notas: 1) El archivo de recursos por defecto es aquel que no tiene código ISO asociado a un idioma en particular. Cuando se seleccione en la aplicación web un idioma que no haya sido configurado en ningún archivo de recursos, automáticamente, struts 2 recupera las keys del archivo de recursos por defecto. c) Paso 3: Modificar Modificar el archivo archivo cabecera.jsp