Servlets y JSP - Experto Java

185
Servlets y JSP Índice 1 Introducción a los servlets............................................................................................ 5 1.1 Conceptos básicos de servlets.................................................................................. 5 1.2 Configuración de servlets en aplicaciones web....................................................... 9 1.3 Ejemplos básicos de servlets.................................................................................. 13 1.4 Logging en aplicaciones Java EE con servlets...................................................... 18 2 Ejercicios de introducción a los servlets.................................................................... 20 2.1 Servlet básico......................................................................................................... 20 2.2 Servlet que muestra la fecha y hora actuales......................................................... 20 2.3 Servlet que muestra parámetros de inicio.............................................................. 21 2.4 (*) Configurar logging en servlets......................................................................... 21 3 Procesamiento de peticiones...................................................................................... 23 3.1 Peticiones: HttpServletRequest.............................................................................. 23 3.2 Respuestas: HttpServletResponse.......................................................................... 24 3.3 Procesamiento de peticiones GET y POST........................................................... 24 3.4 Manejo de formularios........................................................................................... 26 4 Ejercicios de procesamiento de peticiones................................................................. 29 4.1 Recogida de parámetros del usuario...................................................................... 29 4.2 Trabajando con redirecciones................................................................................ 29 4.3 (*)Un buscador sencillo......................................................................................... 29 5 Cabeceras y códigos desde servlets............................................................................ 30 5.1 Cabeceras de petición............................................................................................ 30 5.2 Cabeceras de respuesta.......................................................................................... 30 5.3 Variables CGI........................................................................................................ 31 5.4 Códigos de estado HTTP....................................................................................... 33 5.5 Ejemplos................................................................................................................ 33 6 Ejercicios de cabeceras y códigos.............................................................................. 41 Copyright © 2008-09 Depto. CCIA All rights reserved.

Transcript of Servlets y JSP - Experto Java

Page 1: Servlets y JSP - Experto Java

Servlets y JSP

Índice

1 Introducción a los servlets............................................................................................5

1.1 Conceptos básicos de servlets..................................................................................5

1.2 Configuración de servlets en aplicaciones web....................................................... 9

1.3 Ejemplos básicos de servlets..................................................................................13

1.4 Logging en aplicaciones Java EE con servlets...................................................... 18

2 Ejercicios de introducción a los servlets.................................................................... 20

2.1 Servlet básico......................................................................................................... 20

2.2 Servlet que muestra la fecha y hora actuales......................................................... 20

2.3 Servlet que muestra parámetros de inicio.............................................................. 21

2.4 (*) Configurar logging en servlets......................................................................... 21

3 Procesamiento de peticiones...................................................................................... 23

3.1 Peticiones: HttpServletRequest..............................................................................23

3.2 Respuestas: HttpServletResponse..........................................................................24

3.3 Procesamiento de peticiones GET y POST........................................................... 24

3.4 Manejo de formularios...........................................................................................26

4 Ejercicios de procesamiento de peticiones.................................................................29

4.1 Recogida de parámetros del usuario...................................................................... 29

4.2 Trabajando con redirecciones................................................................................ 29

4.3 (*)Un buscador sencillo......................................................................................... 29

5 Cabeceras y códigos desde servlets............................................................................30

5.1 Cabeceras de petición............................................................................................ 30

5.2 Cabeceras de respuesta.......................................................................................... 30

5.3 Variables CGI........................................................................................................ 31

5.4 Códigos de estado HTTP....................................................................................... 33

5.5 Ejemplos................................................................................................................ 33

6 Ejercicios de cabeceras y códigos.............................................................................. 41

Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 2: Servlets y JSP - Experto Java

6.1 Distinguir el navegador..........................................................................................41

6.2 Redirecciones con retardo......................................................................................41

6.3 (*) Loggear variables CGI..................................................................................... 42

7 Manejo de Cookies y de Sesiones.............................................................................. 43

7.1 Cookies.................................................................................................................. 43

7.2 Seguimiento de sesiones........................................................................................ 47

8 Ejercicios de cookies y sesiones.................................................................................55

8.1 Personalizar un sitio web....................................................................................... 55

8.2 Carro de la compra.................................................................................................55

8.3 (*) Mejoras para el carro de la compra.................................................................. 56

9 Contexto y redirecciones............................................................................................ 58

9.1 Contexto global de los servlets.............................................................................. 58

9.2 Otros métodos de comunicación entre servlets......................................................63

10 Ejercicios de Comunicación..................................................................................... 65

10.1 Ejemplo de contexto.............................................................................................65

10.2 Chat con servlets.................................................................................................. 65

11 JSP Básico................................................................................................................ 68

11.1 Introducción a JSP................................................................................................68

11.2 Traducción de los JSP a servlets.......................................................................... 68

11.3 Elementos de JSP ................................................................................................ 69

11.4 Inserción de código en páginas JSP..................................................................... 69

11.5 Directivas de página ............................................................................................ 71

11.6 Acciones............................................................................................................... 73

11.7 Servlets y JSPs..................................................................................................... 75

12 Ejercicios de JSP Básico...........................................................................................77

12.1 Conversor JSP...................................................................................................... 77

12.2 Contador de visitas............................................................................................... 77

12.3 Chat con JSPs....................................................................................................... 78

12.4 Identificador del usuario (*).................................................................................78

13 JavaBeans y lenguaje de expresiones....................................................................... 80

13.1 JavaBeans............................................................................................................. 80

13.2 Lenguaje de expresiones en JSP 2.0 ....................................................................84

Servlets y JSP

2Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 3: Servlets y JSP - Experto Java

14 Ejercicios de Beans y lenguaje de expresiones.........................................................89

14.1 Bean cronómetro.................................................................................................. 89

14.2 Datos de los usuarios............................................................................................89

15 Introducción a las librerías de tags........................................................................... 90

15.1 Conceptos básicos sobre librerías de tags............................................................ 90

15.2 Ejemplo de librería: request................................................................................. 93

15.3 Ejemplo de librería: dbtags.................................................................................. 99

15.4 Otras consideraciones acerca de las librerías de tags.........................................103

16 Ejercicios de introducción a las librerías de tags....................................................106

16.1 Configuración de librerías de tags......................................................................106

16.2 Registro de usuarios........................................................................................... 106

16.3 Listado de usuarios y otras mejoras................................................................... 107

17 JSTL........................................................................................................................109

17.1 Uso de JSTL....................................................................................................... 109

17.2 La librería Core.................................................................................................. 111

17.3 La librería SQL...................................................................................................119

17.4 La librería de internacionalización.....................................................................124

17.5 La librería XML y la librería de funciones........................................................ 126

18 Ejercicios de JSTL..................................................................................................127

18.1 Configurar aplicación web con JSTL.................................................................127

18.2 Registro de usuarios con JSTL...........................................................................127

18.3 Listado de usuarios y otras mejoras con JSTL...................................................128

19 Creación de librerías de tags...................................................................................130

19.1 Consideraciones previas.....................................................................................130

19.2 Tags simples.......................................................................................................131

19.3 Tags con parámetros...........................................................................................133

19.4 BodyTags........................................................................................................... 135

19.5 Tags anidados.....................................................................................................138

19.6 Método simplificado de creación de tags...........................................................141

20 Ejercicios de creación de librerías de tags..............................................................148

20.1 Gestor de tags para un tag que formatee números reales................................... 148

20.2 Configuración y prueba de nuestro tag.............................................................. 148

Servlets y JSP

3Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 4: Servlets y JSP - Experto Java

20.3 (*) Iterador sobre una cadena............................................................................. 149

20.4 (*) Tag files........................................................................................................ 150

20.5 (*) Simple tags................................................................................................... 150

21 Filtros y Wrappers.................................................................................................. 151

21.1 ¿Qué es un filtro?............................................................................................... 151

21.2 Funcionalidades de los filtros.............................................................................152

21.3 Aplicaciones de los filtros.................................................................................. 152

21.4 Configuración de un filtro.................................................................................. 153

21.5 Implementación básica de un filtro.................................................................... 155

21.6 Acceso al contexto............................................................................................. 156

21.7 Ciclo de vida de un filtro....................................................................................157

21.8 Wrappers............................................................................................................ 158

21.9 Ejemplos de filtros............................................................................................. 161

22 Ejercicios de Filtros y Wrappers.............................................................................166

22.1 Filtro de acceso restringido................................................................................ 166

22.2 Restringir el acceso al chat.................................................................................166

22.3 Wrapper de ejemplo (*)......................................................................................166

22.4 Registro de accesos (*).......................................................................................167

23 Comunicación con clientes ricos y AJAX.............................................................. 169

23.1 Servlets y clientes ricos...................................................................................... 169

23.2 Servlets y Javascript: AJAX...............................................................................171

24 Ejercicios de Comunicación................................................................................... 180

24.1 Chat con XML y AJAX (*)................................................................................180

24.2 Applet para el chat (*)........................................................................................181

24.3 Autocompletar con jMaki (*).............................................................................181

25 Roadmap................................................................................................................. 182

25.1 Puntos destacados...............................................................................................182

25.2 Certificación Sun................................................................................................183

25.3 Recursos adicionales.......................................................................................... 184

Servlets y JSP

4Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 5: Servlets y JSP - Experto Java

1. Introducción a los servlets

1.1. Conceptos básicos de servlets

1.1.1. Concepto de servlet

Un servlet es un programa Java que se ejecuta en un servidor Web y construye o sirvepáginas web. De esta forma se pueden construir páginas dinámicas, basadas en diferentesfuentes variables: datos proporcionados por el usuario, fuentes de información variable(páginas de noticias, por ejemplo), o programas que extraigan información de bases dedatos.

Comparado con un CGI, un servlet es más sencillo de utilizar, más eficiente (se arrancaun hilo por cada petición y no un proceso entero), más potente y portable. Con los servletspodremos, entre otras cosas, procesar, sincronizar y coordinar múltiples peticiones declientes, reenviar peticiones a otros servlets o a otros servidores, etc.

1.1.2. Recursos de servlets y JSP

Normalmente al hablar de servlets se habla de JSP y viceversa, puesto que ambosconceptos están muy interrelacionados. Para trabajar con ellos se necesitan tenerpresentes algunos recursos:

• Un servidor web que dé soporte a servlets / JSP (contenedor de servlets y páginasJSP). Ejemplos de estos servidores son Apache Tomcat, Resin, JRun, Java WebServer, BEA WebLogic, etc.

• Las librerías (clases) necesarias para trabajar con servlets / JSP. Normalmente vienenen ficheros JAR en un directorio lib del servidor (common/lib en Tomcat):servlet-api.jar (con la API de servlets), y jsp-api.jar, para JSP. Al desarrollarnuestra aplicación, deberemos incluir las librerías necesarias en el classpath para quecompilen los ficheros (sólo necesitaremos compilar los servlets, no los JSP). Tambiénse puede utilizar el fichero JAR j2ee.jar que viene con Java Enterprise Edition, perono es recomendable si se puede disponer de las librerías específicas del servidor.

• La documentación sobre la API de servlets / JSP (no necesaria, pero sírecomendable)

Para encontrar información sobre servlets y JSP, son de utilidad las siguientesdirecciones:

• http://java.sun.com/j2ee/: referencia de todos los elementos que componen J2EE• http://java.sun.com/products/jsp: referencia para las últimas actualizaciones en JSP• http://java.sun.com/products/servlets: referencia para las últimas actualizaciones en

servlets

Servlets y JSP

5Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 6: Servlets y JSP - Experto Java

1.1.3. Arquitectura del paquete servlet

Dentro del paquete javax.servlet tenemos toda la infraestructura para poder trabajarcon servlets. El elemento central es la interfaz Servlet, que define los métodos paracualquier servlet. La clase GenericServlet es una clase abstracta que implementa dichainterfaz para un servlet genérico, independiente del protocolo. Para definir un servlet quese utilice vía web, se tiene la clase HttpServlet dentro del subpaquetejavax.servlet.http. Esta clase hereda de GenericServlet, y también es una claseabstracta, de la que heredaremos para construir los servlets para nuestras aplicacionesweb.

Cuando un servlet acepta una petición de un cliente, se reciben dos objetos:

• Un objeto de tipo ServletRequest que contiene los datos de la petición del usuario(toda la información entrante). Con esto se accede a los parámetros pasados por elcliente, el protocolo empleado, etc. Se puede obtener también un objetoServletInputStream para obtener datos del cliente que realiza la petición. Lasubclase HttpServletRequest procesa peticiones de tipo HTTP.

• Un objeto de tipo ServletResponse que contiene (o contendrá) la respuesta delservlet ante la petición (toda la información saliente). Se puede obtener un objetoServletOutputStream, y un Writer, para poder escribir la respuesta. La claseHttpServletResponse se emplea para respuestas a peticiones HTTP.

1.1.4. Ciclo de vida de un servlet

Todos los servlets tienen el mismo ciclo de vida:

• Un servidor carga e inicializa el servlet• El servlet procesa cero o más peticiones de clientes (por cada petición se lanza un

hilo)• El servidor destruye el servlet (en un momento dado o cuando se apaga)

1. Inicialización

En cuanto a la inicialización de un servlet, se tiene una por defecto en el método init().

public void init() throws ServletException{

...}

public void init(ServletConfig conf) throws ServletException{

super.init(conf);...

}

El primer método se utiliza si el servlet no necesita parámetros de configuración externos.El segundo se emplea para tomar dichos parámetros del objeto ServletConfig que se le

Servlets y JSP

6Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 7: Servlets y JSP - Experto Java

pasa. La llamada a super.init(...) al principio del método es MUY importante,porque el servlet utiliza esta configuración en otras zonas.

Si queremos definir nuestra propia inicialización, deberemos sobreescribir alguno deestos métodos. Si ocurre algún error al inicializar y el servlet no es capaz de atenderpeticiones, debemos lanzar una excepción de tipo UnavailableException.

Podemos utilizar la inicialización para establecer una conexión con una base de datos (sitrabajamos con base de datos), abrir ficheros, o cualquier tarea que se necesite hacer unasola vez antes de que el servlet comience a funcionar.

2. Procesamiento de peticiones

Una vez inicializado, cada petición de usuario lanza un hilo que llama al métodoservice() del servlet.

public void service(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException

Este método obtiene el tipo de petición que se ha realizado (GET, POST, PUT,DELETE). Dependiendo del tipo de petición que se tenga, se llama luego a uno de losmétodos:

• doGet():

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException

Para peticiones de tipo GET (aquellas realizadas al escribir una dirección en unnavegador, pinchar un enlace o rellenar un formulario que no tengaMETHOD=POST)

• doPost():

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException

Para peticiones POST (aquellas realizadas al rellenar un formulario que tengaMETHOD=POST)

• doXXX(): normalmente sólo se emplean los dos métodos anteriores, pero se tienenotros métodos para peticiones de tipo DELETE (doDelete()), PUT (doPut()),OPTIONS (doOptions()) y TRACE (doTrace()).

3. Destrucción

El método destroy() de los servlets se emplea para eliminar un servlet y sus recursosasociados.

public void destroy() throws ServletException

Servlets y JSP

7Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 8: Servlets y JSP - Experto Java

Aquí debe deshacerse cualquier elemento que se construyó en la inicialización (cerrarconexiones con bases de datos, cerrar ficheros, etc).

El servidor llama a destroy() cuando todas las llamadas de servicios del servlet hanconcluido, o cuando haya pasado un determinado número de segundos (lo que ocurraprimero). Si esperamos que el servlet haga tareas que requieran mucho tiempo, tenemosque asegurarnos de que dichas tareas se completarán. Podemos hacer lo siguiente:

• Definir un contador de tareas activas, que se incremente cada vez que una tareacomienza (entendemos por tarea cada petición que se realice al servlet), y sedecremente cada vez que una termina. Podemos utilizar bloques de códigosynchronized para evitar problemas de concurrencia.

• Hacer que el método destroy() no termine hasta que lo hagan todas las tareaspendientes (comprobando el contador de tareas pendientes)

• Hacer que las tareas pendientes terminen su trabajo si se quiere cerrar el servlet(comprobando algún flag que indique si el servlet se va a cerrar o no).

NotaA partir de la versión 2.5 de la API de servlets se introducen una serie de anotaciones comunespara cualquier componente Java EE (como son los servlets). Podemos utilizar las anotaciones@PostConstruct y @PreDestroy como forma alternativa para definir los métodos deinicialización y destrucción de los servlets. Estas etiquetas nos permitirán que cualquier métodoarbitrario pueda comportarse como init() y destroy() respectivamente. Además, no sóloson aplicables a los servlets, sino que podremos utilizarlas en otros componentes como los EJBs.

1.1.5. Estructura básica de un servlet

La plantilla común para implementar un servlet es:

import javax.servlet.*;import javax.servlet.http.*;

public class ClaseServlet extends HttpServlet{

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

// ... codigo para una peticion GET}

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException

{// ... codigo para una peticion POST

}}

Servlets y JSP

8Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 9: Servlets y JSP - Experto Java

El servlet hereda de la clase HttpServlet. Normalmente se deben sobreescribir losmétodos doGet(), doPost() o ambos, colocando el código que queremos que se ejecutecuando se reciba una petición GET o POST, respectivamente. Conviene definir los dospara distinguir ambas peticiones. En caso de que queramos hacer lo mismo para GET oPOST, definimos el código en uno de ellos, y hacemos que el otro lo llame.

Aparte de estos métodos, podemos utilizar otros de los que hemos visto: init() (parainicializaciones), doXXX() (para tratar otros tipos de peticiones (PUT, DELETE, etc)),destroy() (para finalizar el servlet), etc, así como nuestros propios métodos internos de laclase.

1.2. Configuración de servlets en aplicaciones web

Para instalar un servlet en una aplicación web, se coloca la clase compilada del servletdentro del directorio WEB-INF/classes de la aplicación (respetando también la estructurade paquetes, creando tantos subdirectorios como sea necesario).

De forma alternativa, también podríamos empaquetar nuestros servlets en un JAR y poneresta librería de clases dentro del directorio WEB-INF/lib. De cualquiera de las dos formasla clase del servlet estará localizable para la aplicación. Veremos ahora las formas quetenemos de invocar a ese servlet.

1.2.1. Mapeo de servlets en el fichero descriptor

Los servlets se invocarán cuando desde un cliente hagamos una petición a una URLdeterminada. Para especificar la URL a la que está asociada cada servlet, deberemosconfigurar dicho servlet en el fichero descriptor de despliegue (web.xml).

En primer lugar deberemos introducir una marca <servlet> para declarar cada servlet dela siguiente forma:

<servlet><servlet-name>nombre</servlet-name><servlet-class>unpaquete.ClaseServlet</servlet-class>

</servlet>

Donde <servlet-name> es un nombre identificativo y arbitrario del servlet, y<servlet-class> es la clase del servlet.

NotaAl declarar un servlet, debe indicarse el nombre completo de la clase en la que estáimplementado, incluyendo paquetes y subpaquetes. Esto es así porque en el web.xml notenemos ningún "import" que nos permita desambiguar entre posibles diferentes clases con elmismo nombre.

Una vez declarado nuestro servlet, deberemos mapearlo a una URL. Esto se consigue

Servlets y JSP

9Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 10: Servlets y JSP - Experto Java

mediante las etiquetas <servlet-mapping>:

<servlet-mapping><servlet-name>nombre</servlet-name><url-pattern>/ejemploservlet</url-pattern>

</servlet-mapping>

En la subetiqueta <servlet-name> se pone el nombre del servlet al que se quiere asignarla URL (será uno de los nombres dados en alguna etiqueta <servlet> previa), y en<url-pattern> colocamos la URL que le asignamos al servlet, que debe comenzar con'/'.

NotaDestacamos que primero se colocan todas las etiquetas <servlet>, y luego las<servlet-mapping> que se requieran. En las actuales versiones de los servidores web elorden es indiferente, pero si queremos garantizar la compatibilidad con versiones anteriores,deberemos respetarlo.

Así, con lo anterior, podremos llamar al servlet identificado con nombre accediendo a laURL a la que se encuentra mapeado:

http://localhost:8080/<dir>/ejemploservlet

siendo <dir> el directorio en el que se encuentra el contexto de nuestra aplicación Web.

También podemos asignar en <url-pattern> expresiones como:

<servlet-mapping><servlet-name>nombre</servlet-name><url-pattern>/ejemploservlet/*</url-pattern>

</servlet-mapping>

o como:

<servlet-mapping><servlet-name>nombre</servlet-name><url-pattern>/ejemploservlet/*.do</url-pattern>

</servlet-mapping>

Con el primero, cualquier URL del directorio de nuestra aplicación Web que comiencecon /ejemploservlet/ se redirigirá y llamará al servlet identificado con nombre. Porejemplo, las direcciones:

http://localhost:8080/<dir>/ejemploservlet/unapagina.htmlhttp://localhost:8080/<dir>/ejemploservlet/login.do

acabarían llamando al servlet nombre.

Con el segundo, cualquier llamada a un recurso acabado en .do del directorio/ejemploservlet/ de nuestra aplicación se redirigiría al servlet nombre. Podemos hacerque distintas URLs llamen a un mismo servlet, sin más que añadir varios grupos

Servlets y JSP

10Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 11: Servlets y JSP - Experto Java

<servlet-mapping>, uno por cada patrón de URL diferente, y todos con el mismo<servlet-name>.

Este mismo procedimiento se puede aplicar también si en lugar de un servlet queremostratar una página JSP. Para declarar una página JSP, sustituiremos la etiqueta<servlet-class> por la etiqueta <jsp-file>:

<servlet><servlet-name>nombre2</servlet-name><jsp-file>/mipagina.jsp</jsp-file>

</servlet>

Esta página se podrá mapear a diferentes URLs de la misma forma en la que lo hacemospara un servlet.

1.2.2. Servlet invoker

Hemos visto la forma en la que los servlets se mapean a la URL a la que deberemosacceder para invocarlos. Sin embargo, en algunos casos en los que estemos haciendopruebas rápidas podría venirnos bien poder invocar un servlet sin tener que declararlo enel descriptor de despliegue. Existe en los servidores web un servlet llamado invoker quenos permite hacer esto. Este servlet será quien se encargue de invocar otros servlets sintener que ser configurados.

Para poder utilizar esta característica deberemos habilitar este servlet invoker. Para ellodeberemos editar el fichero web.xml general de Tomcat (se encuentra en el directorio$TOMCAT_HOME/conf/web.xml), y descomentar en él tanto la declaración del servletinvoker, como su mapeo a una URL. La declaración será como se muestra acontinuación:

<servlet><servlet-name>invoker</servlet-name><servlet-class>org.apache.catalina.servlets.InvokerServlet

</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value>

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

</servlet>

Por otro lado, el mapeo por defecto se realiza de la siguiente forma:

<servlet-mapping><servlet-name>invoker</servlet-name><url-pattern>/servlet/*</url-pattern>

</servlet-mapping>

Podemos fijarnos en que este servlet se encuentra mapeado por defecto a la URL/servlet/* (aunque podríamos cambiarla). Es decir, este servlet interceptará todas laspeticiones a nuestra aplicación web que comiencen por /servlet. Lo que se indique a

Servlets y JSP

11Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 12: Servlets y JSP - Experto Java

continuación en la URL, será considerado el nombre del servlet que queremos invocar.

http://localhost:8080/<dir>/servlet/<nombre-clase-servlet>

NotaA partir de Tomcat 6.0 sólo se puede utilizar el servlet invoker en contextos "privilegiados".Para hacer esto deberemos editar también el fichero $TOMCAT_HOME/conf/context.xml ysustituir la etiqueta <Context> por <Context privileged="true">

Por ejemplo, podríamos invocar nuestro servlet con la siguiente URL (recordamos quedeberemos siempre proporcionar el nombre completo de la clase, incluyendo el paquete alque pertenezca):

http://localhost:8080/<dir>/servlet/unpaquete.ClaseServlet

Notar que servlet no corresponde a ningún directorio en nuestra aplicación, sino que setrata de la ruta a la que está mapeado el servlet invoker.

Si hemos declarado nuestro servlet en el descriptor de despliegue, también podremosutilizar el servlet invoker para invocar nuestro servlet mediante su nombre, en lugar deutilizar el nombre de la clase en la que se encuentra implementado:

http://localhost:8080/<dir>/servlet/nombre

Incluso aunque hayamos mapeado nuestro servlet a una URL determinada, si tenemoshabilitado el servlet invoker podremos también utilizarlo de forma alternativa parainvocar nuestro servlet, bien mediante su nombre, o el nombre de su clase. En este casopodremos acceder al servlet de tres formas:

http://localhost:8080/<dir>/servlet/nombrehttp://localhost:8080/<dir>/servlet/unpaquete.ClaseServlethttp://localhost:8080/<dir>/ejemploservlet

ImportanteUtilizar el servlet invoker puede ocasionarnos graves problemas de seguridad, al dejar unapuerta abierta para ejecutar cualquier servlet de nuestra aplicación. Por lo tanto, se desapruebatotalmente su uso, siendo interesante únicamente para hacer pruebas rápidas.

1.2.3. Asignar parámetros de inicio a un servlet o página JSP

El hecho de asignar un nombre a un servlet o página JSP mediante la etiqueta <servlet>

y sus subetiquetas nos permite identificarlo con ese nombre, y también poderle asignarparámetros de inicio. Para asignar parámetros se colocan etiquetas <init-param> dentrode la etiqueta <servlet> del servlet o página JSP al que le queremos asignar parámetros.Dichas etiquetas tienen como subetiquetas un <param-name> (con el nombre delparámetro) y un <param-value> (con el valor del parámetro). Por ejemplo:

Servlets y JSP

12Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 13: Servlets y JSP - Experto Java

<servlet><servlet-name>nombre</servlet-name><servlet-class>ClaseServlet</servlet-class><init-param>

<param-name>param1</param-name><param-value>valor1</param-value>

</init-param><init-param>

<param-name>param2</param-name><param-value>valor2</param-value>

</init-param></servlet>

Para obtener luego los parámetros desde el servlet se utilizagetServletConfig().getInitParameter(nombre) donde nombre es el valor<param-name> del parámetro que se busca, y devuelve el valor (elemento<param-value> asociado), que es de tipo String siempre. Para obtener estos valoresdesde páginas JSP se emplean otros métodos.

Los parámetros de inicio sólo se aplican cuando accedemos al servlet o página JSP através del nombre asignado en <servlet-name>, o a través de la URL asociada en un<servlet-mapping>.

1.2.4. Cargar servlets al inicio

A veces nos puede interesar que un servlet se cargue al arrancar el servidor, y no con laprimera petición de un cliente. Para hacer eso, incluimos una etiqueta<load-on-startup> dentro de la etiqueta <servlet>. Dicha etiqueta puede estar vacía:

<servlet><servlet-name>nombre</servlet-name><servlet-class>ClaseServlet</servlet-class><load-on-startup/>

</servlet>

o contener un número:

<servlet><servlet-name>nombre</servlet-name><servlet-class>ClaseServlet</servlet-class><load-on-startup>2</load-on-startup>

</servlet>

que indica el orden en que el servidor irá cargando los servlets (de menor a mayor valor).

1.3. Ejemplos básicos de servlets

1.3.1. Servlet que genera texto plano

El siguiente ejemplo de servlet muestra una página con un mensaje de saludo: "Este es un

Servlets y JSP

13Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 14: Servlets y JSP - Experto Java

servlet de prueba". Lo cargamos mediante petición GET.

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ClaseServlet extends HttpServlet{

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

PrintWriter out = response.getWriter();out.println ("Este es un servlet de prueba");

}}

Se obtiene un Writer para poder enviar datos al usuario. Simplemente se le envía lacadena que se mostrará en la página generada.

1.3.2. Servlet que genera una página HTML

Este otro ejemplo escribe código HTML para mostrar una página web.

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ClaseServletHTML extends HttpServlet{

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");PrintWriter out = response.getWriter();out.println ("<!DOCTYPE HTML PUBLIC \""+

"-//W3C//DTD HTML 4.0 " +"Transitional//EN\">");

out.println ("<HTML>");out.println ("<BODY>");out.println ("<h1>Titulo</h1>");out.println ("<br>Servlet que genera HTML");out.println ("</BODY>");out.println ("</HTML>");

}}

Para generar una página HTML con un servlet debemos seguir dos pasos:

• Indicar que el contenido que se va a enviar es HTML (mediante el métodosetContentType() de HttpServletResponse):

Servlets y JSP

14Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 15: Servlets y JSP - Experto Java

response.setContentType("text/html");

Esta línea es una cabecera de respuesta, que veremos más adelante cómo utilizar. Hayque ponerla antes de obtener el Writer.

• Escribir en el flujo de salida el texto necesario para generar la página HTML. La líneaque genera el DOCTYPE no es necesaria, aunque sí muy recomendada para que sesepa qué versión de HTML se está empleando.

1.3.3. Servlet que utiliza parámetros de inicialización

Este otro ejemplo utiliza dos parámetros de inicialización externos:

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ClaseServletInit extends HttpServlet{

// Mensaje que se va a mostrar en la paginaString mensaje = "";// Numero de veces que se va a repetir el mensajeint contador = 1;

// Metodo de inicializacion

public void init(ServletConfig conf)throws ServletException{

super.init(conf); // MUY IMPORTANTE

mensaje = conf.getInitParameter("mensaje");if (mensaje == null)

mensaje = "Hola";

try{

contador = Integer.parseInt(conf.getInitParameter("contador"));

} catch (NumberFormatException e) {contador = 1;

}}

// Metodo para procesar una peticion GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");PrintWriter out = response.getWriter();out.println ("<!DOCTYPE HTML PUBLIC \""+

"-//W3C//DTD HTML 4.0 " +

Servlets y JSP

15Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 16: Servlets y JSP - Experto Java

"Transitional//EN\">");out.println ("<HTML>");out.println ("<BODY>");

for (int i = 0; i < contador; i++){

out.println (mensaje);out.println ("<BR>");

}

out.println ("</BODY>");out.println ("</HTML>");

}}

• Se utiliza el método init() con un parámetro ServletConfig para poder tomar losparámetros externos. Es importante la llamada a super al principio del método.

• Mediante el método getInitParameter() de ServletConfig obtenemos dosparámetros: mensaje y contador, que asignamos a las variables del mismo nombre.El primero indica el mensaje que se va a mostrar en la página, y el segundo el númerode veces que se va a mostrar.

• En doGet() hacemos uso de esos parámetros obtenidos, para mostrar el mensaje lasveces indicadas.

1.3.4. Prueba de los ejemplos

Para probar el ejemplo, tendríamos dos posibilidades

• Crear un directorio en webapps para el ejemplo (por ejemplo,webapps/ejemplobasico), y dentro de él:

• Definir un directorio WEB-INF

• Dentro de WEB-INF colocar un fichero web.xml descriptor de la aplicación.Podemos mapear los servlets en este fichero descriptor, como veremos acontinuación.

• Colocar los servlets en el directorio WEB-INF/classes.

• Crear un fichero WAR con la estructura de ficheros y directorios vista en el puntoanterior, y copiar dicho fichero WAR en el directorio webapps de Tomcat

Un ejemplo de fichero web.xml podría ser el siguiente:

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN""http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app><servlet>

<servlet-name>ejemplo1_1</servlet-name><servlet-class>ejemplos.ClaseServlet</servlet-class>

</servlet><servlet>

<servlet-name>ejemplo1_2</servlet-name>

Servlets y JSP

16Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 17: Servlets y JSP - Experto Java

<servlet-class>ejemplos.ClaseServletHTML</servlet-class></servlet><servlet>

<servlet-name>ejemplo1_3</servlet-name><servlet-class>ejemplos.ClaseServletInit</servlet-class>

<init-param><param-name>mensaje</param-name><param-value>Mensaje de prueba</param-value>

</init-param><init-param>

<param-name>contador</param-name><param-value>10</param-value>

</init-param></servlet>

<servlet-mapping><servlet-name>ejemplo1_1</servlet-name><url-pattern>/ejemploservlet</url-pattern>

</servlet-mapping><servlet-mapping>

<servlet-name>ejemplo1_2</servlet-name><url-pattern>/ejemploservletHTML</url-pattern>

</servlet-mapping><servlet-mapping>

<servlet-name>ejemplo1_3</servlet-name><url-pattern>/ejemploservletInit</url-pattern>

</servlet-mapping></web-app>

Vemos que se mapean los tres servlets:

• ejemplo1_1 es el nombre para el primer servlet ClaseServlet, que se puedereferenciar también con /ejemploservlet.

• ejemplo1_2 es el nombre para el segundo servlet ClaseServletHTML, que se puedereferenciar también con /ejemploservletHTML

• ejemplo1_3 es el nombre para el tercer servlet ClaseServletInit, que se puedereferenciar también con /ejemploservletInit. En él se definen los parámetros deinicio mensaje y contador, utilizados internamente por el servlet (se definenmediante etiquetas <init-param>, indicando el nombre (param-name) y el valor(param-value)).

Para probar los servlets, instalamos la aplicación web en Tomcat. Para llamar a losservlets, podemos hacerlo de tres formas:

• Escribiendo, respectivamente para cada servlet:

http://localhost:8080/appserv1/servlet/ejemplos.ClaseServlethttp://localhost:8080/appserv1/servlet/ejemplos.ClaseServletHTMLhttp://localhost:8080/appserv1/servlet/ejemplos.ClaseServletInit

• Sustituir la clase del servlet por su nombre asociado en el mapeo:

Servlets y JSP

17Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 18: Servlets y JSP - Experto Java

http://localhost:8080/appserv1/servlet/ejemplo1_1http://localhost:8080/appserv1/servlet/ejemplo1_2http://localhost:8080/appserv1/servlet/ejemplo1_3

• Utilizar el mapeo en el fichero descriptor y llamar a los servlets con su URL asociada:

http://localhost:8080/appserv1/ejemploservlethttp://localhost:8080/appserv1/ejemploservletHTMLhttp://localhost:8080/appserv1/ejemploservletInit

NOTA: el servlet ClaseServletInit no tomará los parámetros si lo llamamos del primermodo, debido a que se asignan esos parámetros al mapeo.

1.4. Logging en aplicaciones Java EE con servlets

Utilizaremos Log4J como librería de logging, pero encapsulada dentro de la libreríacommons-logging de Jakarta. Ya vimos en el módulo de servidores web que, para poderimprimir mensajes de log en una aplicación que contenga servlets, se debían seguir estospasos:

• Añadir los ficheros JAR de las librerías (commons-logging-X.X.jar ylog4j-X.X.X.jar) en la carpeta WEB-INF/lib de nuestra aplicación

• Colocar dos ficheros .properties en el CLASSPATH de la aplicación (carpetaWEB-INF/classes):• Un fichero commons-logging.properties indicando que vamos a utilizar Log4J

como librería subyacente• Un fichero log4j.properties con la configuración de logging para Log4J.

Vimos que estos ficheros los colocaríamos en una carpeta fuente llamada resources,para luego desde Ant o con WebTools llevarlo a build/WEB-INF/classes.

• Finalmente, sólo queda en cada servlet o clase Java colocar los mensajes de log dondequeramos. Veremos cómo hacerlo en servlets y páginas JSP en el siguiente módulo.Aquí vemos un ejemplo de cómo ponerlos en cada servlet:...

import org.apache.commons.logging.*;

public class ServletLog4J1 extends HttpServlet{

static Log logger = LogFactory.getLog(ServletLog4J1.class);

// Metodo para procesar una peticion GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

logger.info("Atendiendo peticion Servlet Log4J");PrintWriter out = response.getWriter();out.println ("Servlet sencillo de prueba para

logging");

Servlets y JSP

18Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 19: Servlets y JSP - Experto Java

logger.debug("Fin de procesamiento de petición");}

}

Servlets y JSP

19Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 20: Servlets y JSP - Experto Java

2. Ejercicios de introducción a los servlets

2.1. Servlet básico

Para comenzar vamos a crear un proyecto web desde cero, y en él un servlet sencillo detipo Hola Mundo. Seguiremos los siguientes pasos:

a) Crear un nuevo proyecto web dinámico con Eclipse, de nombre jsp-sesion01-hola.

b) Crear un nuevo servlet dentro del proyecto, en un paquetees.ua.jtech.jsp.sesion01.hola, con nombre HolaMundoServlet. Mapearemos elservlet a la dirección /HolaMundoServlet.

c) Introducir en el método doGet del servlet el código para que muestre como salida eltexto "Hola Mundo":

PrintWriter out = response.getWriter();out.println ("Hola Mundo");

d) Ejecutar la aplicación web en Tomcat y comprobar que el servlet funcionacorrectamente..

2.2. Servlet que muestra la fecha y hora actuales

Completar el servlet es.ua.jtech.jsp.sesion01.ejercicios.FechaServlet de laaplicación jsp-sesion01 para que, tanto por GET como por POST, muestre una páginaHTML con la fecha y hora actuales en una cabecera <H3>, y en el <TITLE> de la página.Para ello podéis utilizar la clase java.util.Date, y sacar por la salida del servlet la horaen formato cadena:

public void doGet(...) throws ...{

String fecha = "" + new java.util.Date();response.setContentType(...);out = response.getWriter();... // sacar la fecha tanto en el TITLE como en una

cabecera H3}

Una vez hecho, configurad el descriptor de la aplicación para que el servlet se mapee a ladirección /fechaHora.

AyudaCuando tengamos un servlet ya implementado, pero sin configurar, podemos utilizar Eclipse paraañadir automáticamente la configuración necesaria al descriptor de despligue. Para elloentraremos en el asistente de crear nuevo servlet (New > Servlet), y marcamos en él la casilla Usean existing Servlet class or JSP. Una vez hecho esto, seleccionaremos la clase en la que se

Servlets y JSP

20Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 21: Servlets y JSP - Experto Java

encuentra nuestro servlet y pulsamos sobre Next. Ahora podremos especificar la ruta a la quequeremos mapear el servlet, y Eclipse añadirá la configuración necesaria al fichero web.xml.

2.3. Servlet que muestra parámetros de inicio

Crear un servlet es.ua.jtech.jsp.sesion01.ejercicios.ParamIniServlet en laaplicación jsp-sesion01 que muestre en una tabla el nombre y el valor de todos losparámetros de inicio que se tengan configurados para ese servlet en el fichero descriptor(web.xml). La tabla tendrá dos columnas: una con el nombre del parámetro y otra con elvalor.

Una vez hecho, probadlo añadiéndole en el fichero web.xml 3 parámetros de inicio connombres param1, param2 y param3 y valores val1, val2 y val3. Para ello deberéisdar un nombre al servlet (el nombre es arbitrario).

NOTA: para recorrer todos los parámetros de inicio, deberéis utilizar el métodoinit(...) que tiene un parámetro ServletConfig, y utilizar dicho parámetro paraobtener los nombres de los parámetros, y recorrerlos uno a uno para obtener su valor:

ServletConfig sc;

public void init(ServletConfig s) throws ServletException{

super.init(s);sc = s;

}

public void doGet(...) throws...{

java.util.Enumeration nombres = sc.getInitParameterNames();while (nombres.hasMoreElements()){

String nombre = (String)(nombres.nextElement());String valor = sc.getInitParameter(nombre);... // Mostrar nombre y valor en una tabla

}}

2.4. (*) Configurar logging en servlets

En la aplicación jsp-sesion01 tenemos dos servlets, ServletLog4J1 y ServletLog4J2

en el paquete es.ua.jtech.jsp.sesion01.ejercicios. Queremos configurar laslibrerías de logging para poder ver los mensajes que emiten. Se pide:

• Comprobar que las librerías de logging de commons-logging y log4j estáncorrectamente copiadas en WebContent/WEB-INF/lib (o en las librerías del proyecto)

• Añadir los ficheros de configuración pertinentes commons-logging.properties ylog4j.properties en una carpeta de fuentes llamada resources para que saquenlos mensajes de ambos servlets (de tipo INFO o superior) a un fichero

Servlets y JSP

21Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 22: Servlets y JSP - Experto Java

C:/errores.log, con el formato:

dd/MM/aaaa hh:mm:ss - prioridad - texto del mensaje - salto de línea

• El servlet ServletLog4J2 no saca mensajes de log. Añadid las líneas de códigonecesarias para que saque un mensaje de tipo INFO cuando empiece a procesar lapetición (al inicio del doGet) y otro cuando la termine, anotando el tiempotranscurrido entre ambos mensajes (puede serte de utilidad el métodoSystem.currentTimeMillis() de Java).

Probad a llamar a los servlets ServletLog4J1 o ServletLog4J2 alguna vez, y quegeneren logs en el fichero errores.log que viene por defecto en el fichero deconfiguración.

Servlets y JSP

22Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 23: Servlets y JSP - Experto Java

3. Procesamiento de peticiones

Un servlet maneja peticiones de los clientes a través de su método service. Con él sepueden manejar peticiones HTTP (entre otras), reenviando las peticiones a los métodosapropiados que las manejan. Por ejemplo, una petición GET puede redirigirse a unmétodo doGet. Veremos ahora los elementos principales que intervienen en unainteracción vía HTTP.

3.1. Peticiones: HttpServletRequest

Como hemos visto anteriormente, los objetos ServletRequest se emplean para obtenerinformación sobre la petición de los clientes. Más en concreto, el subtipoHttpServletRequest se utiliza en las peticiones HTTP. Proporciona acceso a los datosde las cabeceras HTTP, cookies, parámetros pasados por el usuario, etc, sin tener queparsear nosotros a mano los datos de formulario de la petición.

La clase dispone de muchos métodos, pero destacamos los siguientes:

• Para obtener los valores de los parámetros pasados por el cliente, se tienen losmétodos:

Enumeration getParameterNames()String getParameter (String nombre)String[] getParameterValues (String nombre)

Con getParameterNames() se obtiene una lista con los nombres de los parámetrosenviados por el cliente. Con getParameter() se obtiene el valor del parámetro denombre nombre. Si un parámetro tiene varios valores (por ejemplo, si tenemos unarray de cuadros de texto con el mismo nombre en un formulario), se pueden obtenertodos separados con getParameterValues(). Los nombres de los parámetrosnormalmente sí distinguen mayúsculas de minúsculas, deberemos tener cuidado alindicarlos.

• Para obtener la cadena de una petición GET, se tiene el método:

String getQueryString()

que devuelve todos los parámetros de la petición en una cadena, que deberemosparsear nosotros como nos convenga.

• Para obtener datos de peticiones POST, PUT o DELETE, se tienen los métodos:

BufferedReader getReader()ServletInputStream getInputStream()

Con getReader() se obtiene un BufferedReader para peticiones donde esperemosrecibir texto. Si esperamos recibir datos binarios, se debe empleargetInputStream(). Si lo que esperamos recibir son parámetros por POST igual que

Servlets y JSP

23Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 24: Servlets y JSP - Experto Java

se haría por GET, es mejor utilizar los métodos getParameterXXXX(...) vistosantes.

• Para obtener información sobre la línea de petición, se tienen los métodos:

String getMethod()String getRequestURI()String getProtocol()

Con getMethod() obtenemos el comando HTTP solicitado (GET, POST, PUT, etc),con getRequestURI() obtenemos la parte de la URL de petición que está detrás delhost y el puerto, pero antes de los datos del formulario. Con getProtocol()

obtenemos el protocolo empleado (HTTP/1.1, HTTP/1.0, etc).

3.2. Respuestas: HttpServletResponse

Los objetos ServletResponse se emplean para enviar el resultado de procesar unapetición a un cliente. El subtipo HttpServletResponse se utiliza en las peticionesHTTP. Proporciona acceso al canal de salida por donde enviar la respuesta al cliente.

La clase dispone de muchos métodos, pero destacamos:

Writer getWriter()ServletOutputStream getOutputStream()

Con getWriter() se obtiene un Writer para enviar texto al cliente. Si queremos enviardatos binarios, se debe emplear getOutputStream().

Si queremos especificar información de cabecera, debemos establecerla ANTES deobtener el Writer o el ServletOutputStream. Hemos visto en algún ejemplo el métodosetContentType() para indicar el tipo de contenido. Veremos las cabeceras con másdetenimiento más adelante.

3.3. Procesamiento de peticiones GET y POST

Como se ha visto anteriormente, el método doGet() se emplea para procesar peticionesGET. Para realizar nuestro propio procesamiento de petición, simplementesobreescribimos este método en el servlet:

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

// ... codigo para una peticion GET}

Podemos utilizar los métodos del objeto HttpServletRequest vistos antes. Asípodremos, entre otras cosas:

• Acceder a elementos de la petición, como valores de parámetros:

Servlets y JSP

24Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 25: Servlets y JSP - Experto Java

String nombreUsuario = request.getParameter("nombre");

• Acceder a los parámetros en la cadena de la petición y procesarlos como queramos:

String query = request.getQueryString();...

• Obtener un canal de entrada (Reader o InputStream) con que leer los datos de lapetición:

BufferedReader r = request.getReader();...

Esta, sin embargo, no es una buena idea para tomar parámetros de peticiones u otrascosas. Se suele emplear sobre todo para transferencias de ficheros, pero hay que teneren cuenta que si obtenemos un canal de entrada, luego no podremos obtenerparámetros u otros valores con métodos getParameter() y similares.

• etc.

También podemos utilizar los métodos del objeto HttpServletResponse para, entre otrascosas:

• Establecer valores de la cabecera (antes que cualquier otra acción sobre la respuesta):

response.setContentType("text/html");

• Obtener el canal de salida por el que enviar la respuesta:

PrintWriter out = response.getWriter();out.println ("Enviando al cliente");

• Redirigir a otra página:

response.sendRedirect("http://localhost:8080/pag.html");

• etc.

De forma similar, el método doPost(), se emplea para procesar peticiones POST. Igualque antes, debemos sobreescribir este método para definir nuestro propio procesamientode la petición:

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

// ... codigo para una peticion POST}

Las posibilidades de los parámetros HttpServletRequest y HttpServletResponse sonlas mismas que para GET. Normalmente muchos servlets definen el mismo código parauno y otro método (hacen que doPost() llame a doGet() y definen allí el código, o alrevés), pero conviene tenerlos separados para poder tratar independientemente uno y otrotipo de peticiones si se quiere.

Servlets y JSP

25Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 26: Servlets y JSP - Experto Java

3.3.1. Procesamiento secuencial de peticiones

Los servlets normalmente pueden gestionar múltiples peticiones de clientesconcurrentemente. Pero puede suceder que, si los métodos que definimos acceden a unrecurso compartido, no nos interese que varios clientes accedan a dicho recursosimultáneamente. Para solucionar este problema, podemos definir bloques de códigosynchronized, o bien hacer que el servlet sólo atienda una petición cada vez.

Para esto último, lo único que hay que hacer es que el servlet, además de heredar deHttpServlet, implemente la interfaz SingleThreadModel. Esto no supone definir másmétodos, simplemente añadimos el implements necesario al definir la clase Servlet, y yaestá:

public class MiServletextends HttpServlet implements SingleThreadModel{

...}

3.4. Manejo de formularios

Los datos que se envían como parámetros en una petición (tras el interrogante si es unapetición GET, o por otro lado si es POST) se llaman datos de formulario. Una vezenviados estos datos como petición, ¿cómo se extraen en el servidor?

Si trabajáramos con CGI, los datos se tomarían de forma distinta si fuese una peticiónGET o una POST. Para una GET, por ejemplo, tendríamos que tomar la cadena tras lainterrogación, y parsearla convenientemente, separando los bloques entre '&', y luegoseparando el nombre del parámetro de su valor a partir del '='. También hay quedescodificar los valores: los alfanuméricos no cambian, pero los espacios se hanconvertido previamente en '+', y otros caracteres se convierten en '%XX%'.

Con servlets todo este análisis se realiza de forma automática. La claseHttpServletRequest dispone de métodos que devuelven la información que nos interesaya procesada, e independientemente de si es una petición GET o POST. Hemos vistoantes los métodos:

Enumeration getParameterNames()String getParameter (String nombre)String[] getParameterValues (String nombre)

3.4.1. Ejemplo

Veamos un ejemplo: supongamos que tenemos este formulario:

<html><body><form action="/appforms/servlet/ejemplos.ServletForm">

Servlets y JSP

26Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 27: Servlets y JSP - Experto Java

Valor 1: <input type="text" name="texto1"><br>Valor2:<select name="lista"><option name="lista" value="Opcion 1">Opcion 1</option><option name="lista" value="Opcion 2">Opcion 2</option><option name="lista" value="Opcion 3">Opcion 3</option></select><br>Valores 3:<br><input type="text" name="texto2"><input type="text" name="texto2"><input type="text" name="texto2">

<input type="submit" value="Enviar"></form></body></html>

Al validarlo se llama al servlet ServletForm, que muestra una página HTML con losvalores introducidos en los parámetros del formulario:

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ServletForm extends HttpServlet{

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");

PrintWriter out = response.getWriter();

// Mostramos los datos del formulario

out.println ("<HTML>");out.println ("<BODY>");out.println ("<H1>Datos del formulario</H1>");out.println ("<BR>");

String valor1 =request.getParameter("texto1");

String valor2 =request.getParameter("lista");

String[] valor3 =request.getParameterValues("texto2");

out.println ("Valor 1:" + valor1);out.println ("<BR>");out.println ("Valor 2:" + valor2);

Servlets y JSP

27Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 28: Servlets y JSP - Experto Java

out.println ("<BR>");out.println ("Valor 3:");out.println ("<BR>");if (valor3 != null)

for (int i = 0; i < valor3.length; i++){

out.println (valor3[i]);out.println ("<BR>");

}

out.println ("</BODY>");out.println ("</HTML>");

}

// Metodo para POST

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

doGet(request, response);}

}

Para probar el ejemplo que viene en las plantillas, cargamos la URL:

http://localhost:8080/appforms/index_form.html

Servlets y JSP

28Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 29: Servlets y JSP - Experto Java

4. Ejercicios de procesamiento de peticiones

4.1. Recogida de parámetros del usuario

La aplicación jsp-sesion02 contiene un formulario form_datos.html con una serie decampos (tipo texto, listas, checkboxes...). Se pide que dicho formulario, en su action,llame al servlet es.ua.jtech.jsp.sesion02.ejercicios.DatosServlet que deberéiscrear e implementar. El servlet recogerá todos los parámetros del formulario y losmostrará en una tabla de dos columnas (una con el nombre del parámetro y otra con elvalor).

4.2. Trabajando con redirecciones

Sobre la aplicación anterior, tenemos otro formulario form_datos2.html idéntico al delejercicio anterior, que deberá llamar al servletes.ua.jtech.jsp.sesion02.ejercicios.DatosServlet2. Crear este servlet y hacerque redirija a la página bienvenida.html con un mensaje de bienvenida, si los datosintroducidos en el formulario son correctos, y a la misma página form_datos2.html sihay algún dato incorrecto. Entenderemos por dato incorrecto que alguno de los campos detexto se quede vacío. Utilizad el método sendRedirect de la respuesta para lasredirecciones.

4.3. (*)Un buscador sencillo

En el fichero libros.txt hay un listado de libros, indicando su ISBN, título y autor.Cread e implementad un servletes.ua.jtech.jsp.sesion02.ejercicios.LibroServlet que lea dicho fichero, guardelos libros en un ArrayList, y reciba un parámetro cadena. Como resultado, sacará todoslos libros de la lista que contengan dicha cadena (en el título, en el autor, o en cualquierparte de la cadena). Podéis hacer también una página HTML libros.html con elformulario de búsqueda que llame al servlet, para poderlo probar

Servlets y JSP

29Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 30: Servlets y JSP - Experto Java

5. Cabeceras y códigos desde servlets

Veremos a continuación cómo tratar las cabeceras HTTP de una petición y de unarespuesta, así como los códigos de estado que emite un servidor Web ante una petición, ylas variables CGI a las que podemos acceder.

5.1. Cabeceras de petición

Cuando se envía una petición HTTP, se pueden enviar, entre otras cosas, unas cabecerascon información sobre el navegador. Para leer estas cabeceras de una petición desde unservlet, se utiliza el método getHeader() del objeto HttpServletRequest.

String getHeader(String nombre)

El parámetro indica el nombre de la cabecera cuyo valor se quiere obtener. Devuelve elvalor de la cabecera, o null si la cabecera no ha sido enviada en la petición.

Se tienen otros métodos, como:

Enumeration getHeaderNames()Enumeration getHeaders(String nombre)int getIntHeader(String nombre)...

Con getHeaderNames() obtendremos todos los nombres de las cabeceras enviadas. CongetHeaders() obtendremos todos los valores de la cabecera de nombre dado. Tambiénhay métodos como getIntHeader() que devuelve el valor de una cabecera con un tipode dato específico (entero, en este caso). Los nombres de las cabeceras normalmente nodistinguen mayúsculas de minúsculas.

Algunas cabeceras son de uso común, y tienen métodos específicos para obtener susvalores, como:

Cookie[] getCookies()String getContentLength()String getContentType()...

Con getCookies()obtendremos todas las cookies de la petición (veremos las cookies conmás detalle en otro tema). Con getContentLength() obtenemos el valor de la cabeceraContent-Length, y con getContentType() el de la cabecera Content-Type.

5.2. Cabeceras de respuesta

En la respuesta de un servidor web a una petición también pueden aparecer cabeceras queinforman sobre el documento servido o sobre el propio servidor. Podemos definircabeceras de respuesta para enviar cookies, indicar la fecha de modificación, etc. Estas

Servlets y JSP

30Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 31: Servlets y JSP - Experto Java

cabeceras deben establecerse ANTES de enviar cualquier documento, o antes de obtenerel PrintWriter si es el caso.

Para enviar cabeceras, el método más general es setHeader() del objetoHttpServletResponse.

void setHeader(String nombre, String valor)

Al que se le pasan el nombre de la cabecera y el valor. Hay otros métodos útiles:

void setIntHeader(String nombre, int valor)void addHeader(String nombre, String valor)void addIntHeader(String nombre, int valor)...

setIntHeader() o setDateHeader() se utilizan para enviar cabeceras de tipo entero ofecha. Los métodos add...() se emplean para añadir múltiples valores a una cabeceracon el mismo nombre.

Algunas cabeceras tienen métodos específicos de envío, como:

void setContentType(String tipo)void setContentLength(int tamaño)void sendRedirect(String url)void addCookie(Cookie cookie)

Con setContentType() se establece la cabecera Content-Type con el tipo MIME deldocumento. Con setContentLength() se indican los bytes enviados. ConsendRedirect() se selecciona la cabecera Location, y con ella se redirige a la páginaque le digamos. Finalmente, con addCookie() se establecen cookies (esto último ya loveremos con más detalle en otro tema). Es recomendable utilizar estos métodos en lugardel método setHeader() para la cabecera en cuestión.

5.3. Variables CGI

Las variables CGI son una forma de recoger información sobre una petición. Algunas sederivan de la línea de petición HTTP y de las cabeceras, otras del propio socket (como elnombre o la IP de quien solicita la petición), y otras de los parámetros de instalación delservidor (como el mapeo de URLs a los paths actuales).

Mostramos a continuación una tabla con las variables CGI, y cómo acceder a ellas desdeservlets:

VARIABLE CGI SIGNIFICADO ACCESO DESDE SERVLETS

AUTH_TYPE Tipo de cabecera Authorization(basic o digest)

request. getAuthType()

CONTENT_LENGTH Número de bytes enviados enpeticiones POST

request.getContentLength()

Servlets y JSP

31Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 32: Servlets y JSP - Experto Java

CONTENT_TYPE Tipo MIME de los datosadjuntos

request.getContentType()

DOCUMENT_ROOT Path del directorio raíz delservidor web

getServletContext().getRealPath("/")

HTTP_XXX_YYY Acceso a cabeceras arbitrariasHTTP

request.getHeader("Xxx-Yyy")

PATH_INFO Información de path adjunto ala URL

request. getPathInfo()

PATH_TRANSLATED Path mapeado al path real delservidor

request.getPathTranslated()

QUERY_STRING Datos adjuntos para peticionesGET

request.getQueryString()

REMOTE_ADDR IP del cliente que hizo lapetición

request.getRemoteAddr()

REMOTE_HOST Nombre del dominio del clienteque hizo la petición (o IP si nose puede determinar)

request.getRemoteHost()

REMOTE_USER Parte del usuario en lacabecera Authorization (si sesuministró)

request. getRemoteUser

REQUEST_METHOD Tipo de petición (GET, POST,PUT, DELETE, HEAD,OPTIONS, TRACE)

request. getMethod()

SCRIPT_NAME Path del servlet request.getServletPath()

SERVER_NAME Nombre del servidor web request.getServerName()

SERVER_PORT Puerto por el que escucha elservidor

request.getServerPort()

SERVER_PROTOCOL Nombre y versión usada en lalínea de petición (HTTP/1.0,HTTP/1.1 ...)

request.getServerProtocol()

SERVER_SOFTWARE Información del servidor web getServletContext().getServerInfo()

request se asume que es un objeto de tipo HttpServletRequest. Para obtenercualquiera de las variables antes mencionadas, sólo hay que llamar al método apropiadodesde doGet() o doPost().

Servlets y JSP

32Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 33: Servlets y JSP - Experto Java

5.4. Códigos de estado HTTP

Cuando un servidor web responde a una petición, en la respuesta aparece, entre otrascosas, un código de estado que indica el resultado de la petición, y un mensaje cortodescriptivo de dicho código.

El envío de cabeceras de respuesta normalmente se planifica junto con el envío decódigos de estado, ya que muchos de los códigos de estado necesitan tener una cabeceradefinida. Podemos hacer varias cosas con los servlets manipulando las líneas de estado ylas cabeceras de respuesta, como por ejemplo reenviar al usuario a otros lugares, indicarque se requiere un password para acceder a un determinado sitio web, etc.

Para enviar códigos de estado se emplea el método setStatus() deHttpServletResponse:

void setStatus(int estado)

Donde se le pasa como parámetro el código del estado. En la claseHttpServletResponse tenemos una serie de constantes para referenciar a cada código deestado. Por ejemplo, la constante:

HttpServletResponse.SC_NOT_FOUND

se corresponde con el código 404, e indica que el documento solicitado no se haencontrado.

Existen otros métodos para gestión de mensajes de error:

void sendError(int codigo, String mensaje)void sendRedirect(String url)

sendError() genera una página de error, con código de error igual a codigo, y conmensaje de error igual a mensaje. Se suele utilizar este método para códigos de error, ysetStatus() para códigos normales.

sendRedirect() genera un error de tipo 302, envía una cabecera Location y redirige ala página indicada en url. Es mejor que enviar directamente el código, o hacer unresponse.setHeader("Location", "http..."), porque es más cómodo, y porque elservlet genera así una página con el enlace a la nueva dirección, para navegadores que nosoporten redirección automática

Si queremos enviar un código en la respuesta, se tiene que especificar antes de obtener elobjeto PrintWriter.

5.5. Ejemplos

5.5.1. Ejemplo de cabeceras de petición

Servlets y JSP

33Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 34: Servlets y JSP - Experto Java

El siguiente servlet muestra los valores de todas las cabeceras HTTP enviadas en lapetición. Recorre las cabeceras enviadas y muestra su nombre y valor:

package ejemplos;

import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;

public class ServletCabecerasPeticionextends HttpServlet{

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

PrintWriter out = response.getWriter();

// Mostramos las cabeceras enviadas// en la peticion

out.println ("<HTML>");out.println ("<BODY>");out.println ("<H1>Cabeceras</H1>");out.println ("<BR>");

Enumeration cabeceras = request.getHeaderNames();

while (cabeceras.hasMoreElements()){

String nombre = (String)(cabeceras.nextElement());out.println ("Nombre: " + nombre +

", Valor: " + request.getHeader(nombre));out.println ("<BR><BR>");

}

out.println ("</BODY>");out.println ("</HTML>");

}

// Metodo para POST

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

doGet(request, response);}

}

Se puede probar con este formulario, pinchando el botón:

<html><body><form action=

Servlets y JSP

34Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 35: Servlets y JSP - Experto Java

"/appcab/servlet/ejemplos.ServletCabecerasPeticion"><input type="submit" value="Pulsa aqui">

</form></body></html>

5.5.2. Ejemplo de cabeceras de respuesta

El siguiente servlet espera un parámetro accion que puede tomar 4 valores:

• primos: El servlet tiene un hilo que está constantemente calculando números primos.Al elegir esta opción se envía una cabecera Refresh y recarga el servlet cada 10segundos, mostrando el último número primo que ha encontrado.

• redirect: Utiliza un sendRedirect() para cargar la página que se indique comoparámetro

• error: Utiliza un sendError() para mostrar una página de error, con un mensaje deerror definido por el usuario, y un código de error a elegir de una lista.

• codigo: Envía un código de estado HTTP (con setStatus()), a elegir de entre unalista.

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ServletCabecerasRespuestaextends HttpServlet implements Runnable{

// Ultimo numero primo descubiertolong primo = 1;// Hilo para calcular numeros primosThread t = new Thread(this);

// Metodo de inicializacion

public void init(){

t.start();}

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

String accion = request.getParameter("accion");

if (accion.equals("primo")){

// Buscar el ultimo numero// primo y enviarlo

Servlets y JSP

35Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 36: Servlets y JSP - Experto Java

response.setContentType("text/html");response.setHeader("Refresh", "10");PrintWriter out = response.getWriter();out.println ("<HTML><BODY>");out.println ("Primo: " + primo);out.println ("</BODY></HTML>");

} else if (accion.equals("redirect")) {

// Redirigir a otra pagina

String url = request.getParameter("url");if (url == null)

url = "http://www.ua.es";response.sendRedirect(url);

} else if (accion.equals("error")) {

// Enviar error con sendError()

int codigo = response.SC_NOT_FOUND;try{

codigo = Integer.parseInt(request.getParameter("codigoMensaje"));

} catch (Exception ex) {codigo = response.SC_NOT_FOUND;

}String mensaje = request.getParameter("mensaje");if (mensaje == null)

mensaje = "Error generado";response.sendError(codigo, mensaje);

} else if (accion.equals("codigo")) {

// Enviar un codigo de error

int codigo = response.SC_NOT_FOUND;try{

codigo = Integer.parseInt(request.getParameter("codigo"));

} catch (Exception ex) {codigo = response.SC_NOT_FOUND;

}response.setStatus(codigo);

}}

// Metodo para POST

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

doGet(request, response);}

... el resto del codigo es para el hilo,

Servlets y JSP

36Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 37: Servlets y JSP - Experto Java

para calcular numeros primosPuede consultarse en el fichero fuente,aqui se quita por simplificar

}

Se puede probar con este formulario, eligiendo la acción a realizar, introduciendo losparámetros necesarios en el formulario y pinchando el botón de Enviar Datos:

<html><body><form action="/appcab/servlet/ejemplos.ServletCabecerasRespuesta">

<table border="0">

<tr><td><input type="radio" name="accion" value="primo" selected>Obtener ultimo numero primo</td><td></td><td></td></tr>

<tr><td><input type="radio" name="accion" value="redirect">Redirigir a una pagina</td><td>URL:<input type="text" name="url" value="http://www.ua.es"></td><td></td></tr>

<tr><td><input type="radio" name="accion" value="error">Mostrar pagina de error</td><td>Mensaje:<input type="text" name="mensaje"value="Error generado por el usuario"></td><td>Codigo:<select name="codigoMensaje"><option name="codigoMensaje" value="400">400</option><option name="codigoMensaje" value="401">401</option><option name="codigoMensaje" value="403">403</option><option name="codigoMensaje" value="404" selected>404</option></select></td></tr>

<tr>

Servlets y JSP

37Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 38: Servlets y JSP - Experto Java

<td><input type="radio" name="accion" value="codigo">Enviar codigo de error</td><td>Codigo:<select name="codigo"><option name="codigo" value="200">200</option><option name="codigo" value="204">204</option><option name="codigo" value="404" selected>404</option></select></td><td></td></tr>

</table>

<input type="submit" value="Enviar Datos">

</form></body></html>

5.5.3. Ejemplo de autentificación

El siguiente servlet emplea las cabeceras de autentificación: envía una cabecera deautentificación si no ha recibido ninguna, o si la que ha recibido no está dentro de unconjunto de Properties predefinido, con logins y passwords válidos. En el caso deintroducir un login o password válidos, muestra un mensaje de bienvenida.

Los logins y passwords están en un objeto Properties, definido en el método init().Podríamos leer estos datos de un fichero, aunque por simplicidad aquí se definen comoconstantes de cadena.

Los datos de autentificación se envían codificados, y se emplea un objetosun.misc.BASE64Decoder para descodificarlos y sacar el login y password.

package ejemplos;

import java.io.*;import java.util.*;import sun.misc.*;import javax.servlet.*;import javax.servlet.http.*;

public class ServletPassword extends HttpServlet{

// Conjunto de logins y passwords permitidosProperties datos = new Properties();

// Metodo de inicializacion

public void init(){

datos.setProperty("usuario1", "password1");

Servlets y JSP

38Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 39: Servlets y JSP - Experto Java

datos.setProperty("usuario2", "password2");}

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");

// Comprobamos si hay cabecera// de autorizacion

String autorizacion = request.getHeader("Authorization");

if (autorizacion == null){

// Enviamos el codigo 401 y// la cabecera para autentificacion

response.setStatus(response.SC_UNAUTHORIZED);response.setHeader("WWW-Authenticate",

"BASIC realm=\"privileged-few\"");}else{

// Obtenemos los datos del usuario// y comparamos con los almacenados

// Quitamos los 6 primeros caracteres// que indican tipo de autentificación// (BASIC)

String datosUsuario =autorizacion.substring(6).trim();

BASE64Decoder dec = new BASE64Decoder();

String usuarioPassword = new String(dec.decodeBuffer(datosUsuario));

int indice = usuarioPassword.indexOf(":");

String usuario =usuarioPassword.substring(0, indice);

String password =usuarioPassword.substring(indice + 1);

String passwordReal =datos.getProperty(usuario);

if (passwordReal != null &&passwordReal.equals(password))

{// Mensaje de bienvenida

PrintWriter out = response.getWriter();

Servlets y JSP

39Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 40: Servlets y JSP - Experto Java

out.println ("<HTML><BODY>");out.println ("OK");out.println ("</BODY></HTML>");

} else {

// Pedir autentificacion

response.setStatus(response.SC_UNAUTHORIZED);

response.setHeader("WWW-Authenticate","BASIC realm=\"privileged-few\"");

}}

}

// Metodo para POST

public void doPost(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

doGet(request, response);}

}

Se puede probar cada ejemplo, respectivamente, con:

http://localhost:8080/appcab/inicioCabecerasPeticion.htmlhttp://localhost:8080/appcab/inicioCabecerasRespuesta.htmlhttp://localhost:8080/appcab/servPassword

Un ejemplo de login y password válidos para el tercer ejemplo es: login=usuario1,password=password1.

Servlets y JSP

40Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 41: Servlets y JSP - Experto Java

6. Ejercicios de cabeceras y códigos

6.1. Distinguir el navegador

Muchas veces, cuando escribamos una aplicación Web, nos va a interesar poder distinguirel tipo de navegador que está utilizando el cliente, porque en función del mismo se podránhacer o no determinadas acciones. Por ejemplo, el código Javascript que se emplea en unnavegador Internet Explorer es diferente a veces del que se emplea en uno Netscape. Paraprobar a distinguir entre navegadores, vamos a completar el servlet ejercicios.NavServletde la aplicación appcab para que identifique si el cliente accede desde un tipo denavegador u otro. Para ello leemos la cabecera User-Agent con el métodogetHeader(...) de la petición, y comprobamos su valor. Mostrad la cadena en unapágina, y cargad dicha página desde dos o tres navegadores diferentes. Cada uno mostraráalgún rasgo distintivo en dicha cadena, que lo identifique de los demás. Una vez tengáisuna parte de texto que los diferencia (por ejemplo, imaginemos que en Netscape elUser-Agent tiene la cadena "Netscape", y en el otro navegador (Konqueror, porejemplo), no la tiene) haríamos con algo como:

public void doGet(HttpServletRequest req, ...) throws ...{

String nav = req.getHeader("User-Agent");if (nav.indexOf("Netscape") != -1) // Cambiar

"Netscape" por el texto que sea... // Netscape

else... // Otro navegador (Konqueror)

...}

Una vez distinguido el navegador, ya se podría hacer algo que sólo sirviera para esenavegador. En este caso, por simplificar, vamos a cargar como imagen el logo delnavegador que hayamos detectado. Tenéis en la plantilla las imágenes GIFcorrespondientes a tres navegadores o entornos diferentes. Colocad como imagen de lapágina la del navegador que hayáis detectado (con una etiqueta <img> de HTML).

6.2. Redirecciones con retardo

El formulario form_datos.html de la aplicación appcab se envía al servletejercicios.CompruebaServlet. Se pide implementar dicho servlet para comprobar quelos datos sean correctos (que no haya ningún campo de texto vacío). En el caso de que nohaya errores el servlet simplemente mostrará un mensaje indicando que todo ha ido bien.Si hay algún error, el servlet debe redirigir al servletejercicios.ErrorCompruebaServlet, que deberéis completar para que muestre unmensaje con el error producido (indicando qué campo está incompleto), y a los 5segundos redirija al formulario anterior (utilizando una cabecera de respuesta Refresh).

Servlets y JSP

41Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 42: Servlets y JSP - Experto Java

6.3. (*) Loggear variables CGI

Sobre el servlet ejercicios.CompruebaServlet anterior vamos a añadir mensajes de logde tipo INFO, para que:

• Tras cada petición (por doGet o doPost), genere un mensaje de tipo INFO queindique la IP del cliente que solicitó la petición (variable CGI REMOTE_ADDR), el tipode petición (variable CGI REQUEST_METHOD), y el tipo de navegador (cabeceraUser-Agent).

• El mensaje en conjunto deberá tener el formato siguiente:

día/mes/año hora:minuto:segundo - texto del mensaje - nueva línea

Haced que los mensajes de log se guarden en un fichero visitas.txt, en la carpeta queprefiráis. Para ello utilizad un fichero log4j.properties colocado enWEB-INF/classes.

Servlets y JSP

42Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 43: Servlets y JSP - Experto Java

7. Manejo de Cookies y de Sesiones

Veremos en este tema aspectos sobre el seguimiento de las acciones de los usuarios sobreun sitio web. Para ello veremos cómo trabajar con cookies en los servlets, y cómomanejar información sobre las sesiones de los usuarios.

7.1. Cookies

Una cookie es un objeto de tipo nombre = valor donde se asigna un valor determinado(una cadena de texto) a una variable del nombre indicado. Dicho objeto es almacenado yrecordado por el servidor web y el navegador durante un período de tiempo (indicadocomo un parámetro interno de la propia cookie). Así, se puede tener una lista de cookies

con distintas variables y distintos valores, para almacenar información relevante para cadausuario (se tienen listas de cookies independientes para cada usuario).

En Javascript, por ejemplo, el objeto document.cookie contiene como valor una lista dela forma:

nombre1=valor1;nombre2=valor2;...;nombreN=valorN

donde se almacenan así los valores de las cookies que se tengan definidas.

Se pueden emplear cookies, entre otras cosas, para:

• Identificar a un usuario durante una o varias sesiones. Por ejemplo, a la hora derealizar compras a través de una tienda web, se almacena su identidad (login ypassword) como una cookie y se recuerda a lo largo de diferentes visitas qué es lo quelleva almacenado en su cesta de la compra cada usuario.

• Personalizar un sitio web de acuerdo a las preferencias de cada usuario: definir elcontenido, apariencia, etc, que queremos que tenga una determinada página enfunción de las preferencias del usuario que la esté visitando.

Los navegadores que trabajen con cookies pueden soportar hasta 20 cookies por servidor,de al menos 4 KB cada una. Los servlets que se ejecutan en un mismo servidor compartenlas cookies.

A la hora de trabajar con cookies, debemos tener en cuenta que nuestro sitio web no debedepender de ellas, puesto que muchos navegadores y usuarios las deshabilitan para evitarproblemas de privacidad y otras cuestiones.

Veremos ahora cómo trabajar con cookies desde servlets.

7.1.1. Enviar una cookie

Para crear una nueva cookie y enviarla, se siguen los pasos:

Servlets y JSP

43Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 44: Servlets y JSP - Experto Java

1. Crear la cookie

Las cookies se manejan con la clase Cookie. Se tiene el constructor:

public Cookie (String nombre, String valor)

que crea una cookie de nombre nombre, dándole el valor valor.

2. Establecer los atributos de la cookie

Una vez creada la cookie, podemos establecer los atributos que queramos, con losmétodos de la clase Cookie. Por ejemplo, se tienen:

public void setComment(String comentario)public void setMaxAge(int edad)...

El primero asigna una cadena descriptiva sobre la cookie. El segundo indica cuántossegundos de vida tiene. Si es un valor negativo, se borrará la cookie cuando se cierre elnavegador. Si el valor es 0, se borra la cookie instantáneamente, y si es positivo, seborrará la cookie cuando pasen los segundos indicados (si cerramos y volvemos a abrir elnavegador dentro de ese tiempo, la cookie todavía persistirá). Se tienen otros métodospara establecer atributos de la cookie.

3. Enviar la cookie

Las cookies se añaden a la cabecera de la respuesta, y se envían así al cliente, mediante elmétodo de HttpServletResponse:

public void addCookie (Cookie cookie)

Ejemplo

Vemos un ejemplo completo de envío de cookie:

public class MiServlet extends HttpServlet{

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

Cookie miCookie = new Cookie ("nombre", "Pepe");miCookie.setMaxAge(120);response.addCookie(miCookie);PrintWriter out = response.getWriter();...

}}

Hay que tener en cuenta que las cookies son parte de la cabecera HTTP, con lo cual hayque enviarlas ANTES de escribir la respuesta (o antes de obtener el objeto Writer si loqueremos utilizar).

Servlets y JSP

44Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 45: Servlets y JSP - Experto Java

7.1.2. Obtener una cookie

Para obtener una cookie que envía el cliente se trabaja sobre la petición del cliente(HttpServletRequest), siguiendo los pasos:

1. Obtener todas las cookies

Obtenemos todas las cookies con el método getCookies() de la claseHttpServletRequest:

public Cookie[] getCookies()

Con esto se tiene un array con todas las cookies actuales para el usuario. Si no haycookies el método devuelve null.

2. Obtener el valor de una cookie

Con lo anterior, para obtener el valor de una cookie simplemente recorremos el array decookies buscando la que concuerde con el nombre que queramos. Pueden ser útiles losmétodos de Cookie:

public String getName()public String getValue()

El primero obtiene el nombre de la cookie, y el segundo el valor.

Ejemplo

Un ejemplo de uso, para obtener el nombre del usuario, guardado en la cookie "nombre":

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

Cookie[] cookies = request.getCookies();String nombre;for (int i = 0; i < cookies.length; i++)

if (cookies[i].getName().equals("nombre"))nombre = cookies[i].getValue();

}

7.1.3. Ejemplo

Aquí tenéis un ejemplo de uso de cookies. El servlet ServletCookies cuenta el númerode visitas a una página con una cookie que dura 3 minutos.

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

Servlets y JSP

45Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 46: Servlets y JSP - Experto Java

public class ServletCookies extends HttpServlet{

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");response.setHeader("Cache-Control", "no-cache");

Cookie[] cookies = request.getCookies();Cookie contador = buscaCookie("contador", cookies);

if (contador == null){

// Creamos la cookie con el contador

Cookie cookie = new Cookie ("contador", "1");cookie.setMaxAge(180);response.addCookie(cookie);

// Mostramos el mensaje de primera visita

PrintWriter out = response.getWriter();out.println ("<HTML>");out.println ("<BODY>");out.println ("Primera visita");out.println ("<BR>");out.println ("</BODY>");out.println ("</HTML>");

} else {

// Obtenemos el valor actual del contador

int cont = Integer.parseInt(contador.getValue());cont++;

// Modificamos el valor de la cookie// incrementando el contador

Cookie cookie = new Cookie ("contador", "" + cont);cookie.setMaxAge(180);response.addCookie(cookie);

// Mostramos el numero de visitas

PrintWriter out = response.getWriter();out.println ("<HTML>");out.println ("<BODY>");out.println ("Visita numero " + cont);out.println ("<BR>");out.println ("</BODY>");out.println ("</HTML>");

}}

// Busca la cookie 'nombre'

Servlets y JSP

46Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 47: Servlets y JSP - Experto Java

// en el array de cookies indicado.// Devuelve null si no esta

private Cookie buscaCookie(String nombre,Cookie[] cookies)

{if (cookies == null)

return null;

for (int i = 0; i < cookies.length; i++)if (cookies[i].getName().equals(nombre))

return cookies[i];

return null;}

}

Podéis probar el ejemplo con:

http://localhost:8080/appcs/servCookies

7.2. Seguimiento de sesiones

El seguimiento de sesiones es un mecanismo empleado por los servlets para gestionar unestado sobre las peticiones realizadas desde un mismo cliente (un mismo navegador) a lolargo de un período de tiempo determinado. Las sesiones se comparten por los servlets alos que accede un cliente (algo útil si queremos construir una aplicación basada enmúltiples servlets).

Para utilizar el seguimiento de sesiones se tienen los pasos:

• Utilizar una sesión (objeto HttpSession) para un usuario• Almacenar u obtener datos del objeto HttpSession

• Opcionalmente, invalidar la sesión

7.2.1. Obtener una sesión

El método getSession() del objeto HttpServletRequest obtiene una sesión deusuario.

public HttpSession getSession()public HttpSession getSession(boolean crear)

El primer método obtiene la sesión actual, o crea una si no existe. Con el segundo métodopodemos establecer, mediante el flag booleano, si queremos crear una nueva si no existe(true) o no (false). Si la sesión es nueva, el método isNew() del HttpSession devuelvetrue, y la sesión no tiene ningún dato asociado. Deberemos ir añadiéndole datos trascrearla.

Para mantener la sesión de forma adecuada, debemos llamar a getSession() antes deque se escriba nada en la respuesta HttpServletResponse (y si utilizamos un Writer,

Servlets y JSP

47Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 48: Servlets y JSP - Experto Java

debemos obtenerla antes de obtener el Writer, no antes de escribir datos).

Por ejemplo:

public class MiServlet extends HttpServlet{

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

HttpSession sesion = request.getSession(true);...PrintWriter out = response.getWriter();...

}}

7.2.2. Guardar y obtener datos de la sesión

La interfaz HttpSession proporciona métodos que permiten almacenar y obtener:

• Propiedades de la sesión, como por ejemplo su identificador:

public String getId()

• Datos de la aplicación, que se almacenan y obtienen como pares nombre-valor, dondeel nombre es un String que identifica al dato, y el valor es un Object con el valorasociado. Tendremos que tener cuidado de no sobreescribir datos de un servlet desdeotro accidentalmente. Se tienen los métodos:

public Object getAttribute(String nombre)public void setAttribute(String nombre, Object valor)public void removeAttribute(String nombre)

que obtienen / establecen / eliminan, respectivamente, valores de atributos.Estos`métodos eran getValue(), putValue() y removeValue() hasta la versión 2.2de servlets. Se tienen además métodos como getAttributeNames() para obtener losnombres de los atributos que se tienen almacenados para la sesión, y otros métodos deutilidad en la clase HttpSession.

Por ejemplo:

public class MiServlet extends HttpServlet{

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

HttpSession sesion = request.getSession(true);String nombreUsuario =

(String)(sesion.getAttribute("nombre"));sesion.setAttribute("password", "secreto");

}}

Servlets y JSP

48Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 49: Servlets y JSP - Experto Java

El ejemplo lee el atributo "nombre" de la sesión, y establece el atributo "password" alvalor "secreto".

7.2.3. Invalidar la sesión

Una sesión de usuario puede invalidarse manualmente, o automáticamente (dependiendode dónde esté ejecutando el servlet). Esto implica eliminar el objeto HttpSession y susvalores de la memoria. Se tienen los métodos de HttpSession:

public int getMaxInactiveInterval()public void setMaxInactiveInterval(int intervalo)public void invalidate()

Para invalidarla automáticamente, la sesión expira cuando transcurre el tiempo indicadopor el método getMaxInactiveInterval() entre dos accesos del cliente (en segundos).Se puede establecer dicho valor con setMaxInactiveInterval(...).

Para invalidar manualmente una sesión, se emplea el método invalidate() de la misma.Esto puede ser interesante por ejemplo en comercio electrónico: podemos mantener unasesión donde se vayan acumulando los productos que un usuario quiera comprar, einvalidar la sesión (borrarla) cuando el usuario compre los productos.

Por ejemplo:

public class MiServlet extends HttpServlet{

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

HttpSession sesion = request.getSession(true);...sesion.invalidate();...

}}

7.2.4. Compatibilidad con los navegadores

Una alternativa para el seguimiento de sesiones consiste en la reescritura de URLs.Con esta técnica, se añaden como parámetros de la URL los datos relativos a la sesiónactual, de forma que se van conservando entre las páginas.

El seguimiento de sesiones por defecto emplea cookies para almacenar el identificador deuna sesión. Para poder utilizar seguimiento de sesiones con usuarios que accedan desdenavegadores que no utilicen cookies, los servlets aplican automáticamente la reescriturade URLs cuando no se utilizan cookies.

Para poder utilizar esto, debemos codificar todas las URLs que referenciemos. Para estose emplean los métodos:

Servlets y JSP

49Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 50: Servlets y JSP - Experto Java

public String encodeURL(String url)public String encodeRedirectURL(String url)

El primero se emplea para asociar identificadores con URLs, se utilizará cuandopongamos urls en el contenido de la página que generamos. El segundo se utiliza paraasociar identificadores con redirecciones. Lo emplearemos cuando utilicemos métodossendRedirect(), para codificar la URL que se le pasa. Ambos devuelven la URLsobreescrita si la sobreescritura ha sido necesaria, o la misma URL si no ha sido necesariosobreescribir.

Por ejemplo:

public class MiServlet extends HttpServlet{

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

...String url = response.encodeURL(

"http://localhost:8080/mipagina.html");out.println ("<a href=\"" + url + "\">...</a>");...String url2 = response.encodeRedirectURL(

"http://otrapagina.com");response.sendRedirect(url2);

}}

7.2.5. Oyentes

Existen tres tipos de oyentes (listeners) que podemos utilizar en sesiones, para darrespuesta a eventos que produzcan las propias sesiones, o que desde fuera se provoquensobre las mismas:

• HttpSessionListener se emplea para eventos de crear la sesión y terminarla. Tienelos métodos:

public void sessionCreated(HttpSessionEvent e)public void sessionDestroyed(HttpSessionEvent e)

El objeto que implemente esta interfaz ejecutará el código de sessionCreated()

cuando se inicie la sesión, y el de sessionDestroyed() cuando se termine. Lasclases que implementen este oyente deben configurarse en el fichero descriptor de laaplicación, mediante etiquetas <listener>:

<listener><listener-class>clase</listener-class>

</listener>

donde en <listener-class> se pone el nombre (completo) de la clase que implementael listener. Así, el listener se registra, y el servidor ya sabe que tiene que notificarle en

Servlets y JSP

50Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 51: Servlets y JSP - Experto Java

los momentos oportunos.

• HttpSessionBindingListener: si un objeto asociado a una sesión implementa estainterfaz, la sesión se encarga de notificarle de cuándo son añadidos y eliminados de lasesión. Para ello la interfaz tiene los métodos:

public void valueBound(HttpSessionBindingEvent e)public void valueUnbound(HttpSessionBindingEvent e)

El objeto que implemente esta interfaz ejecutará el código de valueBound() cuandola sesión lo añada, y el método valueUnbound() cuando la sesión lo elimine.

• HttpSessionActivationListener: si un objeto asociado a una sesión implementa estainterfaz, la sesión se encarga de notificarles de cuándo el contenedor cambia la sesiónentre máquinas virtuales distintas, para un sistema distribuido. Para ello tiene losmétodos:

public void sessionDidActivate(HttpSessionEvent e)public void sessionWillPassivate(HttpSessionEvent e)

El objeto que implemente esta interfaz ejecutará el código desessionDidActivate() cuando la sesión se active, y sessionWillPassivate()

cuando se vuelva pasiva.

7.2.6. Ejemplos

Aquí tenéis un ejemplo de uso de sesiones. El servlet ServletSesiones cuenta elnúmero de visitas a una página en una sola sesión (en una sola ventana de navegador).

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class ServletSesiones extends HttpServlet{

// Metodo para GET

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");response.setHeader("Cache-Control", "no-cache");

HttpSession sesion = request.getSession();PrintWriter out = response.getWriter();

if (sesion.isNew()){

// Mostramos un mensaje de primera visita

out.println ("<HTML>");

Servlets y JSP

51Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 52: Servlets y JSP - Experto Java

out.println ("<BODY>");out.println ("Primera visita a la pagina");out.println ("<BR>");out.println ("</BODY>");out.println ("</HTML>");

sesion.setAttribute("contador", new Integer(1));

} else {

// Mostramos el numero de visitas// y actualizamos el contador

int contador = ((Integer)(sesion.getAttribute("contador"))).intValue();contador++;

out.println ("<HTML>");out.println ("<BODY>");out.println ("Visita numero " +

contador +" a la pagina en esta sesion");

out.println ("<BR>");out.println ("</BODY>");out.println ("</HTML>");

sesion.setAttribute("contador",new Integer(contador));

}}

}

Podéis probar el ejemplo con:

http://localhost:8080/appcs/servSesiones

El siguiente servlet utiliza como atributo de sesión una clase interna ObjetoSesion, queimplementa la interfaz HttpSessionBindingListener. Dicho objeto tiene dentro unvalor entero, y una cadena. Cada vez que el objeto se añade a la sesión se modifica unmensaje de texto, mostrando el valor entero actual del objeto:

package ejemplos;

import java.io.*;import javax.servlet.*;import javax.servlet.http.*;

public class EjemploServletListener extends HttpServlet{

public void doGet(HttpServletRequest request,HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");response.setHeader("Cache-Control",

"no-cache");

HttpSession sesion = request.getSession();

Servlets y JSP

52Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 53: Servlets y JSP - Experto Java

PrintWriter out = response.getWriter();

if (sesion.isNew()){

// Mostramos mensaje de inicio

out.println ("<HTML><BODY>" +"Mensaje de inicio" +"</BODY></HTML>");

sesion.setAttribute("contador",new ObjetoSesion(1));

} else {

// Mostramos el valor actual del// objeto "contador"

int contador = ((ObjetoSesion)(sesion.getAttribute("contador"))).getValor();

String mensaje = ((ObjetoSesion)(sesion.getAttribute("contador"))).getEnlazado();

out.println ("<HTML><BODY>");out.println ("Valor: " + contador +

"<br>Enlazado: " + mensaje);out.println ("</BODY></HTML>");

sesion.setAttribute("contador",new ObjetoSesion(contador+1));

}}

}

class ObjetoSesion implements HttpSessionBindingListener{

int valor;String enlazado = "NO";

public ObjetoSesion(int valor){

this.valor = valor;}

public void valueBound(HttpSessionBindingEvent e){

enlazado = "Objeto enlazado a la sesion " +valor + " veces";

}

public void valueUnbound(HttpSessionBindingEvent e){}

public String getEnlazado(){

return enlazado;}

public int getValor()

Servlets y JSP

53Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 54: Servlets y JSP - Experto Java

{return valor;

}}

Si cargamos el servlet por primera vez en la sesión, muestra el mensaje:

Mensaje de bienvenida

Luego, cada vez que recarguemos el servlet se entrará en el bloque else, y al llamar almétodo setAttribute() se disparará el método valueBound(), actualizando la cadena.Con esto, con cada recarga se mostrará el mensaje:

Valor: iEnlazado: Objeto enlazado a la sesion i veces

siendo i el número de veces que se ha enlazado (que coincide con el número de veces quese ha cargado el servlet, en este caso). Lo esencial aquí es que esta variable enlazado semodifica sólo desde el método valueBound, y éste es llamado sólo cuando el objeto seañade a la sesión.

Servlets y JSP

54Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 55: Servlets y JSP - Experto Java

8. Ejercicios de cookies y sesiones

8.1. Personalizar un sitio web

Una de las utilidades que se le dan a las cookies es la de personalizar sitios Web. Laaplicación appcs contiene un formulario form_pers.html que le indica al usuario queintroduzca su nombre, y elija un color de fondo. Dicho formulario llama después alservlet ejercicios.PersonalizaServlet. El formulario también tiene un enlace Ir a páginaprincipal, que internamente llama al servlet ejercicios.PrincipalServlet. Se pide:

• Que en el servlet ejercicios.PersonalizaServlet se guarde en dos cookies el nombredel usuario y el valor del color seleccionado. Después, redirigirá a form_pers.html denuevo.

• Que el servlet ejerciciosPrincipalServlet (llamado desde el formulario anterior) tomelas cookies que le envíe el usuario, y genere una página de bienvenida con el color defondo que haya en la cookie con el color, y con un mensaje de saludo al nombre quehaya en la cookie con el nombre. Para establecer el color de fondo, en el bodypodemos tener un atributo bgcolor, y ahí le colocaremos el valor que tenga la cookie.

<body bgcolor="red">...

8.2. Carro de la compra

La aplicación appcs contiene también una página form_carro.html que tiene una lista deartículos para comprar. Para comprarlos, basta con pulsar el botón de "Añadir al carro"correspondiente. Dicho formulario llama al servlet ejercicios.CarroServlet. Se pide quedicho servlet almacene como objetos de sesión los objetos que se vayan comprando, ygenere una página dinámica con:

• Cada uno de los objetos que se llevan comprados hasta ahora en la sesión, indicandocantidad y precio total.

• Precio total de la compra• Un enlace al formulario form_carro.html para seguir comprando.

NOTA: para almacenar los objetos podemos utilizar cualquier estructura de datos quequeramos (Vector, Hashtable, ArrayList, etc), y la guardaremos como un atributo de lasesión (es decir, dicha estructura ENTERA la guardaremos como UN UNICO atributo desesión). Guardaremos, para cada nombre de artículo, qué cantidad lleva comprada elusuario, y el precio unitario o total, para luego mostrar estos dos datos en la página que segenere. Para tomar el nombre del artículo y el valor, notar que cada artículo tieneasociado en la página un formulario con dos campos ocultos articulo y precio, con estoselementos.

Servlets y JSP

55Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 56: Servlets y JSP - Experto Java

CONSEJO: crear una clase interna en el propio CarroServlet (llamadla ObjetoCarro, porejemplo), que tenga como campos los valores que hay que guardar de cada artículo:

class ObjetoCarro{

String articulo;int precio;

public ObjetoCarro(String articulo, int precio){

this.articulo = articulo;this.precio = precio;

}

public String getArticulo(){

return articulo;}

public int getPrecio(){

return precio;}

}

Después, en el servlet CarroServlet, cada vez que el usuario compre un artículo, creáis unobjeto de este tipo con los valores del artículo que haya enviado. Y lo añadís a la sesión,almacenando todos los objetos de tipo ObjetoCarro en un Vector, por ejemplo:

HttpSession sesion = request.getSession();String articulo = request.getParameter("articulo");int precio = Integer.parseInt(request.getParameter("precio"));

if (sesion.isNew()){

Vector carro = new Vector();carro.addElement(new ObjetoCarro(articulo, precio));sesion.setAttribute("miCarro", carro);

} else {Vector carro = (Vector)(sesion.getAttribute("miCarro"));carro.addElement(new ObjetoCarro(articulo, precio));sesion.setAttribute("miCarro", carro);

}

8.3. (*) Mejoras para el carro de la compra

Sobre el ejercicio anterior:

a) Añadid un enlace u opción para invalidar la sesión al llamar aejercicios.CarroServlet. Comprobad que al pincharlo, y luego comprar un artículo, elcarro aparecerá sólo con ese artículo.

b) Si quisiéramos aplicar reescritura de URLs en el ejercicio anterior para prevenir quelas cookies estén deshabilitadas, ¿qué cambios tendríamos que hacer? Dejadlos reflejados

Servlets y JSP

56Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 57: Servlets y JSP - Experto Java

en el código.

Servlets y JSP

57Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 58: Servlets y JSP - Experto Java

9. Contexto y redirecciones

En este tema veremos los elementos que podemos utilizar para establecer unacomunicación entre los distintos servlets de una aplicación web, así como lacomunicación entre los servlets y otros elementos de la aplicación web.

9.1. Contexto global de los servlets

Vamos a comenzar estudiando el contexto de los servlets (Servlet Context). Este objeto decontexto es propio de cada aplicación web, es decir, tendremos un objetoServletContext por aplicación web, por lo que nos servirá para comunicar los servletsde dicha aplicación.

public void init(ServletConfig config)

En la inicialización del servlet (método init), se nos proporcionará un objetoServletConfig como parámetro. Mediante este objeto podemos:

• Obtener el nombre del servlet, que figurará en el descriptor de despliegue de laaplicación web (web.xml en Tomcat).

String nombre = config.getServletName();

• Obtener los valores de los parámetros de inicialización del servlet, que se hayanestablecido en el descriptor de despliegue. Tanto los nombres como los valores de losparámetros son cadenas de texto (String).

String valor_param = config.getInitParameter(nombre_param);Enumeration nombres_params = config.getInitParameterNames();

• Acceder al objeto de contexto de la aplicación a la que pertenece el servlet.

ServletContext context = config.getServletContext();

Esta última función es la más importante, ya que nos permite acceder al objeto decontexto global de la aplicación, con el que podremos realizar una serie de operacionesque veremos a continuación.

Servlets y JSP

58Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 59: Servlets y JSP - Experto Java

Contexto global de los servlets

Tanto el objeto ServletConfig como ServletContext pueden ser obtenidosdirectamente desde dentro de nuestro servlet llamando a los métodos getServletConfigy getServletContext respectivamente, definidos en GenericServlet, y por lo tantodisponibles en cualquier servlet.

9.1.1. Atributos de contexto

Dentro del objeto de contexto de nuestra aplicación podremos establecer una serie deatributos, que serán globales dentro de ella. Estos atributos son un conjunto de pares<nombre, valor> que podemos establecer y consultar desde los distintos servlets denuestra aplicación web. El nombre del atributo será una cadena de texto (String),mientras que el valor podrá ser cualquier objeto java (Object).

Para consultar el valor de un atributo utilizaremos:

Object valor = context.getAttribute(nombre);

Daremos valor a un atributo con:

context.setAttribute(nombre, valor);

Podemos también eliminar un atributo:

context.removeAttribute(nombre);

Lo cual dejará el atributo a null, igual que si nunca le hubiesemos asignado un valor. Porúltimo, con

Enumeration enum = context.getAttributeNames();

Obtenemos la lista de nombres de atributos definidos en el contexto.

Hay que hacer notar en este punto, que el objeto de contexto a parte de ser propio de cadaaplicación web, es propio de cada máquina virtual Java. Cuando trabajemos en un

Servlets y JSP

59Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 60: Servlets y JSP - Experto Java

contexto distribuido, cada máquina ejecutará una VM distinta, por lo que tendrán tambiénobjetos de contexto diferentes. Esto hará que si los servlets de una aplicación se alojan enmáquinas distintas, tendrán contextos distintos y este objeto ya no nos servirá paracomunicarnos entre ellos. Veremos más adelante formas alternativas de comunicaciónpara estos casos.

9.1.2. Parámetros de inicialización

El objeto ServletConfig nos proporcionaba acceso a los parámetros de inicialización delservlet en el que nos encontramos. Con ServletContext, tendremos acceso a losparámetros de inicialización globales de nuestra aplicación web. Los métodos paraobtener dichos parámetros son análogos a los que usabamos en ServletConfig:

String valor_param = context.getInitParameter(nombre_param);Enumeration nombres_params = context.getInitParameterNames();

9.1.3. Acceso a recursos estáticos

Este objeto nos permite además acceder a recursos estáticos alojados en nuestro sitio web.Utilizaremos los métodos:

URL url = context.getResource(nombre_recurso);InputStream in = context.getResourceAsStream(nombre_recurso);

El nombre del recurso que proporcionamos será una cadena que comience por "/", locual indica el directorio raiz dentro del contexto de nuestra aplicación, por lo tanto serándirecciones relativas a la ruta de nuestra aplicación web.

El primer método nos devuelve la URL de dicho recurso, mientras que el segundo nosdevuelve directamente un flujo de entrada para leer dicho recurso.

Hay que señalar que esto nos permitirá leer cualquier recurso de nuestra aplicación comoestático. Es decir, si proporcionamos como recurso "/index.jsp", lo que hará será leerel código fuente del JSP, no se obtendrá la salida procesada que genera dicho JSP.

Podemos también obtener una lista de recursos de nuestra aplicación web, con:

Set recursos = context.getResourcePaths(String ruta);

Nos devolverá el conjunto de todos los recursos que haya en la ruta indicada (relativa alcontexto de la aplicación), o en cualquier subdirectorio de ella.

9.1.4. Redirecciones

Si lo que queremos es acceder a recursos dinámicos, el método anterior no nos sirve. Paraello utilizaremos estas redirecciones. Utilizaremos el objeto RequestDispatcher que nosproporciona ServletContext.

Servlets y JSP

60Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 61: Servlets y JSP - Experto Java

Hemos de distinguir estas redirecciones de la que se producen cuando ejecutamos

response.sendRedirect();

Con sendRedirect lo que estamos haciendo es devolver al cliente una respuesta deredirección. Es decir, será el cliente, quien tras recibir esta respuesta solicite la página a laque debe redirigirse.

Con RequestDispatcher es el servidor internamente quien solicita el recurso al que nosredirigimos, y devuelve la salida generada por éste al cliente, pero todo ello de formatransparente al cliente. En cliente no sabrá en ningún momento que se ha producido unaredirección.

Para obtener un objeto RequestDispatcher podemos usar los siguientes métodos deServletContext:

RequestDispatcher rd = context.getRequestDispatcher(ruta);RequestDispatcher rd = context.getNamedDispatcher(ruta);

Como ruta proporcionaremos la ruta relativa al contexto de nuestra aplicación,comenzando por el carácter "/", del recurso al que nos queramos redirigir. Tambiénpodemos obtener este objeto proporcionando una ruta relativa respecto al recurso actual,utilizando para ello el método getRequestDispatcher del objeto ServletRequest, enlugar de ServletContext:

RequestDispatcher rd = request.getRequestDispatcher(ruta);

Podemos utilizar el RequestDispatcher de dos formas distintas: llamando a su métodoinclude o a forward.

rd.include(request, response);

El método include incluirá el contenido generado por el recurso al que redireccionamosen la respuesta, permitiendo que se escriba este contenido en el objeto ServletResponse

a continuación de lo que se haya escrito ya por parte de nuestro servlet. Se podrá llamar aeste método en cualquier momento. Lo que no podrá hacer el recurso al queredireccionamos es cambiar las cabeceras de la respuesta, ya que lo único que estamoshaciendo es incluir contenido en ella. Cualquier intento de cambiar cabeceras en lallamada a include será ignorado.

Si hemos realizado la redirección utilizando un método getRequestDispatcher (nomediante getNamedDispatcher), en la petición del servlet al que redireccionamospodremos acceder a los siguientes atributos:

javax.servlet.include.request_urijavax.servlet.include.context_pathjavax.servlet.include.servlet_pathjavax.servlet.include.path_infojavax.servlet.include.query_string

Con los que podrá consultar la ruta desde donde fué invocado.

Servlets y JSP

61Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 62: Servlets y JSP - Experto Java

rd.forward(request, response);

El método forward sólo podrá ser invocado cuando todavía no se ha escrito nada en larespuesta del servlet. Esto es así porque esta llamada devolverá únicamente la salida delobjeto al que nos redirigimos. Si esto no fuese así, se produciría una excepciónIllegalStateException. Una vez el método forward haya devuelto el control, la salidaya habrá sido escrita completamente en la respuesta.

Si el recurso al que redireccionamos utiliza direcciones relativas, estás direcciones seconsiderarán relativas al servlet que ha hecho la redirección, por lo que si se encuentranen rutas distintas se producirá un error. Tenemos que hacer que las direcciones seanrelativas a la raiz del servidor para que funcione correctamente (direcciones quecomiencen por "/").

9.1.5. Otros métodos

La clase ServletContext nos proporciona otros métodos de utilidad, que podremosconsultar accediendo a su documentación JavaDoc.

Un método de interés es log, que nos permite escribir texto en el fichero de log delservlet:

context.log(mensaje);

Esto será util para tener un registro de eventos que ocurren en nuestra web, o bien paradepurar errores.

9.1.6. Listeners de contexto

Existen objetos que permanecen a la escucha de los distintos eventos que pueden ocurriren el objeto de contexto de servlets, ServletContext.

Un primer listener, es el ServletContextListener, que nos permitirá dar respuesta a loseventos de creación y destrucción del contexto del servlet. El código para este listenerserá como sigue a continuación:

import javax.servlet.*;

public class MiContextListener implements ServletContextListener {

public void contextDestroyed(ServletContextEvent sce) {// Destruccion del contexto

}

public void contextInitialized(ServletContextEvent sce) {// Inicialización del contexto

}}

Esto nos será de gran utilidad si necesitamos inicializar ciertas estructuras de datos que

Servlets y JSP

62Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 63: Servlets y JSP - Experto Java

van a utilizar varios servlets. De esta forma el contexto se habrá inicializado antes de quelos servlets puedan ejecutarse.

Si lo que queremos es saber cuando se ha añadido, eliminado, o modificado alguno de losatributos del contexto global, podemos utilizar un listenerServletContextAttributeListener. Los métodos que deberemos definir en este casoson los siguientes:

import javax.servlet.*;

public class MiContextAttributeListenerimplements ServletContextAttributeListener {

public void attributeAdded(ServletContextAttributeEvent scae) {// Se ha añadido un nuevo atributo

}

public void attributeRemoved(ServletContextAttributeEvent scae){

// Se ha eliminado un atributo}

public void attributeReplaced(ServletContextAttributeEventscae) {

// Un atributo ha cambiado de valor}

}

Para hacer que estos objetos se registren como listeners y permanezcan a la escucha,deberemos registrarlos como tales en el descriptor de despliegue de la aplicación.Deberemos añadir un elemento <listener> para cada objeto listener que queramosregistrar:

<listener><listener-class>MiContextListener</listener-class>

</listener>

<listener><listener-class>MiContextAttributeListener</listener-class>

</listener>

9.2. Otros métodos de comunicación entre servlets

Como hemos dicho anteriormente, el contexto de los servlets tiene el inconveniente deque se creará uno por cada VM. Por lo tanto, si el contenedor de los servlets se encuentradistribuido en varias máquinas, y los tenemos alojados en distintas VM, accederán acontextos distintos, aunque pertenezcan a una misma aplicación web.

Por lo tanto, en estos casos el contexto no nos servirá para comunicar todos los servlets dela aplicación web. Si queremos hacer una comunicación totalmente global, tendremos queutilizar otros métodos, como almacenar los datos en una base de datos, en sesiones, o bienen Enterprise Java Beans (EJB).

Servlets y JSP

63Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 64: Servlets y JSP - Experto Java

Servlets y JSP

64Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 65: Servlets y JSP - Experto Java

10. Ejercicios de Comunicación

10.1. Ejemplo de contexto

Vamos a probar la aplicación jsp-sesion05-contexto incluida en los ejercicios de lasesión.

a) Desplegar la aplicación web en Tomcat, y acceder a la dirección:

http://localhost:8080/jsp-sesion05-contexto

Veremos la aplicación web ya en marcha.

b) La aplicación web nos permite visualizar los atributos de contexto definidos y susvalores, y añadir nuevos atributos. A parte de los atributos que nosotros añadimosmanualmente, ¿hay más atributos de contexto definidos?

c) Podemos añadir nuevos atributos de contexto. Daremos un nombre del atributo, y untexto que contendrá como valor. Además como valor también se introducirá elidentificador de sesión del navegador que haya creado dicho atributo. Abrir distintosnavegadores y añadir atributos de contexto desde cada uno. Comprobar que en cadanavegador vemos tanto los atributos creados en su sesión, como lo atributos creadoscreados en las sesiones de otros navegadores (el identificador de sesión será distinto).

d) Si nos fijamos en el descriptor de despligue, web.xml, veremos que se ha añadido unlistener sobre los atributos del contexto. Este listener imprime mensajes en el logindicando cuando se añade, elimina o reemplaza un atributo de contexto. Comprobar en elfichero de logs correspondiente que se han registrado los cambios en los atributos quehayamos hecho.

10.2. Chat con servlets

Vamos a realizar una aplicación de chat utilizando servlets. En el directoriojsp-sesion05-chat de los fuentes de la sesión podrás encontrar la base sobre la queconstruiremos el chat. Cada mensaje de chat estará encapsulado en la clase Mensaje, y lalista de mensajes actual del chat se encontrará en la clase ColaMensajes.

Además se proporcionan los ficheros HTML necesarios para la aplicación. El ficheroindex.html contiene el formulario de login para que un usuario introduzca el nick con elque entrará en el chat (no se solicita ningún password para validar). El login se haráefectivo por el servlet LoginUsuarioServlet también proporcionado, que introducirá elnick del usuario en la información de sesión y nos redirigirá al chat. En el subdirectoriochat tendremos los ficheros estáticos del chat:

chatFrames.htmlPágina principal de los frames de la aplicación chat. Mostrará un frame con el

Servlets y JSP

65Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 66: Servlets y JSP - Experto Java

formulario para enviar mensajes, y otro con la lista de mensajes enviados.

enviaMensaje.htmlFormulario para enviar mensajes al chat.

error.html Página que nos muestra un mensaje de error cuando se intenta enviar unmensaje sin haber hecho login.

cabecera.html Cabecera de la tabla de mensajes, a incluir al comienzo de la página de listade mensajes.

pie.html Pie de la tabla de mensajes, a incluir al final de la página de lista de mensajes.

Ahora deberemos implementar los servlets para el envio de mensajes y para la consulta dela lista de mensajes enviados. Se pide:

a) La cola de mensajes será el objeto común al que acceden los servlets para el envio y laconsulta de estos mensajes. Por lo tanto el objeto deberá añadirse como atributo delcontexto. Esto lo tendremos que hacer antes de que cualquier servlet se haya ejecutado.Para ello debemos crear un objeto ServletContextListener que en la creación delcontexto inicialice la cola de mensajes (ColaMensajes) y la introduzca como atributo enel contexto global (atributo es.ua.jtech.jsp.sesion5.chat.mensajes).

b) Una vez tenemos creada la cola de mensajes, deberemos implementar el servletEnviaMensajeServlet, que tome un mensaje como parámetro (el nombre del parámetroes texto), y lo añada a la lista de mensajes con el nick del usuario actual (obtenido delatributo es.ua.jtech.jsp.sesion5.chat.nick de la sesión). Una vez enviado elmensaje, mostraremos en la salida el contenido de enviaMensaje.html, mediante unobjeto RequestDispatcher. Si no hubiese ningún usuario en la sesión, no se registrará elmensaje y se deberá redirigir la salida a error.html

c) Por último, deberemos implementar el servlet ListaMensajesServlet que mostrarátodos los mensajes del chat. Este servlet debe:

• Para que la lista de mensajes se actualice periodicamente en el cliente, haremos que serecargue cada 5 segundos. Añadir la cabecera HTTP correspondiente a la respuestapara que esto ocurra (cabecera Refresh, indicando como valor el número de segundosque tardará en recargar).

• Incluir el contenido del fichero estático cabecera.html al comienzo del documentogenerado, y pie.html al final, para enmarcar la zona donde aparecen los mensajes delchat.

NotaSe debe obtener el PrintWriter para escribir la respuesta antes de hacer el primer include,ya que de lo contrario se obtendría una excepción de tipo IllegalStateException. Estode debido a que el include ya habría obtenido previamente el flujo de salida de la respuesta.

• Obtener el nick del usuario actual de la sesión. Los mensajes enviados con este nick semostrarán en negrita, el resto se mostrarán de forma normal.

Servlets y JSP

66Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 67: Servlets y JSP - Experto Java

d) Comprobar que el chat funciona correctamente. Conectar desde varios clientes a unmismo servidor.

Servlets y JSP

67Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 68: Servlets y JSP - Experto Java

11. JSP Básico

11.1. Introducción a JSP

JSP (JavaServer Pages) es una tecnología que permite incluir código Java en páginasweb. El denominado contenedor JSP (que sería un componente del servidor web) es elencargado de tomar la página, sustituir el código Java que contiene por el resultado de suejecución, y enviarla al cliente. Así, se pueden diseñar fácilmente páginas con partes fijasy partes variables. El siguiente es un ejemplo muy sencillo de página JSP:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><title>Mi primera página JSP</title></head><body><h1> Hoy es:<%= new java.util.Date() %></h1></body></html>

Para ejecutar la página basta con colocarla en una aplicación web (por ejemplo, enTomcat, dentro de webapps/ROOT). No es necesario que sea en un directorio específicocomo ocurre con los servlets, sino que puede ir en cualquier directorio en el que secolocaría normalmente un HTML.

La última versión de la especificación JSP es la 2.0, aunque es de reciente aparición(Tomcat 4.x implementa la versión anterior, la 1.2). Como se verá, es una especificaciónparalela al API de servlets, concretamente a la versión 2.3.

Aunque JSP y servlets parecen a primera vista tecnologías distintas, en realidad elservidor web traduce internamente el JSP a un servlet, lo compila y finalmente lo ejecutacada vez que el cliente solicita la página JSP. Por ello, en principio, JSPs y servletsofrecen la misma funcionalidad, aunque sus características los hacen apropiados paradistinto tipo de tareas. Los JSP son mejores para generar páginas con gran parte decontenido estático. Un servlet que realice la misma función debe incluir gran cantidad desentencias del tipo out.println() para producir el HTML. Por el contrario, los servletsson mejores en tareas que generen poca salida, datos binarios o páginas con gran parte decontenido variable. En proyectos más complejos, lo recomendable es combinar ambastecnologías: los servlets para el procesamiento de información y los JSP para presentarlos datos al cliente.

11.2. Traducción de los JSP a servlets

Como se ha comentado, la primera vez que se solicita una página JSP, el servidor genera

Servlets y JSP

68Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 69: Servlets y JSP - Experto Java

el servlet equivalente, lo compila y lo ejecuta. Para las siguientes solicitudes, solo esnecesario ejecutar el código compilado. El servlet generado de manera automática tieneun método _jspService que es el equivalente al service de los servlets "generadosmanualmente". En este método es donde se genera el código HTML, medianteinstrucciones println y donde se ejecuta el código Java insertado en la página. Porejemplo, la página primera.jsp podría generar un servlet con estructura similar alsiguiente:

public void _jspService(HttpServletRequest request,HttpServletResponse response)throws java.io.IOException,

ServletException {JspWriter out = null;response.setContentType("text/html;ISO-8859-1");out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0

Transitional//EN\">);out.println("<html>");out.println("<head>");out.println("<title>Mi primera pagina JSP</title>");out.println("</head>");out.println("<body>");out.print("Hoy es ");out.println(new java.util.Date());out.println("</body>");out.println("</html>");

}

El directorio donde se coloca el servlet generado, así como su nombre, dependen delservidor web. Por ejemplo, Tomcat utiliza su directoriowork/Catalina/localhost/aplicacion_web. En caso de que la página esté en ROOT, elnombre de la aplicación se sustituye por un carácter de subrayado (_).

11.3. Elementos de JSP

Existen tres tipos de elementos JSP que podemos insertar en una página web:

• Código: podemos "incrustar" código Java de distintos tipos (declaraciones devariables y/o métodos, expresiones, sentencias) para que lo ejecute el contenedor JSP.

• Directivas: permiten controlar distintos parámetros del servlet resultante de latraducción automática del JSP

• Acciones: normalmente sirven para alterar el flujo normal de ejecución de la página(p.ej. redirecciones), aunque tienen usos variados.

Se pueden poner comentarios en una página JSP entre los símbolos <%-- y --%>. Elcontenedor JSP ignorará todo lo contenido entre ambos. Dentro de los fragmentos decódigo Java también se pueden colocar comentarios siguiendo la sintaxis habitual dellenguaje.

11.4. Inserción de código en páginas JSP

Servlets y JSP

69Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 70: Servlets y JSP - Experto Java

Hay tres formas de insertar código Java en una página JSP:

• Expresiones de la forma <%= expresión %>: en este caso, la expresión se evalúa, suresultado se convierte a String y se inserta en la salida.

• Scriptlets de la forma <% código %> : el código se ejecuta dentro del método_jspService del servlet generado.

• Declaraciones de la forma <%! código %>: se insertan en el cuerpo del servletgenerado, fuera de sus métodos.

11.4.1. Expresiones

Como se ha visto, se evalúan, su resultado se convierte a un String y se escriben en lasalida (el objeto predefinido out). La forma de traducir una expresión a código de servletes imprimiéndola en out (mediante una sentencia out.write(expresion)) o similar.

11.4.2. Scriptlets

Permiten ejecutar código arbitrario, cuyo resultado no es necesario enviar a la salida. Sidesde un scriptlet se desea escribir algo en ésta, bastará con utilizar el objeto predefinidoout. Un uso común de los scriptlets es hacer que ciertas partes de código HTMLaparezcan o no en función de una condición. Por ejemplo:

<%java.util.Calendar ahora = java.util.Calendar.getInstance();int hora = ahora.get(java.util.Calendar.HOUR_OF_DAY);

%><b> Hola mundo, <i><% if ((hora>20)||(hora<6)) { %>

buenas noches<% }

else if ((hora>=6)&&(hora<=12)) { %>buenos días

<% }else { %>buenas tardes

<% } %></i> </b>

11.4.3. Declaraciones

Permiten definir variables o métodos que se insertarán dentro del cuerpo del servletgenerado. Esto da la posibilidad de sobreescribir los métodos jspInit y jspDestroy queson el equivalente en JSP del init y destroy de los servlets. Las variables declaradasconservarán su valor entre sucesivas llamadas a la página, ya que son variables miembrodel servlet y no locales al método jspService. Esto nos permite, por ejemplo, crear uncontador de accesos a la página:

<%! private int accesos = 0; %><h1> Visitas: <%= ++accesos %> </h1>

Servlets y JSP

70Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 71: Servlets y JSP - Experto Java

11.4.4. Objetos implícitos de JSP

En cualquiera de estas tres formas, se puede hacer referencia a una serie de objetosimplícitos , que se corresponden con objetos útiles del API de servlets (petición,respuesta, ...) y que en realidad son variables instanciadas de manera automática en elservlet generado a partir del JSP. Los objetos predefinidos en JSP se referencian en latabla 1.

Objeto Significado

request el objeto HttpServletRequest asociado conla petición

response el objeto HttpServletResponse asociadocon la respuesta

out el Writer empleado para enviar la salida alcliente. La salida de los JSP emplea un bufferque permite que se envíen cabeceras HTTP ocódigos de estado aunque ya se hayaempezado a escribir en la salida (out no es unPrintWriter sino un objeto de la claseespecial JspWriter).

session el objeto HttpSession asociado con lapetición actual. En JSP, las sesiones se creanautomáticamente, de modo que este objeto estáinstanciado aunque no se cree explícitamenteuna sesión.

application el objeto ServletContext, común a todos losservlets de la aplicación web.

config el objeto ServletConfig, empleado para leerparámetros de inicialización.

pageContext permite acceder desde un único objeto a todoslos demás objetos implícitos

page referencia al propio servlet generado (tiene elmismo valor que this).Como tal, en Java notiene demasiado sentido utilizarla, pero estápensada para el caso en que se utilizara unlenguaje de programación distinto.

exception Representa un error producido en la aplicación.Solo es accesible si la página se ha designadocomo página de error (mediante la directivapage isErrorPage).

11.5. Directivas de página

Servlets y JSP

71Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 72: Servlets y JSP - Experto Java

Las directivas influyen en la estructura que tendrá el servlet generado a partir de la páginaJSP. Hay tres tipos de directivas:

• page: tiene varios usos: importar clases de Java, fijar el tipo MIME de la respuesta,controlar el buffer de salida,...

• include: sirve para incluir código en la página antes de que se realice la compilacióndel JSP.

• taglib: se emplea cuando el JSP hace uso de etiquetas definidas por el usuario.

El formato genérico de una directiva es:

<%@ directiva atributo="valor" %>

algunas directivas admiten más de un atributo.

11.5.1. La directiva page

La tabla 2 recoge los distintos atributos que admite la directiva page y su significado.

Atributo Significado Ejemplo

import el equivalente a una sentenciaimport de Java

<%@ page import="java.util.Date" %>

contentType genera una cabecera HTTPContent-Type

<%@ page contentType="text/plain" %>

isThreadSafe si es false, el servletgenerado implementará elinterfaceSingleThreadModel (únúnico hilo para todas laspeticiones). Por defecto, elvalor es true.

session Si es false, no se creará unobjeto session de maneraautomática. Por defecto, estrue.

buffer Define el tamaño del bufferpara la salida (en kb), o nonesi no se desea buffer. Suexistencia permite generarcabeceras HTTP o códigos deestado aunque ya se hayacomenzado a escribir la salida.

<%@ page buffer="64kb" %>

autoflush Si es true (valor por defecto),el buffer se envíaautomáticamente a la salida al

Servlets y JSP

72Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 73: Servlets y JSP - Experto Java

llenarse. Si es false, alllenarse el buffer se genera unaexcepción.

extends Permite especificar de quéclase debe descender el servletgenerado a partir de la páginaJSP. No es habitual cambiarlo.

info define una cadena que puedeobtenerse a través del métodogetServletInfo

<%@ page info="carro de la compra"%>

errorPage especifica la página JSP quedebe procesar los erroresgenerados y no capturados enla actual.

<%@ page errorPage="error.jsp" %>

isErrorPage Si es true, indica que lapágina actúa como página deerror para otro JSP. El valorpor defecto es false.

language Permite especificar el lenguajede programación usado en elJSP. En la práctica, el lenguajesiempre es Java, por lo queesta directiva no se usa.

pageEncoding define el juego de caracteresque usa la página. El valor pordefecto es ISO-8859-1.

11.6. Acciones

En JSP existen varios mecanismos para incluir elementos externos en la página actual oredirigir la petición hacia otra página

• La directiva include permite insertar código en la página antes de que ésta setransforme en un servlet. De este modo se pueden reutilizar fragmentos de código JSPo HTML.

• La acción <jsp:include> permite insertar la salida de otra página JSP. Nótese quese incluye la salida generada por el código JSP, no el código propiamente dicho.

• La acción <jsp:plugin> permite incluir applets que hagan uso de Java 2.• La acción <jsp:forward> sirve para redirigir la petición a otra página JSP

11.6.1. La directiva include

Es el equivalente al #include del lenguaje C. su sintaxis es:

Servlets y JSP

73Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 74: Servlets y JSP - Experto Java

<%@ include file="fichero" %>

Como el código se incluye en el servlet generado, los fragmentos de código incluidospueden tener efecto sobre la página actual. Así, se puede utilizar esta directiva paradefinir constantes, generar cabeceras HTTP, ...

El problema de esta directiva es que el estándar no exige que el contenedor JSP detecte demanera automática los cambios en los ficheros incluidos, de manera que si cambia uno deellos puede ser necesario forzar la recompilación de las páginas JSP que los incluyan.

La especificación JSP recomienda que si la página incluida no es una página JSP válidapor sí sola (por ejemplo, porque utiliza variables que se confía que se hayan declaradopreviamente) se utilice la extensión "estándar" .jspf (JSP fragment) y se coloque en undirectorio no público del contenedor JSP (por ejemplo, WEB-INF, que no es accesibledesde el cliente, pero sí desde la directiva).

11.6.2. La acción <jsp:include>

Esta acción incluye en una página la salida generada por otra perteneciente a la mismaaplicación web. La petición se redirige a la página incluida, y la respuesta que genera seincluye en la generada por la principal. Su sintaxis es:

<jsp:include page="URL relativa" flush="true|false"/>

El atributo flush especifica si el flujo de salida de la página principal debería ser enviadoal cliente antes de enviar el de la página incluida. En JSP 1.2 este atributo es optativo, ysu valor por defecto es false. En JSP 1.1 es obligatorio y siempre debía valer true (elforzar el vaciado de buffer era problemático porque una vez que ha sucedido esto no sepueden hacer redirecciones ni ir a páginas de error, ya que ya se han terminado de escribirlas cabeceras).

Esta acción presenta la ventaja sobre la directiva del mismo nombre de que cambios en lapágina incluida no obligan a recompilar la "principal". No obstante, la página incluidasolo tiene acceso al JspWriter de la "principal" y no puede generar cabeceras (porejemplo, no puede crear cookies).

Por defecto, la petición que se le pasa a la página incluida es la original, pero se le puedenagregar parámetros adicionales, mediante la etiqueta jsp:param. Por ejemplo:

<jsp:include page="cabecera.jsp"><jsp:param name="color" value="YELLOW" />

</jsp:include>

11.6.3. La acción <jsp:plugin>

Esta acción sirve para incluir, de manera portable e independiente del navegador, appletsque utilicen alguna librería de Java 2 (Swing, colecciones, Java 2D, ...), ya que lasmáquinas virtuales Java distribuidas con algunos navegadores relativamente antiguos

Servlets y JSP

74Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 75: Servlets y JSP - Experto Java

(Explorer 5.x, Netscape 4.x,...) son de una versión anterior a Java 2.

11.6.4. La acción <jsp:forward>

Esta acción se utiliza para redirigir la petición hacia otra página JSP que esté en la mismaaplicación web que la actual. Un ejemplo de su sintaxis básica es:

<jsp:forward page="principal.jsp"/>

La salida generada hasta el momento por la página actual se descarta (se borra el buffer).En caso de que no se utilizara buffer de salida, se produciría una excepción.

Al igual que en el caso de <jsp:include>, se pueden añadir parámetros a la peticiónoriginal para que los reciba la nueva página JSP:

<jsp:forward page="principal.jsp"><jsp:param name="privilegios" value="root" />

</jsp:forward>

11.7. Servlets y JSPs

Los servlets y los JSPs son tecnologías complementarías. Cada una de ellas es másapropiada para realizar ciertas tareas. Por lo tanto, lo más adecuado será integrar ambastecnologías, y realizar con cada una las tareas más apropiadas para ella.

Los servlets serán adecuados cuando se requiere mucha programación. Por el contrario,los JSPs serán más apropiados para generar la presentación en HTML. Por lo tanto, seráconveniente combinar ambas tecnologías para separar el código y la presentación.

Podremos integrar ambas tecnologías, realizando la programación en el servlet, yredirigiendo al JSP adecuado para que produzca la presentación, utilizando elRequestDispatcher visto anteriormente, bien por el método forward o include.

Puede ser necesario que el servlet proporcione cierta información al JSP, ya que el servleten el procesamiento puede haber producido ciertos datos que el JSP deberá presentar. Unaforma para proporcionar estos datos es establecerlos como atributos en el objetoServletRequest:

MiClase valor = generaDatos();request.setAttribute("nombre", valor);

Este valor podrá ser cualquier objeto Java (Object). En el JSP podremos obtener dichoobjeto de la petición:

<% MiClase valor = (MiClase)request.getAttribute("nombre"); %>

De esta forma pasaremos los datos para únicamente una petición determinada. Siqueremos que estos datos estén disponibles para todas las peticiones que haga un mismocliente a la aplicación, deberemos incluirlos en el ámbito de la sesión. Esto lo haremos en

Servlets y JSP

75Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 76: Servlets y JSP - Experto Java

el servlet de la siguiente forma:

HttpSession session = request.getSession();session.setAttribute("nombre", valor);

Este objeto podrá ser importado por el JSP mediante el objeto session:

<% MiClase valor = (MiClase)session.getAttribute("nombre"); %>

Podemos también incluir estos datos en ámbito del contexto de la aplicación si queremosque estos datos estén disponibles para todas las peticiones que se realicen a la aplicaciónde forma global. En este caso deberemos incluirlos en el ámbito del contexto de lasiguiente forma dentro de nuestro servlet:

ServletContext context = getServletContext();context.setAttribute("nombre", valor);

Este objeto podrá ser importado por el JSP mediante el objeto application:

<% MiClase valor = (MiClase)application.getAttribute("nombre"); %>

Servlets y JSP

76Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 77: Servlets y JSP - Experto Java

12. Ejercicios de JSP Básico

12.1. Conversor JSP

Crear una versión JSP de la aplicación conversor que teníais en el tema de servidoresweb. La aplicación será una única página JSP a la que:

• Si se le llama sin que exista un parametro HTTP numero, mostrará el formulario paraintroducir la cantidad de euros

• Si se la llama con un parámetro HTTP numero tomará el valor del parámetro,realizará la conversión euros/pesetas y la mostrará en pantalla.

Una vez realizada la parte básica, añadirle tratamiento de errores, de manera que si seproduce una excepción en la página conversor.jsp se salte a la página de error,error.jsp (que también debéis crear). En caso de que la cantidad que representa elparámetro numero sea negativa lanzar una excepcion con el mensaje de error deseado(throw new Exception("La cantidad no es correcta")). Imprimir dicho mensajedesde la página de error.

12.2. Contador de visitas

Crear un fragmento de código JSP que sirva como contador de visitas. El objetivo espoder incluir este código en otras páginas JSP, por lo que no es necesario (ni conveniente)que sea una página web completa, sino solo el texto del contador. Este debe aparecer contexto HTML en negrita similar al siguiente

Esta página ha sido visitada X veces

Valorar si sería más conveniente emplear la directiva include o la acción del mismonombre. El código debe poder incluirse en distintas páginas de forma que cada una tengaun contador propio.

(*) Una vez se tenga funcionando el contador básico, mejorarlo haciendo que el númerode visitas se conserve, aunque el servidor se apague o se descargue el JSP de la memoria.Para ello, tener en cuenta que:

• El número de visitas se puede guardar en un fichero con el nombre de la página. Parasimplificar, se puede suponer que en la página principal se define una variable"nombrePag" de tipo String con el nombre del fichero. No obstante, este se podríaobtener a partir del método getRequestURI() del objeto implícito request (estemétodo devuelve la URI completa de la página actual, de la que habrá que extraer elnombre del fichero).

NotaSólo tenemos acceso al objeto request una vez realizada una petición, por lo que no podremos

Servlets y JSP

77Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 78: Servlets y JSP - Experto Java

utilizarlo desde el método jspInit. En su lugar podríamos utilizar, por ejemplo, el nombre dela clase actual.

• Habrá que sobreescribir los métodos public void jspInit() y public void

jspDestroy(), que se ejecutan, respectivamente, cuando la página se carga porprimera vez y cuando se destruye por falta de memoria o porque se apaga el servidor.Al llamar a jspDestroy se debe guardar el número de visitas en el fichero, y cargarlocuando se realice el jspInit.

12.3. Chat con JSPs

En la sesión anterior implementamos un chat con servlets. Hemos visto que los JSP sonmás adecuados para la presentación. Por lo tanto, vamos a modificar el chat para que lalista de mensajes sea generada por un JSP, en lugar de un servlet. Se pide:

a) Crearemos un directorio jsp en la raíz de la web al que no se deberá poder accederdirectamente desde el cliente. Para ello deberemos protegerlo utilizando seguridaddeclarativa y no daremos acceso a usuarios de ningún rol. Este directorio contendráaquellos JSP que utilizan los servlets de la aplicación para presentar la informaciónproducida. Estos JSP serán:

listaMensajes.jspMostrará los mensajes publicados en el chat en forma de documento HTML.Debe esperar recibir un atributoes.ua.jtech.jsp.sesion6.chat.mensajes en el ámbito de la petición(request), con la lista de mensajes publicados en el chat.

error.jsp Mostrará un mensaje de error y permitirá volver a la página de login. Esperarecibir un atributo es.ua.jtech.jsp.sesion6.chat.error en el ámbitode la petición (request), con el mensaje de error que deberá mostrar.

b) Implementar el JSP listaMensajes.jsp. Modificar el servletListaMensajesServlet para que en lugar de generar el mismo el HTML, redirijamediante forward la petición al JSP que acabamos de crear. En el servlet se deberáobtener la lista de mensajes y le deberá pasar este objeto al JSP como atributo de lapetición, como se ha descrito anteriormente.

c) Implementar el JSP error.jsp. Modificar el servlet EnviaMensajeServlet para queen lugar redirigir a error.html en caso de error, lo haga a error.jsp, pasando comoatributo de la petición una cadena con el mensaje de error que deberá mostrar esta página.

12.4. Identificador del usuario (*)

Desarrollar código JSP (debe poderse incluir en cualquier página) que muestre datosbásicos del usuario: IP desde donde se conecta y nombre de usuario (si se haautentificado en la aplicación). El nombre de usuario se puede obtener del método

Servlets y JSP

78Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 79: Servlets y JSP - Experto Java

getRemoteUser() en el objeto implícito request. Se debe poder controlar de manerasencilla desde la página principal el color en que aparece la información. Incluir estecódigo dentro de la página restringida.html que tenéis en la aplicación seguridadincluida en las plantillas de la sesión.

Servlets y JSP

79Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 80: Servlets y JSP - Experto Java

13. JavaBeans y lenguaje de expresiones

13.1. JavaBeans

Un JavaBean (o, para abreviar, un bean) es un componente software reutilizable escritoen Java. En realidad un bean no es más que una clase Java escrita siguiendo unas ciertasconvenciones. Estas convenciones hacen posible que herramientas automáticas puedanacceder a sus propiedades y manipularlas sin necesidad de modificar el código. Estopuede servir en el caso de un IDE, por ejemplo, para realizar "programación visual". EnJSP el uso principal de los beans es manipular componentes Java sin necesidad de incluircódigo en la página, accediendo a sus propiedades mediante etiquetas.

El uso de beans en páginas JSP ofrece diversas ventajas con respecto al uso directo decódigo Java:

• Se evita el uso de sintaxis Java, en su lugar se emplean etiquetas con sintaxis XML.Esto permite separar más fácilmente el trabajo de programadores y diseñadores web.

• Se simplifica la creación y uso de objetos compartidos entre varias páginas.• Se simplifica la creación de objetos a partir de los parámetros de la petición

13.1.1. Características de un bean

Como se ha comentado, un bean no es más que una clase Java en la que se observanciertas convenciones. En lo que respecta a su uso con JSP, estas convenciones afectan almodo de definir constructores, métodos y variables miembro:

1. Un bean debe tener al menos un constructor sin argumentos. Este constructor serállamado cuando una página JSP cree una instancia del bean.

2. Un bean no debe tener variables miembro de acceso público. El acceso a las variablesy su modificación se debe hacer a través de métodos.

3. El nombre de los métodos de acceso y modificación de variables miembro debe seguiruna norma: si la variable tiene el nombre nombreVar, entonces el método de accesodebe llamarse getNombreVar (obsérvese el cambio a mayúsculas de la "N", siguiendolas convenciones habituales de Java), y el método de cambio de valor (en caso de queexista) debe llamarse setNombreVar. En el caso especial de variables booleanas, elmétodo de acceso se debe denominar isNombreVar.

Por ejemplo, supongamos que se desea definir un bean para almacenar informaciónrelativa a un usuario (nombre, número de visitas al sitio, fecha de la última visita y sexo),y compartirla entre varias páginas, una vez que se ha autentificado en la aplicación ysabemos quién es. Para ello podríamos utilizar un código similar al siguiente:

package beans;

import java.util.Date;

Servlets y JSP

80Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 81: Servlets y JSP - Experto Java

public class UsuarioBean{//variables miembro, privadasprivate String nombre;private int visitas;private Date ultimaVisita;private boolean varon;

//constructor sin argumentospublic UsuarioBean() {

nombre = null;visitas = 0;ultimaVisita = null;varon = false;

}

//métodos de acceso: getXXX, isXXXpublic String getNombre() {

return nombre;}

public int getVisitas() {return visitas;

}

public Date getUltimaVisita() {return ultimaVisita;

}

public boolean isVaron() {return varon;

}

//métodos de cambio de valor: setXXXpublic void setNombre(String nom) {

nombre = nom;}

public void setVisitas(int v) {visitas = v;

}

public void setUltimaVisita(Date fecha) {ultimaVisita = fecha;

}

public void setVaron(boolean valor) {varon = valor;

}}

13.1.2. Uso de beans desde páginas JSP

Para interactuar con un bean desde una página JSP es necesario primero asignarle unnombre y especificar qué clase Java lo define. Una vez hecho esto, se puede acceder a sus

Servlets y JSP

81Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 82: Servlets y JSP - Experto Java

propiedades y darles nuevos valores.

1. Acceso al bean

Para hacer accesible un bean a una página JSP se emplea la etiqueta jsp:useBean. En suforma más simple la sintaxis es:

<jsp:useBean id="nombreBean" class="paquete.Clase"/>

En caso de que el bean referenciado no existiera previamente, esta etiqueta se puede vercomo la creación de una variable en Java de nombre nombreBean y de tipopaquete.Clase. Así, para crear un bean de tipo UsuarioBean sería equivalente utilizarlas siguientes expresiones:

<jsp:useBean id="usuario" class="beans.UsuarioBean" />

<% beans.UsuarioBean usuario = new beans.UsuarioBean() %>

La clase a la que pertenece el bean debería colocarse donde están habitualmente las clasesJava que pertenecen a una aplicación web, es decir, en WEB-INF/classes. Para que elcontenedor JSP pueda encontrar la clase del bean, es conveniente que éste pertenezca aun package (como en el ejemplo anterior). En caso contrario se asumiría que pertenece almismo package que el servlet generado a partir del JSP, con el problema de que elnombre de este package es desconocido.

2. Acceso a las propiedades del bean

El acceso a una propiedad se realiza mediante la etiqueta jsp:getProperty. Su sintaxis es:

<jsp:getProperty name="nombreBean" property="nombrePropiedad"/>

donde nombreBean debe corresponderse con el atributo id definido mediante algunaetiqueta anterior jsp:useBean. El acceso a la propiedad también se podría hacerllamando al método Java correspondiente. De este modo, el acceso a la propiedadvisitas del bean usuario se puede hacer mediante las dos formas alternativas:

<jsp:getProperty name="usuario" property="visitas"/>

<%= usuario.getVisitas() %>

aunque se considera preferible la primera forma, ya que la sintaxis es más accesible adiseñadores web que no programen en Java.

3. Asignación de valores a las propiedades del bean

La asignación de valores se realiza mediante la etiqueta jsp:setProperty. Esta etiquetarequiere tres parámetros: name (el id del bean, definido anteriormente mediante algunaetiqueta jsp:useBean), property (el nombre de la propiedad) y value (el valor que sedesea dar a la propiedad). Por ejemplo, para darle a la propiedad visitas del beanusuario el valor 1 se haría:

<jsp:setProperty name="usuario" property="visitas" value="1"/>

Servlets y JSP

82Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 83: Servlets y JSP - Experto Java

Una forma alternativa en código Java sería llamar directamente al método, aunquenormalmente es preferible el uso de la sintaxis anterior:

<% usuario.setVisitas(1) %>

Además de poder asignar a una propiedad un valor fijo, se pueden usar expresiones JSP:

<jsp:setProperty name="usuario" property="ultimaVisita"value="<%= new java.util.Date() %>"/>

4. Inicialización de un bean

En algunos casos, puede ser necesario inicializar un bean antes de empezar a usarlo. Estono se puede hacer directamente con la etiqueta jsp:useBean, ya que no admiteparámetros. Para solucionar el problema, en el cuerpo de la etiqueta jsp:useBean

(siguiendo sintaxis XML) se pueden introducir etiquetas jsp:setProperty queinicialicen las propiedades. Además se pueden colocar scriptlets y código HTML.

<jsp:useBean id="usuario" class="beans.usuarioBean"><b> inicializando datos de usuario </b><jsp:setProperty name="usuario" property="ultimaVisita"

value="<%= new java.util.Date() %>"/></jsp:useBean>

Es importante destacar que el código de inicialización solo se ejecutará en caso de que elbean no existiera previamente (no sea un bean compartido con otras páginas o creado porejemplo por un servlet).

5. Utilizar los parámetros de la petición HTTP

JSP incluye un mecanismo para asignar los valores de los parámetros de la petición a laspropiedades de un bean. Para ello hay que utilizar el parámetro param de la etiquetajsp:setProperty. Por ejemplo, supongamos que se ha definido el siguiente formulario,que toma el nombre del usuario y llama a la página main.jsp con los datos introducidospor el usuario (nombre y sexo):

<html><body><form action="main.jsp" method="get">

Nombre <input type="text" name="nombre"><br>Sexo: varon <input type="radio" name="varon" value="true">

mujer: <input type="radio" name="varon"value="false"> <br>

<input type="submit" value="entrar"></form></body></html>

En la página main.jsp se puede hacer uso de los parámetros para instanciar algunaspropiedades del bean:

<html>

Servlets y JSP

83Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 84: Servlets y JSP - Experto Java

<body><jsp:useBean id="usuario" class="beans.UsuarioBean"/><jsp:setProperty name="usuario" property="nombre"

param="nombre"/><jsp:setProperty name="usuario" property="varon" param="varon"/>Buenos días, <jsp:getProperty name="usuario" property="nombre"/>

</body></html>

Nótese que, aunque los parámetros HTTP son en realidad cadenas, el contenedor JSP escapaz de efectuar la conversión al tipo correspondiente, al menos para tipos primitivos(por ejemplo, se ha convertido de la cadena "true" al valor true que requiere el métodosetVaron. Esta conversión de tipos no funciona en caso de tipos no primitivos. Porejemplo, no se puede aplicar a la propiedad ultimaVisita, de tipo java.util.Date, yaque no se puede convertir automáticamente de cadena a Date (al menos el estándar JSPno lo exige).

En caso de que las propiedades del bean tengan el mismo nombre que los parámetrosHTTP, (como en el caso anterior) la asignación de todos los parámetros se puede hacermediante una única etiqueta setProperty, con el parámetro property="*".

<html><body>

<jsp:useBean id="usuario" class="beans.UsuarioBean"/><jsp:setProperty name="usuario" property="*" />Buenos días, <jsp:getProperty name="usuario" property="nombre"/>

</body></html>

13.1.3. Compartir beans

Hasta el momento, se han tratado los beans como si fueran objetos propios de la páginaen la que se definen, y exclusivos de ella. Este es el comportamiento por defecto, peropodemos cambiar el ámbito de un bean para definir desde dónde será accesible, lo quenos permite compartirlo entre varias páginas. El ámbito se controla con el atributo scope

de la etiqueta jsp:useBean, y puede tomar cuatro valores distintos:

• page: es el valor por defecto• application: el bean será accesible a todas las páginas JSP de la aplicación web, y

compartido entre todos los usuarios. Los servlets pueden acceder a él a través delobjeto ServletContext.

• session: el bean será accesible a todas las páginas JSP, pero cada usuario tendrá supropio objeto. Los servlets pueden acceder a él a través del objeto HttpSession,obteniendo su valor con el método getAttribute.

• request: el bean será accesible durante la petición actual, lo que significa que podránacceder a él las páginas a las que se desvíe la petición con un <jsp:include> o un<jsp:forward>. Los servlets pueden acceder a él a través del objetoServletRequest, de donde se puede obtener su valor con getAttribute.

Servlets y JSP

84Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 85: Servlets y JSP - Experto Java

13.2. Lenguaje de expresiones en JSP 2.0

13.2.1. Introducción al lenguaje de expresiones

Desde las versión 2.0 de JSP se ha introducido en las páginas un lenguaje de expresionesque es equivalente en gran medida a los scriptlets <%= ... %> que venimos utilizandohasta ahora. En realidad, dicho lenguaje se implantó con las primeras versiones de JSTL,una librería de etiquetas JSP que se considera estándar, y que permitía utilizar estelenguaje de expresiones en los atributos de dichas etiquetas, constituyendo unacaracterística muy importante de JSTL.

Cualquier elemento que pertenezca al lenguaje de expresiones irá englobado dentro de lamarca ${...}. En ella podremos colocar nombres de variables que hayamos definido en lapágina, parámetros de petición HTTP, elementos de una sesión... etc.

Por ejemplo, si previamente hemos creado una variable miVar, podríamos acceder a elladesde el propio contenido JSP con algo como:

<h3>La variable miVar vale ${miVar}</h3>

Si lo que queremos es mostrar el parámetro password que hemos tomado de unformulario, para sacarlo por pantalla o guardarlo en alguna base de datos, podríamosacceder a él con algo como:

Accediendo al parámetro ${param.password}

También se pueden utilizar, como veremos, expresiones más complejas, que se evalúandesde el contenedor JSP. Por ejemplo, si tenemos una variable edad para una persona yqueremos comprobar si dicha persona es mayor de edad, podríamos poner:

${edad > 18}

Y luego utilizar el resultado de esta expresión en otras zonas (por ejemplo, etiquetascondicionales de JSTL) para realizar la acción correspondiente.

Se describe a continuación, y a grandes rasgos, el lenguaje de expresiones incluido enJSTL 1.0, y en general a partir de JSP 2.0. El lenguaje está inspirado en los lenguajesECMAScript y XPath, y está basado en espacios de nombres (atributos PageContext),propiedades de elementos, operadores relacionales, lógicos y aritméticos, y un conjuntode objetos implícitos.

13.2.2. Atributos y expresiones

Como hemos comentado anteriormente, podremos invocar a este lenguaje desde cualquierlugar de nuestra página (en JSP 2.0), o dentro de un atributo de una etiqueta JSTL (desdeJSTL 1.0), mediante el elemento ${...}:

Servlets y JSP

85Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 86: Servlets y JSP - Experto Java

${expresion}

Esta expresión podrá estar:

• Por sí sola dentro de un atributo JSTL: :

<c:set var="miVariable" value="${expresion}"/>

En este caso, se evalúa la expresión y el resultado se convierte al tipo de dato delatributo, siguiendo las reglas de conversión internas del lenguaje.

• Combinada con texto dentro de un atributo JSTL:

<c:set var="miVariable" value="texto${e1}y ${e2}texto"/>

Aquí, las expresiones se evalúan de izquierda a derecha, y se intercalan entre el texto,convirtiéndolas a String (siguiendo reglas de conversión internas). Luego, la cadenaresultante se convierte al tipo del atributo en el que esté (si está dentro de algúnatributo).

• Fuera de atributos, dentro del contenido HTML de la página JSP:

<h3>Hola, esto es una página</h3><p>Y aquí ponemos una expresión ${expresion}, para mostrar suvalor</p>

Para cadenas que contengan la secuencia '${' sin que sea propiamente una expresión,se encapsula esa secuencia así: ${'${'}. Por ejemplo:

Cadena con ${'${'}expr}"/>

Mostraría: "Cadena con ${expr}"

13.2.3. Operadores

• Operadores '[ ]' y '.': se unifican los operadores [ ] y . de forma que sonequivalentes:

${expr.campo}${expr["campo"]}

• Operadores aritméticos:

• +, -, *, /: suma, resta, multiplicación y división• div: división entera• %, mod: resto (se mantienen los dos por compatibilidad con XPath y

ECMAScript)• -: cambio de signo

• Operadores relacionales:

• >, gt: mayor que• <, lt: menor que• >=, ge: mayor o igual que

Servlets y JSP

86Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 87: Servlets y JSP - Experto Java

• <=, le: menor o igual que• ==, eq: igual que• !=, ne: distinto que

• Operadores lógicos:

• &&, and: Y lógica• ||, or: O lógica• !, not: NO lógica

• Operador empty: utilizado delante de un elemento, para indicar si el elemento esnulo o vacío (devolvería true) o no (devolvería false). Por ejemplo:

${empty A}

PRECEDENCIA

• [ ], .• ( )• - (cambio de signo), not, !, empty• *, /, div, %, mod• +, -• <, >, <=, >=, lt, gt, le, ge• ==, !=, eq, ne• &&, and• ||, or

EJEMPLOS

${empty param.nombre} // Daría true si el parametro nombre no se haenviado${num1 + num2} // Devolvería el resultado de la suma deambas variables${valor1 >= valor2} // Devolvería true si valor1 es mayor o igualque valor2${v1 ne v2 and v3 < v4} // Daría true si v1 fuese distinto a v2, yv3 menor que v4

13.2.4. Nombres de variables

El lenguaje de expresiones evalúa un identificador o nombre de elemento mirando suvalor como un atributo, según el comportamiento del métodoPageContext.findAttribute(String). Por ejemplo, si ponemos:

${valor}

Se buscará el atributo valor en los ámbitos de página (page), petición (request), sesión(session) y aplicación (application), y si lo encuentra devuelve su valor. Si no, sedevuelve null.

Objetos implícitos

Servlets y JSP

87Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 88: Servlets y JSP - Experto Java

Cuando como nombre de atributo se utiliza alguno de los que el lenguaje de expresionesconsidera como implícitos, se devolverá el objeto asociado. Dichos objetos implícitosson:

• pageContext: el objeto PageContext actual• pageScope, requestScope, sessionScope, applicationScope: para obtener valores de

atributos de página / petición / sesión / aplicación, respectivamente.• param: para obtener el valor de un parámetro de petición. Se obtiene un tipo String

(utilizando el método ServletRequest.getParameter(String))• paramValues: para obtener los valores de un parámetro de petición. Se obtiene un

tipo String[ ] (utilizando el método ServletRequest.getParameterValues(String)).• header: para obtener el valor de un parámetro de cabecera. Se obtiene un tipo String

(utilizando el método ServletRequest.getHeader(String))• headerValues: para obtener los valores de un parámetro de cabecera. Se obtiene un

tipo String[ ] (utilizando el método ServletRequest.getHeaderValues(String)).• cookie: para obtener el valor de una cookie. Se obtiene un objeto Cookie. Las cookies

se buscan con HttpServletRequest.getCookies()• initParam: para obtener el valor de un parámetro de inicialización. Se obtiene un tipo

String (utilizando el método ServletContext.getInitParameter(String))

EJEMPLOS

${sessionScope.profile}

Se obtiene el atributo profile de la sesión

${param.id}

Se obtiene el valor del parámetro id de la petición, o null si no se encuentra.

Palabras reservadas

Se tienen algunos identificadores que no podemos utilizar como nombres de atributos,como son and, eq, gt, true, instanceof, or, ne, le, false, empty, not, lt, ge, null, div y mod.

Servlets y JSP

88Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 89: Servlets y JSP - Experto Java

14. Ejercicios de Beans y lenguaje de expresiones

14.1. Bean cronómetro

Crear un bean denominado beans.CronoBean que sirva como "cronómetro". Cuando elbean se inicialice, debe guardar internamente el momento de su creación. El bean tendráuna propiedad segundos, que devolverá el número de segundos transcurridos desde sucreación. Para calcular tiempos, se puede usar el método System.currentTimeMillis(),que devuelve el número de milisegundos transcurridos entre el instante actual y el1/1/1970.

Probar el bean en una página llamada cronoini.jsp que lo inicialice (mostrando unmensaje HTML que indique que se está inicializando) y muestre el número de segundostranscurridos . Acceder al bean desde otra página crono2.jsp que muestre el mismotemporizador (¿qué ámbito debe tener el bean para funcionar correctamente?).

14.2. Datos de los usuarios

En la plantilla se tiene implementado el bean beans.UsuarioBean explicado en teoría,con los campos que se guardan del usuario. Se tiene el formulario index_usuarios.htmlque sirve para recoger los datos y enviárselos a la página main.jsp que se encargará decrear el bean con los datos y mostrar un mensaje de bienvenida. La página también deberátener un enlace Ver datos para mostrar los datos del usuario, que apunta a la páginadatosusuarios.jsp.

Se pide:

• Implementar la página main.jsp para que cree un bean (si no existe ya), actualice losvalores correspondientes (número de visitas y fecha de la última visita), y saque todoslos datos por pantalla. Modificar el ámbito del bean para que tenga validez suficientecomo para verse desde diferentes páginas (pero que sean beans distintos para usuariosdistintos).

• Implementar la página datosusuarios.jsp para que muestre los datos de la personautilizando lenguaje de expresiones. Para ello deberéis volver a cargar el bean en estapágina, utilizando jsp:useBean antes de mostrar sus datos.

• Indicad, mediante "SI" o "NO" en la página, y utilizando lenguaje de expresiones, siel usuario ha superado las 10 visitas.

AYUDA: se admite el operador '?:' en lenguaje de expresiones. Si tenemos las visitasen la variable visitas, podríamos poner algo como:

${visitas > 10?'SI':'NO'}

Servlets y JSP

89Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 90: Servlets y JSP - Experto Java

15. Introducción a las librerías de tags

15.1. Conceptos básicos sobre librerías de tags

Las librerías de tags (taglibs) son conjuntos de etiquetas HTML personalizadas quepermiten encapsular determinadas acciones, mediante un código Java subyacente. Esdecir, se define lo que va a ejecutar la etiqueta mediante código Java, y luego se le da unnombre a la etiqueta para llamarla desde las páginas JSP, estableciendo la relación entreel nombre de la etiqueta y el código Java que la implementa.

Por ejemplo, una página JSP que hace uso de librerías de tags podría tener este aspecto:

<%@ taglib uri="ejemplo" prefix="ej" %><html><body><h1>Ejemplo de librerias de tags</h1><ej:mitag>Hola a todos</ej:mitag><br><ej:otrotag/></body></html>

donde se utiliza una librería llamada ejemplo, que se simplifica con el prefijo ej, deforma que todos los tags de dicha librería se referencian con dicho prefijo y dos puntos,teniendo la forma ej:tag. Se utilizan así los tags mitag y otrotag.

Para poder utilizar las taglibs necesitamos tener una versión de JSP 1.1 o superior.Veremos a continuación aspectos generales sobre las librerías de tags, para pasar despuésa ver dos ejemplos concretos de librerías ya hechas. Más adelante veremos cómo crearnuestras propias librerías de tags.

15.1.1. El gestor de tags

Cuando escribimos un tag (etiqueta) de una librería en una página JSP, un gestor de tagsse pone en funcionamiento en el servidor para interactuar entre la página JSP y losobjetos relacionados con dicho tag y su librería.

Existen dos interfaces principales que describen un gestor de tags, en el paquetejavax.servlet.jsp.tagext. Cada tag que se cree implementará una de las dos:

• Tag: para tags simples, que no manejan el contenido de los mismos• BodyTag: una extensión del anterior que permite manipular el contenido (cuerpo) de

los tags

El gestor se encarga de llamar a su método doStartTag() cuando comienza el mismo.Este método puede devolver tres valores:

• EVAL_BODY_INCLUDE: explora el cuerpo del tag, para tags de tipo Tag

Servlets y JSP

90Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 91: Servlets y JSP - Experto Java

• EVAL_BODY_TAG: explora el cuerpo del tag, para tags del tipo BodyTag. Con estopodremos manipular el cuerpo del tag.

• SKIP_BODY: no explora el cuerpo del tag

Cuando se termina el tag, se llama al método doEndTag() que puede devolver:

• EVAL_PAGE: para continuar evaluando la página• SKIP_PAGE: para no continuar evaluando la página

Estos valores devueltos permiten al contenedor JSP decidir cómo evaluar el resto de lapágina JSP.

Para los gestores de tipo BodyTag, se tienen los métodos doInitBody() y doAfterBody()para poder manipular el cuerpo del tag al procesarlo.

Los gestores de tags que se tengan deberán colocarse en el directorio WEB-INF/classes

o WEB-INF/lib de la aplicación donde se utilicen (dependiendo de si son ficheros .classsueltos o están empaquetados en ficheros JAR).

15.1.2. El descriptor de la librería de tags

El descriptor de la librería de tags (TLD) es un fichero utilizado para interpretarpáginas que incluyan dicha librería. Contiene directivas que describen la librería, parapoderla utilizar. Es un fichero XML que mapea acciones con clases de tags.

1. Definición del fichero TLD en el descriptor de despliegue (web.xml)

Para encontrar y utilizar este fichero TLD, se utiliza una etiqueta de tipo taglib en elfichero descriptor de despliegue (web.xml) de nuestra aplicación. Así, para cada taglibque se emplee en la aplicación se tendrá un grupo de texto de este tipo en dicho fichero:

<taglib><taglib-uri>identificador</taglib-uri><taglib-location>fichero.tld</taglib-location>

</taglib>

• taglib-uri es un nombre identificativo de la librería• taglib-location indica dónde se encuentra el fichero TLD (por ejemplo, en

/WEB-INF/fichero.tld)

2. Contenido del fichero TLD

Por otra parte, el fichero TLD de la librería tiene un contenido como:

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE taglib PUBLIC "-//Sun Microsystems,Inc.//DTD JSP Tag Library 1.1//EN""http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>

<tlibversion>1.0</tlibversion>

Servlets y JSP

91Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 92: Servlets y JSP - Experto Java

<jspversion>1.1</jspversion><shortname>pt</shortname><uri>pruebatags</uri><info>Librería de prueba</info>

<tag><name>prueba</name><tagclass>Prueba</tagclass><bodycontent>empty</bodycontent><info>Tag de prueba</info><attribute>

<name>nombre</name><required>false</required><rtexprvalue>false</rtexprvalue>

</attribute></tag>

</taglib>

Se especifica al principio que es un fichero XML, y el DOCTYPE del mismo. La etiquetaraíz del documento es taglib, y puede tener como subetiquetas:

• tlibversion: con la versión de la librería• jspversion: versión requerida de JSP para utilizar la librería• shortname: nombre corto para referenciar a la librería desde JSP• uri: identificador de la librería (el mismo que el indicado en el fichero web.xml)• info: cadena descriptiva de la librería

Tras las etiquetas anteriores, tendremos una etiqueta de tipo tag por cada tag de lalibrería. Esta etiqueta puede tener como subetiquetas:

• name: nombre de la etiqueta, para llamarla desde JSP• tagclass: clase Java que implementa la etiqueta• teiclass: para etiquetas TEI (no las veremos) (opcional)• bodycontent: tipo de contenido del cuerpo de la etiqueta: empty (sin contenido),

tagdependent (cuerpo evaluado por la propia clase que implementa el tag), o jsp(cuerpo evaluado por el contenedor JSP que procesa la página)

• info: información sobre el tag (opcional)• attribute: atributos o parámetros del tag. Puede tener como subetiquetas:

• name: nombre del atributo• required: indica si el atributo es requerido (true) o no (false)• rtexprvalue: indica si se pueden asignar valores dinámicos, como expresiones

JSP (true), o no (false). Por defecto es false.

15.1.3. Carga de taglibs en ficheros JSP

Para poder utilizar taglibs en ficheros JSP, se colocan al principio del fichero (antes decualquier acción) directivas del tipo:

<%@ taglib uri="identificador" prefix="prefijo" %>

Servlets y JSP

92Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 93: Servlets y JSP - Experto Java

donde:

• uri es el identificador de la librería (indicado también en el fichero descriptor dedespliegue (web.xml)). Normalmente cada librería tiene una URI que es la que serecomienda utilizar, y en algunos casos utilizar esa URI evita tener que disponer delfichero TLD en nuestra aplicación

• prefix es un prefijo para llamar a los tags de la librería

15.1.4. Ejemplo

Veremos ahora cómo utilizar una librería de tags. Supongamos que tenemos una libreríallamada prueba, de forma que las clases Java que la implementan (los gestores de tags)están en un fichero prueba.jar, y el fichero descriptor es prueba.tld. Supongamos queel identificador (el uri) de la librería es prueba, y supongamos que la librería tiene untag, llamado hola, sin cuerpo, que saca por pantalla el texto "hola a todos".

Para utilizar esta librería en una aplicación web, seguimos los pasos:

• Copiar el fichero JAR en el directorio WEB-INF/lib de la aplicación• Copiar el fichero TLD en el directorio WEB-INF de la aplicación• Añadir en el descriptor de despliegue (web.xml) el bloque <taglib> correspondiente

para la librería:

<taglib><taglib-uri>prueba</taglib-uri><taglib-location>

/WEB-INF/prueba.tld</taglib-location>

</taglib>

• Añadir al principio de cada página JSP donde vayamos a utilizar la librería la línea:

<%@ taglib uri="prueba" prefix="pr" %>

donde el prefix puede ser el que queramos.

Con esto, por ejemplo, podemos utilizar la librería así:

<%@ taglib uri="prueba" prefix="pr" %><html><body><pr:hola/></body></html>

Vemos que el prefijo se utiliza para anteponerlo al nombre de cada tag de la librería, en laforma prefijo:tag.

15.2. Ejemplo de librería: request

Servlets y JSP

93Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 94: Servlets y JSP - Experto Java

La librería request es una librería desarrollada en el proyecto Jakarta (los autores de losservidores Apache y Tomcat), y que permite acceder a la información acerca de unapetición HTTP realizada. De esta forma podremos acceder a los parámetros de entrada deuna petición GET o POST, a las cabeceras HTTP, cookies, etc.

Se tiene información detallada sobre esta librería en:

http://jakarta.apache.org/taglibs/doc/request-doc/intro.html

15.2.1. Uso de la librería

Para utilizar la librería request en una aplicación web, seguimos los pasos:

• Copiar el fichero TLD (request.tld) en el directorio WEB-INF de la aplicación• Copiar el fichero JAR con la implementación de los tags (request.jar) en el

directorio WEB-INF/lib de la aplicación• Añadir al descriptor de despliegue de la aplicación (web.xml) una marca taglib con

información sobre la librería:

<taglib><taglib-uri>http://jakarta.apache.org/taglibs/request-1.0</taglib-uri><taglib-location>/WEB-INF/request.tld</taglib-location>

</taglib>

• Finalmente, en las páginas JSP donde vayamos a utilizar la librería, se añade alprincipio la línea:

<%@ tagliburi="http://jakarta.apache.org/taglibs/request-1.0"prefix="req" %>

donde el prefijo puede ser el que queramos

15.2.2. Algunos tags de la librería

Veremos ahora algunos de los tags con los que cuenta esta librería. Para los ejemplos quese verán, suponemos que se ha indicado un prefijo (prefix) "req":

1. Información de la petición

request

Para obtener información sobre la petición HTTP.

ATRIBUTOS

• id: permite luego obtener los datos de la petición con el mismo id. Los datos de la

Servlets y JSP

94Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 95: Servlets y JSP - Experto Java

petición se obtienen mediante tags jsp:getProperty donde:

• como parámetro name se pasa el id asignado al tag• como parámetro property se pasa la propiedad que se quiere obtener, que por

ejemplo puede ser:

• remoteUser: obtiene el login del usuario que realizó la petición• contentLength: obtiene la longitud en bytes de la petición• remoteHost: obtiene el nombre del cliente que realizó la petición, o la IP si no

puede determinarse el nombre• ...etc.

EJEMPLO

<req:request id="req">Tamaño peticion:<jsp:getProperty name="req"property="contentLength"/><br>Direccion cliente:<jsp:getProperty name="req"property="remoteHost"/>

</req:request>

2. Toma de parámetros

parameter

Obtiene el valor de un parámetro determinado. No tiene cuerpo.

ATRIBUTOS

• name: nombre del parámetro del que se quiere su valor.

EJEMPLO

<req:parameter name="param1"/>

parameters

Recorre toda la lista de parámetros

ATRIBUTOS

• name: para buscar los valores para un parámetro de nombre determinado. Esteatributo es opcional.

• id: permite luego obtener los datos de la petición con el mismo id. Los datos de lapetición se obtienen mediante tags jsp:getProperty donde:

• como parámetro name se pasa el id asignado al tag• como parámetro property se pasa la propiedad que se quiere obtener, que

pueden ser:

• name: obtiene el nombre del parámetro

Servlets y JSP

95Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 96: Servlets y JSP - Experto Java

• value: obtiene el valor del parámetro

EJEMPLO

<req:parameters id="id1">Nombre:<jsp:getProperty name="id1"property="name"/><br>Valor:<jsp:getProperty name="id1"property="value"/><br>

</req:parameters>

<req:parameters id="id1" name="param1">Valor:<jsp:getProperty name="id1"property="value"/><br>

</req:parameters>

parameterValues

Recorre la lista de valores para un parámetro con múltiples valores. Debe estar incluidodentro de un tag parameters, recorriendo así los valores del parámetro que se estéexplorando.

ATRIBUTOS

• id: permite luego obtener los datos de la petición con el mismo id. Los datos de lapetición se obtienen mediante tags jsp:getProperty donde:

• como parámetro name se pasa el id asignado al tag• como parámetro property se pasa value, que obtiene el valor del parámetro

EJEMPLO

<req parameters id="id1" name="param1"><req:parameterValues id="id2">

Valor:<jsp:getProperty name="id2"property="value"/><br>

</req:parameterValues></req:parameters>

equalsParameter

Comprueba si el valor del parámetro coincide con un determinado valor

ATRIBUTOS

• name: nombre del parámetro que se compara

Servlets y JSP

96Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 97: Servlets y JSP - Experto Java

• match: cadena con la que tiene que coincidir• value indica si deben coincidir (true) o no (false) (por defecto es true). Este

parámetro es opcional.• ignoreCase: si deben coincidir mayúsculas y minúsculas (false, valor por defecto) o

no (true). Este parámetro es opcional.

EJEMPLO

<req:equalsParameter name="param1"match="hola" value="false">

El parametro no coincide</req:equalsParameter><req:equalsParameter name="param1"match="hola">

El parametro si coincide</req:equalsParameter>

existsParameter

Comprueba si existe un determinado parámetro

ATRIBUTOS

• name: nombre del parámetro que se busca• value: indica si debe existir (true) o no (false) (por defecto es true). Este

parámetro es opcional

EJEMPLO

<req:existsParameter name="param1"value="false">

El parametro no existe</req:existsParameter>

3. Cookies

cookie

Obtiene el valor de una cookie determinada. Similar a parameter.

<req:cookie name="nombre"/>

cookies

Recorre toda la lista de cookies

ATRIBUTOS

• name: para buscar los valores para una cookie de nombre determinado. Esteparámetro es opcional.

• id: permite luego obtener los datos de la petición con el mismo id. Los datos de lapetición se obtienen mediante tags jsp:getProperty donde:

• como parámetro name se pasa el id asignado al tag

Servlets y JSP

97Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 98: Servlets y JSP - Experto Java

• como parámetro property se pasa la propiedad que se quiere obtener, quepueden ser, por ejemplo:

• name: obtiene el nombre de la cookie• value: obtiene el valor de la cookie• maxAge: obtiene el tiempo de expiración

EJEMPLO

<req:cookies id="id1">Nombre:<jsp:getProperty name="id1"property="name"/><br>Valor:<jsp:getProperty name="id1"property="value"/><br>Max tiempo:<jsp:getProperty name="id1"property="maxAge"/><br>

</req:cookies>

equalsCookie

Obtiene si el valor de una cookie coincide con una cadena dada (similar aequalsParameter)

existsCookie

Obtiene si existe una cookie dada (similar a existsParameter)

4. Cabeceras

header

Obtiene el valor de una cabecera determinada (similar a cookie o a parameter)

<req:header name="nombre"/>

headerValues

Obtiene todos los valores de una cabecera con múltiples valores (similar aparameterValues)

headers

Recorre toda la lista de cabeceras. Similar a parameters.

equalsHeader

Obtiene si el valor de una cabecera coincide con una cadena dada (similar aequalsParameter)

Servlets y JSP

98Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 99: Servlets y JSP - Experto Java

existsHeader

Obtiene si existe una cabecera dada (similar a existsParameter)

15.2.3. Ejemplo de uso

Dado el siguiente formulario index.html:

<html><body>

<form action="request.jsp">Nombre:<input type="text" name="nombre"><br>Descripcion:<input type="text" name="descripcion"><br><input type="submit" value="Enviar">

</form></body></html>

Al validarlo cargamos la página request.jsp, donde tenemos un ejemplo de cómoobtener los valores de los parámetros del formulario:

<%@ tagliburi="http://jakarta.apache.org/taglibs/request-1.0"prefix="req" %>

<html><body>

Nombre:<req:parameter name="nombre"/><br><req:existsParameter name="descripcion" value="true">

Descripcion:<req:parameter name="descripcion"/>

</req:existsParameter><br>

</body></html>

Para probarlo, deberíamos utilizar los ficheros TLD y JAR de la librería request,copiados ya en WEB-INF y WEB-INF/lib, respectivamente. Podemos probar el ejemplocon:

http://localhost:8080/apptaglibs/indexrequest.html

15.3. Ejemplo de librería: dbtags

La librería dbtags es otra librería desarrollada en el proyecto Jakarta que permitemanipular bases de datos SQL. Requiere al menos la versión 1.2 de JSP (aunque enalgunos servidores como Tomcat funciona con la 1.1). También necesita objetos

Servlets y JSP

99Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 100: Servlets y JSP - Experto Java

DataSource, que no son parte de JDK estándar (SE). Para poderlos utilizar, tenemos quetrabajar también con JDK Enterprise Edition, o bien utilizar la API para JDBC quecorresponda.

Se tiene información detallada sobre esta librería en:

http://jakarta.apache.org/taglibs/doc/dbtags-doc/index.html

15.3.1. Uso de la librería

Para utilizar la librería dbtags en una aplicación web, seguimos los pasos:

• Copiar el fichero TLD (dbtags.tld) en el directorio WEB-INF de la aplicación• Copiar el fichero JAR con la implementación de los tags (dbtags.jar) en el

directorio WEB-INF/lib de la aplicación• Añadir al descriptor de despliegue de la aplicación (web.xml) una marca taglib con

información sobre la librería:

<taglib><taglib-uri>http://jakarta.apache.org/taglibs/dbtags</taglib-uri><taglib-location>/WEB-INF/dbtags.tld</taglib-location>

</taglib>

• Finalmente, en las páginas JSP donde vayamos a utilizar la librería, se añade alprincipio la línea:

<%@ tagliburi="http://jakarta.apache.org/taglibs/dbtags"prefix="sql" %>

donde el prefijo puede ser el que queramos

15.3.2. Algunos tags de la librería

Veremos ahora algunos de los tags con los que cuenta esta librería. Para los ejemplos quese verán, suponemos que se ha indicado un prefijo (prefix) "sql":

1. Conexión / Desconexión a la base de datos

connection

Este tag permite conectar a una base de datos, bien a través de una URL, o un objetoDataSource. Veremos el primer caso, por ser más común.

ATRIBUTOS

• id: para identificar la conexión.

Servlets y JSP

100Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 101: Servlets y JSP - Experto Java

Luego, dentro, se tienen cuatro subtags:

• url: indica la URL de la base de datos a la que conectar. En este caso, una base dedatos MySQL llamada prueba. Es el único subtag que hay que indicarobligatoriamente

• driver: driver para conectar con la base de datos (opcional)• userId: login del usuario que conecta (opcional)• password: password del usuario que conecta (opcional)

EJEMPLO

<sql:connection id="con1"><sql:url>jdbc:mysql://localhost/prueba</sql:url><sql:driver>org.gjt.mm.mysql.Driver</sql:driver><sql:userId>root</sql:userId><sql:password>mysql</sql:password>

</sql:connection>

closeConnection

Desconecta de una base de datos

ATRIBUTOS

• conn el id de la conexión que se hubiera abierto y queremos cerrar.

EJEMPLO

<sql:closeConnection conn="con1"/>

2. Sentencias SQL

statement

Este tag permite crear una sentencia SQL para lanzarla a la base de datos.

ATRIBUTOS

• id: para identificar la sentencia SQL• conn: el id de la conexión (abierta previamente) con que nos conectamos a la base

de datos.

Luego, dentro, se tienen los subtags:

• query: para indicar la query SQL que se va a ejecutar• execute: para ejecutar la sentencia (caso de sentencias INSERT, UPDATE, DELETE)• resultSet: para obtener y explorar los resultados de una sentencia SELECT. El

contenido del tag resultSet se ejecuta una vez para cada registro que se hayaobtenido con el SELECT. Podemos utilizar en este bucle los tags:

Servlets y JSP

101Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 102: Servlets y JSP - Experto Java

• getColumn: permite obtener los valores de cada columna de un registro, bien porel nombre de la columna (atributo colName), bien por la posición (atributoposition). Existen tags similares, como getNumber, getTime, etc, para obtenercolumnas con un tipo de datos específico.

• wasEmpty: acciones a realizar si la consulta SELECT no devuelve ningúnregistro. Es una etiqueta relacionada con resultset, aunque se utiliza fuera deesta etiqueta.

• wasNotEmpty: acciones a realizar si la consulta SELECT devuelve algúnregistro. Es una etiqueta relacionada con resultset, aunque se utiliza fuera deesta etiqueta.

EJEMPLO

<sql:statement id="s1" conn="con1"><sql:query>INSERT INTO datos(nombre, desc)VALUES('nombre1','descripcion1')</sql:query><sql:execute/>

</sql:statement>

<sql:statement id="s1" conn="con1"><sql:query>

SELECT * FROM datos</sql:query><sql:resultSet id="rs1">

Nombre:<sql:getColumn colName="id"/><br>Descripcion:<sql:getColumn position="2"/><br>

</sql:resultSet><sql:wasEmpty>

No hay resultados que mostrar</sql:wasEmpty><sql:wasNotEmpty>

Hay resultados que mostrar</sql:wasNotEmpty>

</sql:statement>

15.3.3. Ejemplo de uso

El siguiente ejemplo completo, tomando los fragmentos anteriores, se conecta a una basede datos MySQL para obtener todos los nombres y descripciones de su tabla datos:

<%@ tagliburi="http://jakarta.apache.org/taglibs/dbtags"prefix="sql" %>

<html><body>

<sql:connection id="con1">

Servlets y JSP

102Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 103: Servlets y JSP - Experto Java

<sql:url>jdbc:mysql://localhost/prueba</sql:url><sql:driver>org.gjt.mm.mysql.Driver</sql:driver><sql:userId>root</sql:userId><sql:password>mysql</sql:password>

</sql:connection>

<sql:statement id="s1" conn="con1"><sql:query>

SELECT * FROM datos</sql:query><sql:resultSet id="rs1">

Nombre:<sql:getColumn colName="nombre"/><br>Descripcion:<sql:getColumn position="2"/><br>

</sql:resultSet><sql:wasEmpty>

No hay resultados que mostrar</sql:wasEmpty>

</sql:statement>

<sql:closeConnection conn="con1"/></body></html>

Para probar el ejemplo (una vez instalada la base de datos y establecida la contraseña deacceso al servidor), cargaríamos la página JSP con:

http://localhost:8080/apptaglibs/dbtags.jsp

15.4. Otras consideraciones acerca de las librerías de tags

15.4.1. Uso de los tags

Se pueden colocar tags en varios lugares de nuestra página JSP. Podemos por ejemploutilizar un tag request para obtener un valor de parámetro que utilizar en la sentenciaSQL de un dbtag:

<sql:statement id="s1" conn="con1"><sql:query>

SELECT * FROM datos WHEREnombre = '<req:parameter name="nombre"/>'

</sql:query><sql:execute/>

</sql:statement>

O establecer un enlace en función de un parámetro:

Servlets y JSP

103Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 104: Servlets y JSP - Experto Java

<a href="http://<req:parameter name="url"/>">Enlace dinamico</a>

15.4.2. Comunicación entre JSP y las taglibs

En ocasiones nos puede interesar comunicar código JSP con código de taglibs: obtenerdentro de JSP el valor de una taglib, o al revés, por ejemplo.

Si queremos utilizar código JSP en una taglib, podemos hacerlo sin problemas. Porejemplo, el siguiente código obtiene las 3 primeras columnas de cada registro de unaSELECT:

<sql:statement id="s1" conn="con1"><sql:query>

SELECT * FROM datos</sql:query><sql:resultSet id="rs1">

<% for (int i = 1; i <= 3; i++) { %>Valor:<sql:getColumn position="<%=i%>"/><br><% } %>

</sql:resultSet></sql:statement>

NOTA: algunos atributos de ciertas etiquetas no admiten que se utilicen scriptlets enellos.

El caso contrario, obtener valores de taglibs dentro de código JSP, es más complejo detratar. Algunas etiquetas instancian código Java que es directamente accesible desde JSP,con el nombre que se les da en la etiqueta. Por ejemplo, para saber si una conexión estácerrada, podemos hacerlo con:

<sql:connection id="con1"><sql:url>jdbc:mysql://localhost/prueba</sql:url><sql:driver>org.gjt.mm.mysql.Driver</sql:driver>

</sql:connection>...<% if (con1.getClosed()) { %>

La conexion esta cerrada<% } %>

En otros casos la comunicación no es tan directa, y hay que ver en la documentación deltag en cuestión cómo podemos acceder a su valor. Por ejemplo, para la etiquetagetColumn , podemos utilizar un atributo to para indicar un nombre de variable dondeguardar su valor. Luego, desde JSP, utilizando el método getAttribute() del objetopageContext podemos acceder a dicho valor. Por ejemplo:

<sql:getColumn colName="nombre" to="nombrePersona"/>...<% if (pageContext.getAttribute("nombrePersona").equals("Pepe")) {%>

Hola Pepe<% } %>

Servlets y JSP

104Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 105: Servlets y JSP - Experto Java

15.4.3. Más información

Podemos encontrar información detallada sobre las librerías de tags del proyecto Jakartaen:

http://jakarta.apache.org/taglibs/index.html

Servlets y JSP

105Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 106: Servlets y JSP - Experto Java

16. Ejercicios de introducción a las librerías de tags

En la plantilla tenemos una aplicación jsp-sesion8 que va a almacenar en una base dedatos datosusuarios, en su tabla usuarios, los datos de los usuarios que se registren. Paraello utilizaremos las librerías de tags request y dbtags vistas en la parte teórica.

16.1. Configuración de librerías de tags

Como primer ejercicio, vamos a configurar la aplicación jsp-sesion8 para poder trabajarcon las librerías:

• Tenemos los ficheros TLD de las librerías (dbtags.tld y request.tld) en el directorioWEB-INF de la aplicación (carpeta web)

• Tenemos los ficheros JAR de las librerías (dbtags.jar y request.jar) en el directorioWEB-INF/lib de la aplicación (carpeta web)

• Modificamos el fichero descriptor de la aplicación (web.xml), añadiéndole lasetiquetas para que acepte las dos librerías:

<taglib><taglib-uri>http://jakarta.apache.org/taglibs/request-1.0</taglib-uri><taglib-location>/WEB-INF/request.tld</taglib-location>

</taglib>

<taglib><taglib-uri>http://jakarta.apache.org/taglibs/dbtags</taglib-uri><taglib-location>/WEB-INF/dbtags.tld</taglib-location>

</taglib>

16.2. Registro de usuarios

Una vez tengamos la aplicación configurada, construiremos dos páginas:

• Una página form_registro.html que contendrá un formulario con los siguientescampos de texto:

• nombre: con el nombre del usuario• email: con su correo electrónico• login: nick que utilizará para entrar a la aplicación• password: con la contraseña para validarlo• telefono: con el número de teléfono

Servlets y JSP

106Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 107: Servlets y JSP - Experto Java

• El formulario anterior tendrá un botón de submit que nos enviará a una páginaregistro.jsp, que se encargará de introducir los datos del usuario en la base de datos,tomándolos de los parámetros de la petición (utilizando la librería request), eintroduciéndolos en la base de datos (utilizando dbtags)

La aplicación mostrará un mensaje indicando si los datos se han introducidocorrectamente, o ha habido algún error. Para comprobar si ha habido algún error alinsertar, podemos buscar tras la inserción un registro con los datos insertados, y mostrarel mensaje de error si no existe:

<%@ taglib uri="http://jakarta.apache.org/taglibs/request-1.0"prefix="req" %><%@ taglib uri="http://jakarta.apache.org/taglibs/dbtags"prefix="sql" %>...<sql:connection id="con1">

...</sql:connection>

<sql:statement id="s1" conn="con1"><sql:query>

INSERT INTO usuarios(nombre, email...)VALUES('<req:parameter name="nombre"/>','<req:parameter name="email"/>'...)

</sql:query><sql:execute/>

</sql:statement>

<sql:statement id="s1" conn="con1"><sql:query>

SELECT * FROM usuariosWHERE nombre='<req:parameter name="nombre"/>'AND email='<req:parameter name="email"/>'AND ...

</sql:query><sql:resultSet id="rs1"></sql:resultSet><sql:wasEmpty>Error al insertar</sql:wasEmpty><sql:wasNotEmpty>...</sql:wasNotEmpty>

</sql:statement>

<sql:closeConnection conn="con1"/>

Si se produce un error al insertar, es probable que el servidor lance una excepción. Porejemplo, en el caso de que intentemos introducir un nombre que ya existe. No esnecesario que capturemos ese error. Se deja como optativo comprobar, antes de insertar,si existe el nombre en la BD.

Nota: En el directorio db se encuentra el script para la creación de la BD.

16.3. Listado de usuarios y otras mejoras

Sobre lo anterior, podemos realizar una página listado.jsp que muestre un listado con los

Servlets y JSP

107Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 108: Servlets y JSP - Experto Java

usuarios actualmente registrados

(*) Para cada uno, hacer que permita eliminarlo de la lista (se borrarían sus datos de labase de datos), o modificar sus datos (mostrando en otra página un formulario con susdatos para editarlos).

Servlets y JSP

108Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 109: Servlets y JSP - Experto Java

17. JSTL

JSTL (JavaServer Pages Standard Tag Library) es una librería de tags estándar queencapsula, en forma de tags, muchas funcionalidades comunes en aplicaciones JSP, deforma que, en lugar que tener que recurrir a varias librerías de tags de distintosdistribuidores, sólo necesitaremos tener presente esta librería que, además, por el hechode ser estándar, funciona de la misma forma en cualquier parte, y los contenedorespueden reconocerla y optimizar sus implementaciones.

JSTL permite realizar tareas como iteraciones, estructuras condicionales, tags demanipulación de documentos XML, tags SQL, etc. También introduce un lenguaje deexpresiones que simplifica el desarrollo de las páginas, y proporciona un API parasimplificar la configuración de los tags JSTL y el desarrollo de tags personalizados quesean conformes a las convenciones de JSTL.

Se puede emplear JSTL a partir de la versión 2.3 de servlets, y 1.2 de JSP. Podéisencontrar más información sobre JSTL en:

http://java.sun.com/products/jsp/jstl

17.1. Uso de JSTL

JSTL contiene una gran variedad de tags que permiten hacer distintos tipos de tareas,subdivididas en áreas. Así, JSTL proporciona varios ficheros TLD, para describir cadauna de las áreas que abarca, y dar así a cada área su propio espacio de nombres.

En la siguientes tablas se muestran las áreas cubiertas por JSTL (cada una con unalibrería):

Librería EL:

AREA URI PREFIJO

Core http://java.sun.com/jsp/jstl/core

c

XML http://java.sun.com/jsp/jstl/xml

x

Internacionalización (I18N) http://java.sun.com/jsp/jstl/fmt

fmt

SQL http://java.sun.com/jsp/jstl/sql

sql

Librería RT:

AREA URI PREFIJO

Servlets y JSP

109Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 110: Servlets y JSP - Experto Java

Core http://java.sun.com/jsp/jstl/core_rt

c_rt

XML http://java.sun.com/jsp/jstl/xml_rt

x_rt

Internacionalización (I18N) http://java.sun.com/jsp/jstl/fmt_rt

fmt_rt

SQL http://java.sun.com/jsp/jstl/sql_rt

sql_rt

Se tienen dos versiones de JSTL, aunque la utilidad de las librerías es la misma para lasdos:

• Core se utiliza para funciones de propósito general (manejo de expresiones,sentencias de control de flujo, etc).

• XML se emplea para procesamiento de ficheros XML.• La librería de internationalización se usa para dar soporte a páginas multilenguaje, y

a multiformatos de números, monedas, etc, en función de la región en que se tenga laaplicación.

• SQL sirve para acceder y manipular bases de datos relacionales.

El motivo de esta duplicación de librerías es que las librerías EL son compatibles con ellenguaje de expresiones de JSP (incluído desde JSTL 1.0 en JSTL, y desde JSP 2.0 entodas las páginas JSP), y las librerías RT son compatibles con los clásicos scriptlets<%=...%>. Esto quiere decir que las librerías EL admitirán lenguaje de expresiones en susatributos, y las RT admitirán scriptlets. Se mantiene este segundo grupo de librerías porcompatibilidad con versiones antiguas.

Las URIs y prefijos que se indican en la tabla pueden emplearse (aunque no esobligatorio) para utilizar las librerías en nuestras aplicaciones.

EJEMPLO

Para utilizar, por ejemplo, los tags del área core en una página JSP, seguimos pasossimilares a los realizados para utilizar las librerías de tags vistas anteriormente:

• Colocar al principio de cada página JSP donde vayamos a utilizar la librería core lalínea:

<%@ taglib uri="/jstl-core" prefix="c" %>

donde la uri y el prefix tendrán los valores que queramos darles, si bien la URI serecomienda que sea la indicada en las tablas superiores, para no tener que utilizarfichero TLD en nuestra aplicación

• Las librerías JSTL vienen en dos versiones: los ficheros TLD para la librería JSTL-ELvienen nombrados como prefix.tld (siendo prefix el prefijo para la librería), y losde la librería JSTL-RT vienen nombrados como prefix-rt.tld. Así, por ejemplo,para indicar en el descriptor de despliegue (web.xml) que vamos a utilizar la librería

Servlets y JSP

110Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 111: Servlets y JSP - Experto Java

de core, pondríamos algo como:

<taglib><taglib-uri>/jstl-c</taglib-uri><taglib-location>/WEB-INF/c.tld</taglib-location>

</taglib>

Si utilizamos las uris absolutas que se han indicado anteriormente, no tenemos queañadir este elemento <taglib>en el descriptor de despliegue. El contenedor JSPlocaliza automáticamente el TLD.

• Finalmente, tenemos que tener accesible una implementación de la librería que vamosa utilizar. Hay que copiar los ficheros JAR correspondientes en el directorioWEB-INF/lib de nuestra aplicación, si el servidor web no las tiene directamentedisponibles

• Podemos utilizar las dos librerías conjuntamente, como en este ejemplo, que utilizalas dos librerías de internacionalización (prefijo fmt):

<fmt:message key="clave"><fmt:param value="${miParametro}"/><fmt_rt:param value="<%= miParametro %>"/>

</fmt:message>

17.2. La librería Core

Los tags core incluyen tags de propósito general. En esta librería se tienen etiquetas para:

• Funciones de propósito general: evaluar expresiones, establecer valores deparámetros, etc.

• Funciones de control de flujo: condiciones para ejecutar unos bloques de código uotro, iteradores, etc.

• Funciones de acceso a URLs: para importar URLS en la página actual, etc.

Los tags de esta librería se presentan con el prefijo "c".

17.2.1. Tags de propósito general

out

El tag out evalúa el resultado de una expresión y lo pone en el objeto JspWriter actual.Es equivalente a la sintaxis <%= ... %> de JSP, y también a poner directamente unaexpresión ${...} en su lugar, aunque admite algunos atributos adicionales.

SINTAXIS:

Dar el valor por defecto mediante un atributo default:

<c:out value="valor"

Servlets y JSP

111Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 112: Servlets y JSP - Experto Java

[escapeXML="true|false"][default="valor"]/>

Dar el valor por defecto mediante el cuerpo del tag:

<c:out value="valor"[escapeXML="true|false"]>

Valor por defecto</c:out>

ATRIBUTOS:

• value: expresión que se tiene que evaluar.• escapeXML: a true (valor por defecto) indica que los caracteres <, >, &, ', " que

haya en la cadena resultado se deben convertir a sus códigos correspondientes (&lt;,&gt;, &amp;, &#039;, &#034;, respectivamente).

• default: valor por defecto si el resultado es null. Se puede indicar por el atributo opor el cuerpo del tag.

EJEMPLO:

<c:out value="${datos.ciudad}"default="desconocida"/>

Sacaría el valor del campo ciudad del objeto datos, o mostraría "desconocida" si dichovalor es nulo.

set

El tag set establece el valor de un atributo en cualquier campo JSP (page, request,

session, application). Si el atributo no existe, se crea.

SINTAXIS:

Dar valor a una variable utilizando el atributo value:

<c:set value="valor" var="variable"[scope="page|request|session|application"]/>

Dar valor a una variable utilizando el cuerpo del tag:

<c:set var="variable"[scope="page|request|session|application"]>

Valor</c:set>

Dar valor a una propiedad de un objeto utilizando el atributo value:

<c:set value="valor" target="objeto"property="propiedad"/>

Dar valor a una propiedad de un objeto utilizando el cuerpo del tag:

<c:set target="objeto" property="propiedad">Valor

Servlets y JSP

112Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 113: Servlets y JSP - Experto Java

</c:set>

ATRIBUTOS:

• value: valor que se asigna. Podemos dar el valor con este atributo o con el cuerpo deltag.

• var: variable a la que se asigna el valor.• scope: ámbito de la variable a la que se asigna el valor.• target: objeto al que se le modifica una propiedad. Debe ser un objeto JavaBeans con

una propiedad propiedad que pueda establecerse, o un objeto java.util.Map.• property: propiedad a la que se le asigna valor en el objeto target.

EJEMPLO:

<c:set var="foo" value="2"/>...<c:out value="${foo}"/>

Asignaría a la variable foo el valor "2", y luego mostraría el valor por pantalla.

Otras Etiquetas

Existen otras etiquetas, como remove o catch, que no se comentan aquí.

17.2.2. Tags de control de flujo

if

El tag if permite ejecutar su código si se cumple la condición que contiene su atributotest.

SINTAXIS:

Sin cuerpo:

<c:if test="condicion" var="variable"[scope="page|request|session|application"]/>

Con cuerpo:

<c:if test="condicion" [var="variable"][scope="page|request|session|application"]>

Cuerpo</c:if>

ATRIBUTOS:

• test: condicion que debe cumplirse para ejecutar el if.• var: variable donde se guarda el resultado de evaluar la expresión. El tipo de esta

variable debe ser Boolean.• scope: ámbito de la variable a la que se asigna el valor de la condición.

Servlets y JSP

113Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 114: Servlets y JSP - Experto Java

EJEMPLO:

<c:if test="${visitas > 1000}"><h1>¡Mas de 1000 visitas!</h1></c:if>

Sacaría el mensaje "¡Mas de 1000 visitas!" si el contador visitas fuese mayor que1000.

choose

El tag choose permite definir varios bloques de código y ejecutar uno de ellos en funciónde una condición. Dentro del choose puede haber espacios en blanco, una o variasetiquetas when y cero o una etiquetas otherwise.

El funcionamiento es el siguiente: se ejecutará el código de la primera etiqueta when quecumpla la condición de su atributo test. Si ninguna etiqueta when cumple su condición, seejecutará el código de la etiqueta otherwise (esta etiqueta, si aparece, debe ser la últimahija de choose).

SINTAXIS:

<c:choose><c:when test="condicion1">

codigo1</c:when><c:when test="condicion2">

codigo2</c:when>...<c:when test="condicionN">

codigoN</c:when><c:otherwise>

codigo</c:otherwhise>

</c:choose>

EJEMPLO:

<c:choose><c:when test="${a < 0}"><h1>a menor que 0</h1></c:when><c:when test="${a > 10}"><h1>a mayor que 10</h1></c:when><c:otherwise><h1>a entre 1 y 10</h1></c:otherwhise>

</c:choose>

Sacaría el mensaje "a es menor que 0" si la variable a es menor que 0, el mensaje "aes mayor que 10" si es mayor que 10, y el mensaje "a esta entre 1 y 10" si no secumple ninguna de las dos anteriores.

Servlets y JSP

114Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 115: Servlets y JSP - Experto Java

forEach

El tag forEach permite repetir su código recorriendo un conjunto de objetos, o durante unnúmero determinado de iteraciones.

SINTAXIS:

Para iterar sobre un conjunto de objetos:

<c:forEach [var="variable"] items="conjunto"[varStatus="variableEstado"] [begin="comienzo"][end="final"] [step="incremento"]>

codigo</c:forEach>

Para iterar un determinado número de veces:

<c:forEach [var="variable"][varStatus="variableEstado"] begin="comienzo"end="final" [step="incremento"]>

codigo</c:forEach>

ATRIBUTOS:

• var: variable donde guardar el elemento actual que se está explorando en la iteración.El tipo de este objeto depende del tipo de conjunto que se esté recorriendo.

• items: conjunto de elementos que recorre la iteración. Pueden recorrerse varios tipos:

• Array: tanto de tipos primitivos como de tipos complejos. Para los tiposprimitivos, cada dato se convierte en su correspondiente wrapper (Integer paraint, Float para float, etc)

• java.util.Collection: mediante el método iterator() se obtiene el conjunto, quese procesa en el orden que devuelve dicho método.

• java.util.Iterator• java.util.Enumeration• java.util.Map:el objeto del atributo var es entonces de tipo Map.Entry, y se

obtiene un Set con los mapeos. Llamando al método iterator() del mismo seobtiene el conjunto a recorrer.

• String: la cadena representa un conjunto de valores separados por comas, que sevan recorriendo en el orden en que están.

• varStatus: variable donde guardar el estado actual de la iteración. Es del tipojavax.servlet.jsp.jstl.core.LoopTagStatus.

• begin: indica el valor a partir del cual comenzar la iteración. Si se está recorriendo unconjunto de objetos, indica el índice del primer objeto a explorar (el primero es el 0),y si no, indica el valor inicial del contador. Si se indica este atributo, debe ser mayor oigual que 0.

• end: indica el valor donde terminar la iteración. Si se está recorriendo un conjunto deobjetos, indica el índice del último objeto a explorar (inclusive), y si no, indica elvalor final del contador. Si se indica este atributo, debe ser mayor o igual que begin.

Servlets y JSP

115Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 116: Servlets y JSP - Experto Java

• step: indica cuántas unidades incrementar el contador cada iteración, para ir de begin

a end. Por defecto es 1 unidad. Si se indica este atributo, debe ser mayor o igual que1.

EJEMPLO:

<c:forEach var="item"items="${cart.items}">

<tr><td><c:out value="${item.valor}"/></td>

</tr></c:forEach>

Muestra el valor de todos los items.

forTokens

El tag forTokens es similar al tag foreach, pero permite recorrer una serie de tokens

(cadenas de caracteres), separadas por el/los delimitador(es) que se indique(n).

SINTAXIS

La sintaxis es la misma que foreach, salvo que se tiene un atributo delims, obligatorio.

ATRIBUTOS

• var: igual que para foreach

• items: cadena que contiene los tokens a recorrer• delims:conjunto de delimitadores que se utilizan para separar los tokens de la cadena

de entrada (colocados igual que los utiliza un StringTokenizer).• varStatus: igual que para foreach

• begin: indica el índice del token a partir del cual comenzar la iteración.• end: indica el índice del token donde terminar la iteración.• step: igual que para foreach.

EJEMPLO:

<c:forTokens var="item"items="un#token otro#otromas" delims="# ">

<tr><td><c:out value="${item}"/></td>

</tr></c:forEach>

Definimos dos separadores: el '#' y el espacio ' '. Así habrá 4 iteraciones, recorriendo lostokens "un", "token", "otro" y "otromas".

17.2.3. Tags de manejo de URLs

Servlets y JSP

116Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 117: Servlets y JSP - Experto Java

import

El tag import permite importar el contenido de una URL.

SINTAXIS:

Para copiar el contenido de la URL en una cadena:

<c:import url="url" [context="contexto"][var="variable"][scope="page|request|session|application"][charEncoding="codificacion"]>

cuerpo para tags "param" opcionales</c:import>

Para copiar el contenido de la URL en un Reader:

<c:import url="url" [context="contexto"]varReader="variableReader"[charEncoding="codificacion"]>

codigo para leer del Reader</c:import>

ATRIBUTOS:

• url: URL de la que importar datos• context: contexto para URLs que pertenecen a contextos distintos al actual.• var: variable (String) donde guardar el contenido de la URL• varReader: variable (Reader) donde guardar el contenido de la URL• scope: ámbito para la variable var

• charEncoding: codificación de caracteres de la URL

EJEMPLO:

<c:import url="http://www.ua.es"var="universidad">

<c:out value="${universidad}"/></c:import>

Obtiene y muestra el contenido de la URL indicada.

param

El tag param se utiliza dentro del tag import y de otros tags (redirect, url) paraindicar parámetros de la URL solicitada. Dentro del tag import sólo se utiliza si la URLse guarda en una cadena. Para los Readers no se emplean parámetros.

SINTAXIS:

Sin cuerpo:

<c:param name="nombre" value="valor"/>

Con cuerpo:

Servlets y JSP

117Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 118: Servlets y JSP - Experto Java

<c:param name="nombre">Valor

</c:param>

ATRIBUTOS:

• name: nombre del parámetro• value: valor del parámetro. Puede indicarse bien mediante este atributo, bien en el

cuerpo del tag.

EJEMPLO:

<c:import url="http://localhost/mipagina.jsp"var="universidad">

<c:param name="id" value="12"/></c:import>

Obtiene la página mipagina.jsp?id=12 (le pasa como parámetro id el valor 12).

Otras Etiquetas

Existen otras etiquetas, como url o redirect, que no se comentan aquí.

17.2.4. Ejemplo

Vemos cómo quedaría el ejemplo visto en la sesión anterior para la librería request

adaptado a la librería core. Partiendo del mismo formulario inicial:

<html><body>

<form action="request.jsp">Nombre:<input type="text" name="nombre"><br>Descripcion:<input type="text" name="descripcion"><br><input type="submit" value="Enviar">

</form></body></html>

Para obtener los parámetros podríamos tener una página como esta:

<%@ taglib uri="core" prefix="c" %>

<html><body>

Nombre: <c:out value="${param.nombre}"/><br><c:if test="${not empty param.descripcion}">

Descripcion: <c:out value="${param.descripcion}"/></c:if>

</body></html>

Servlets y JSP

118Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 119: Servlets y JSP - Experto Java

Hemos utilizado en este caso, como ejemplo, los tags out e if (para comprobar si hayparámetro descripcion). En este último caso, utilizamos el operador empty en ellenguaje de expresiones, para ver si hay o no valor.

17.3. La librería SQL

Los tags de la librería SQL permiten acceder y manipular información de bases de datosrelacionales. Vienen definidos con el prefijo "sql".

Con esta librería podremos:

• Establecer la base de datos a la que acceder• Realizar consultas a bases de datos (select)• Acceder a los resultados de las consultas realizadas• Realizar actualizaciones sobre la base de datos (insert, update, delete)• Agrupar operaciones en una sola transacción

Estas acciones se realizan sobre objetos de tipo javax.sql.DataSource, queproporciona conexiones a la fuente de datos que representa. Así, se obtiene un objetoConnection de dicho DataSource, y con él podremos ejecutar sentencias y obtenerresultados. Podemos definir el DataSource mediante la etiqueta setDataSource y luegoacceder a ese DataSource con los atributos dataSource de las etiquetas de la librería.

17.3.1. Etiquetas de la librería

setDataSource

El tag setDataSource permite definir el objeto DataSource con el que trabajar, y dejarloasignado en una variable.

SINTAXIS:

<sql:setDataSource {dataSource="DataSource" |url="url" [driver="driver"] [user="usuario"][password="password"]} [var="variable"][scope="page|request|session|application"]/>

ATRIBUTOS:

• dataSource: objeto DataSource al que queremos enlazar (en caso de que esté creadode antemano).

• url: URL de la base de datos a acceder• driver: driver con que conectar con la base de datos• user: nombre de usuario con que conectar a la base de datos• password: password con que conectar a la base de datos• var: variable donde guardar el DataSource que se obtenga• scope: ámbito de la variable var

Servlets y JSP

119Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 120: Servlets y JSP - Experto Java

Notar que se puede obtener el DataSource tanto indicándolo directamente en el atributodataSource como indicando url, driver, user y password (los tres últimosopcionales).

query

El tag query permite definir una consulta (select) en una base de datos.

SINTAXIS:

Sin cuerpo:

<sql:query sql="consulta" var="variable"[scope="page|request|session|application"][dataSource="DataSource"] [maxRows="max"][startRow="inicio"]/>

Con cuerpo donde indicar parámetros de la consulta:

<sql:query sql="consulta" var="variable"[scope="page|request|session|application"][dataSource="DataSource"] [maxRows="max"][startRow="inicio"]>

Campos <sql:param></sql:query>

Con cuerpo donde indicar la propia consulta y los parámetros de la consulta:

<sql:query var="variable"[scope="page|request|session|application"][dataSource="DataSource"] [maxRows="max"][startRow="inicio"]>

ConsultaCampos <sql:param>

</sql:query>

ATRIBUTOS:

• sql: consulta a realizar (en formato SQL). Puede indicarse la consulta tanto en esteatributo como en el cuerpo de la etiqueta.

• dataSource: objeto DataSource asociado a la base de datos a la que se accede. Siespecificamos este campo, no podemos incluir esta etiqueta dentro de una transacción(etiqueta transaction).

• maxRows: máximo número de filas que se devuelven como resultado• startRow: fila a partir de la cual devolver resultados. Por defecto es la 0.• var: variable donde guardar el resultado. Es de tipo

javax.servlet.jsp.jstl.sql.Result.• scope: ámbito de la variable var.

update

El tag update permite definir una actualización (insert, update, delete) en una basede datos.

Servlets y JSP

120Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 121: Servlets y JSP - Experto Java

SINTAXIS:

Sin cuerpo:

<sql:update sql="actualizacion"[dataSource="DataSource"] [var="variable"][scope="page|request|session|application"]/>

Con cuerpo donde indicar parámetros de la actualización:

<sql:update sql="actualizacion"[dataSource="DataSource"] [var="variable"][scope="page|request|session|application"]>

Campos <sql:param></sql:update>

Con cuerpo donde indicar la propia actualización y los parámetros de la misma:

<sql:update [dataSource="DataSource"] [var="variable"][scope="page|request|session|application"]>

ActualizaciónCampos <sql:param>

</sql:update>

ATRIBUTOS:

• sql: actualización a realizar (en formato SQL). Puede indicarse tanto en este atributocomo en el cuerpo de la etiqueta.

• dataSource: objeto DataSource asociado a la base de datos a la que se accede. Siespecificamos este campo, no podemos incluir esta etiqueta dentro de una transacción(etiqueta transaction).

• var: variable donde guardar el resultado. Es de tipo Integer (se devuelve el númerode filas afectadas por la actualización).

• scope: ámbito de la variable var.

transaction

El tag transaction permite agrupar dentro de él varios tags query y/o update, de formaque se define una transacción con ellos.

SINTAXIS:

<sql:transaction [dataSource="DataSource"][isolation="nivel"]>

Conjunto de etiquetas query y/o update</sql:transaction>

ATRIBUTOS:

• dataSource: objeto DataSource asociado a la base de datos a la que se accede. Seutiliza este DataSource por todas las operaciones query y update que se definandentro.

• isolation: nivel de aislamiento de la transacción, que puede ser "read_committed",

Servlets y JSP

121Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 122: Servlets y JSP - Experto Java

"read_uncommitted", "repeatable_read" o "serializable".

param

El tag param permite definir parámetros a la hora de ejecutar consultas (query) oactualizaciones (update). Así, se sustituyen las marcas "?" que pueda haber en consultaso actualizaciones, por los valores de los parámetros que se indiquen.

SINTAXIS:

Sin cuerpo:

<sql:param value="valor"/>

Con cuerpo:

<sql:param>Valor

</sql:param>

ATRIBUTOS:

• value: valor del parámetro. Puede indicarse mediante este atributo o como cuerpo deltag.

Los valores de los parámetros se sustituyen en las etiquetas en el orden en que se vandefiniendo. Veremos un ejemplo más adelante.

Otras Etiquetas

Se tienen otras etiquetas, como dateParam, que es igual que param pero para parámetrosde tipo Date (fechas). No la veremos con más detalle aquí.

EJEMPLO

Vemos un ejemplo de uso de las etiquetas explicadas.

• Creamos un DataSource mediante una etiqueta setDataSource, que se conecta a labase de datos miBD, de MySQL. Guardamos el DataSource en la variablemiDataSource:

<sql:setDataSourceurl="jdbc:mysql//localhost/miBD"driver="org.gjt.mm.mysql.Driver"user="root" password="mysql"var="miDataSource"

/>

• Ejecutamos una consulta (query) que muestra todos los nombres de la tablanombres. Guardamos el resultado en la variable miConsulta:

<sql:query var="miConsulta"dataSource="${miDataSource}">

SELECT nombre FROM nombres</sql:query>

Servlets y JSP

122Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 123: Servlets y JSP - Experto Java

<c:foreach var="fila" items="${miConsulta.rows}"><c:out value="${fila.nombre}"/><br>

</c:foreach>

• Ejecutamos una actualización que actualice el nombre que tenga id = 1 o id = 2:

<sql:update dataSource="${miDataSource}">UPDATE nombres SET nombre='pepe'WHERE id=1 OR id=2

</sql:update>

• Utilizamos dos etiquetas param para pasar como parámetros los id de los nombresque se tienen que actualizar:

<sql:update dataSource="${miDataSource}">UPDATE nombres SET nombre='pepe'WHERE id=? OR id=?<sql:param value="${param.id1}"/><sql:param value="${param.id2}"/>

</sql:update>

Se sustituiría la primera ? por el primer param y la segunda ? por el segundo param.Los dos parámetros se toman en este ejemplo de la petición request. Pueden tomarsede cualquier otro sitio (constantes, variables, etc).

• Vemos cómo quedarían las dos operaciones anteriores en una transacción(transaction):

<sql:transaction dataSource="${miDataSource}">

<sql:query var="miConsulta">SELECT nombre FROM nombres

</sql:query>

<c:foreach var="fila"items="${miConsulta.rows}">

<c:out value="${fila.nombre}"/><br></c:foreach>

<sql:update>UPDATE nombres SET nombre='pepe'WHERE id=? OR id=?<sql:param value="${param.id1}"/><sql:param value="${param.id2}"/>

</sql:update>

</sql:transaction>

17.3.2. Ejemplo

Vemos cómo quedaría el ejemplo visto en la sesión anterior para la librería dbtags

adaptado a la librería sql.

<%@ taglib uri="sql" prefix="sql" %>

Servlets y JSP

123Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 124: Servlets y JSP - Experto Java

<%@ taglib uri="core" prefix="c" %>

<html><body>

<sql:setDataSource url="jdbc:mysql://localhost/prueba"driver="org.gjt.mm.mysql.Driver"user="root" password="mysql" var="miDataSource"/>

<sql:query var="miConsulta" dataSource="${miDataSource}">SELECT * FROM datos

</sql:query>

<c:forEach var="fila" items="${miConsulta.rows}">Nombre: <c:out value="${fila.nombre}"/><br>Descripcion: <c:out value="${fila.descripcion}"/><br></c:forEach>

</body></html>

Utilizamos la librería sql y la core para recorrer todos los registros encontrados.

17.4. La librería de internacionalización

Los tags de la librería de internacionalización (o I18n) permiten adaptar aplicacionesWeb a las convenciones de idioma y formato de los clientes para un determinado origen(locale). Los tags de esta librería se presentan con el prefijo "fmt".

En la librería tenemos tags para la internacionalización propiamente dicha, y para elformato de determinados elementos según la región (podremos formatear números,fechas, monedas, etc, dependiendo del idioma o región que se trate).

17.4.1. Etiquetas de la librería

Algunas etiquetas interesantes de esta librería son:

formatNumber

El tag formatNumber permite dar formato a un número, e indicar, por ejemplo, concuántos decimales queremos que se muestre.

SINTAXIS:

<fmt:formatNumber [value="numero"][type="number|currency|percentage"][pattern="patron"] [groupingUsed="true|false"][maxIntegerDigits="cantidad"] [minIntegerDigits="cantidad"][maxFractionDigits="cantidad"] [minFracionDigits="cantidad"][var="nombreVariable"] [scope="ambito"]... />

ATRIBUTOS:

• value: el valor del número que queremos formatear. Podrá ser un valor constante("2.34"), o uno encapsulado en una variable en lenguaje de expresiones

Servlets y JSP

124Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 125: Servlets y JSP - Experto Java

").• type: indica el tipo de número que se quiere formatear: number (número genérico),

currency (moneda) o percentage (para porcentajes).• pattern: indica un patrón propio con el que formatear el número. Un ejemplo de uso

sería "#.###", que dejaría 3 decimales, y al menos 1 entero.• groupingUsed: a true indica que se separen las cifras de mil en mil, con puntos

(2.032.135), y a false indica que no se utilicen los puntos para separar (2032135).• maxIntegerDigits y minIntegerDigits establecen cuántas cifras tendrá como mucho

y como poco (respectivamente) la parte entera.• maxFractionDigits y minFractionDigits establecen el número de cifras como

máximo y como mínimo (respectivamente) de la parte decimal.• var: nombre de la variable donde guardar el número formateado (si se quiere

almacenar temporalmente)• scope: ámbito de la variable (como los campos scope vistos en otras etiquetas).• Además, la etiqueta tiene otros atributos (para indicar monedas y otros elementos),

que no se comentan aquí.

formatDate

El tag formatDate permite dar formato a una fecha y mostrar las partes de ella quequeramos, y en el orden que queramos.

SINTAXIS:

<fmt:formatDate [value="fecha"] [type="time|date|both"][dateStyle="default|short|medium|long|full"][timeStyle="default|short|medium|long|full"][pattern="patron"] [timeZone="zona"][var="nombreVariable"] [scope="ambito"]... />

ATRIBUTOS:

• value: el valor de la fecha. Normalmente vendrá en una variable ("${fecha}").• type: indica el tipo de fecha que se quiere formatear: fecha, hora o ambos.• dateStyle: formatea la fecha con uno de los formatos predeterminados que tiene• timeStyle: formatea la hora con uno de los formatos predeterminados que tiene• pattern: indica un patrón propio con el que formatear la fecha.• timeZone: cadena de texto descriptiva de la zona horaria para la que queremos

formatear la fecha.• var: nombre de la variable donde guardar el número formateado (si se quiere

almacenar temporalmente)• scope: ámbito de la variable (como los campos scope vistos en otras etiquetas).

17.4.2. Ejemplo

Vemos cómo formatear un número almacenado en la variable num, para que se muestrecon 3 decimales siempre:

Servlets y JSP

125Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 126: Servlets y JSP - Experto Java

<fmt:formatNumber value="${num}" maxFractionDigits="3"minFractionDigits="3"/>

Formateamos ahora una fecha guardada en la variable miFecha, para mostrarla con:

día/mes/año - horas:minutos:segundos

<fmt:formatDate value="${miFecha}" pattern="dd/MM/yyyy-hh:mm:ss"/>

17.5. La librería XML y la librería de funciones

Los tags de la librería de XML permiten tener acceso y procesar el contenido dedocumentos XML, utilizando la recomendación XPath del W3C como un lenguaje deexpresiones local. Esta librería se utiliza con el prefijo "x".

Dentro de la librería, distinguimos entre los tags principales (que nos permiten explorarel contenido de un fichero XML), tags de control de flujo (para realizar código enfunción de dicho contenido), y tags de transformación (que permite transformar ficherosXML aplicando hojas de estilo XSLT).

Por otro lado, JSTL dispone también de un conjunto de funciones que pueden emplearsedesde dentro del lenguaje de expresiones, y permiten sobre todo manipular cadenas, parasustituir caracteres, concatenar, etc.

Para utilizar estas funciones, cargaríamos la directiva taglib correspondiente:

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

Y luego utilizaríamos las funciones que haya disponibles, dentro de una expresión dellenguaje:

La cadena tiene <c:out value="${fn:length(miCadena)}"/> caracteres

Servlets y JSP

126Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 127: Servlets y JSP - Experto Java

18. Ejercicios de JSTL

Como ejercicios de esta sesión, repetiremos los pasos seguidos en la sesión anterior conlas librerías request y dbtags, pero empleando las librerías de JSTL (la librería core y lasql, respectivamente, además de probar la librería fmt). Para ello se os proponen aquí lospasos equivalentes a aquellos.

18.1. Configurar aplicación web con JSTL

Como primer ejercicio, vamos a configurar la aplicación jsp-sesion09 para podertrabajar con las librerías:

• Tenemos los ficheros TLD de las librerías (c.tld, sql.tld y fmt.tld) en eldirectorio WEB-INF de la aplicación

• Tenemos los ficheros JAR de las librerías en el directorio WEB-INF/lib de laaplicación.

• Modificamos el fichero descriptor de la aplicación, añadiéndole las etiquetas para queacepte las librerías (este paso no es necesario en las últimas versiones):

<taglib><taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri><taglib-location>/WEB-INF/c.tld</taglib-location>

</taglib>

<taglib><taglib-uri>http://java.sun.com/jsp/jstl/sql</taglib-uri><taglib-location>/WEB-INF/sql.tld</taglib-location>

</taglib>

<taglib><taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri><taglib-location>/WEB-INF/fmt.tld</taglib-location>

</taglib>

18.2. Registro de usuarios con JSTL

Una vez tengamos la aplicación configurada, construiremos dos páginas:

• Una página form_registro.jsp que contendrá un formulario con los siguientescampos de texto:• nombre: con el nombre del usuario• mail: con su correo electrónico• login: nick que utilizará para entrar a la aplicación• password: con la contraseña para validarlo• telefono: con el número de teléfono• Además, la página mostrará la fecha actual (sólo en el momento de cargar la

página), utilizando la librería de internacionalización de JSTL (fmt). Para ello,

Servlets y JSP

127Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 128: Servlets y JSP - Experto Java

primero creamos un bean de tipo java.util.Date, que tomará la fecha actual:

<jsp:useBean id="fechaActual" class="java.util.Date"/>

Después, damos formato a dicha fecha con la etiqueta formatDate de la libreríafmt, pasándole como variable el bean anterior, y poniendo en pattern la cadenanecesaria para mostrar día/mes/año hora:minuto:segundo. Deberemos incluir ladirectiva taglib al principio de esta página, para poder usar la librería fmt:

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>...<fmt:formatDate var="fechaFormat" value="${fechaActual}"pattern="..."/>...${fechaFormat}

• El formulario anterior tendrá un botón de submit que nos enviará a una páginaregistro.jsp, que se encargará de introducir los datos del usuario en la base de datos,tomándolos de los parámetros de la petición (podemos utilizar para ello el lenguaje deexpresiones de JSTL), e introduciéndolos en la base de datos (utilizando sql)

La aplicación mostrará un mensaje indicando si los datos se han introducidocorrectamente, o ha habido algún error. Podemos utilizar el tag if o choose de la libreríacore para comprobar si lo que devuelve la inserción (que podemos guardarlo en unavariable desde el tag update) es lo correcto o no.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>

...

<sql:setDataSource url="..." driver="..." .../>

<sql:update var="upd1" dataSource="${miDataSource}">INSERT INTO usuarios(nombre, email...) VALUES (?,? ...)<sql:param value="${param.nombre}"/><sql:param value="${param.email}"/>...

</sql:update>

Para comprobar si la inserción es correcta o no, podéis ver si la variable upd1 donde seguarda la inserción es mayor que 0 (lo que indicaría que hay filas afectadas) o es 0 (queindicaría que no se ha insertado nada). Se deja como optativo el comprobar antes deinsertar si existe el nombre del usuario en la tabla.

18.3. Listado de usuarios y otras mejoras con JSTL

Sobre lo anterior, realizar una página listado.jsp que muestre un listado con los usuariosactualmente registrados.

(*) Para cada usuario, hacer que permita eliminarlo de la lista (se borrarían sus datos de la

Servlets y JSP

128Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 129: Servlets y JSP - Experto Java

base de datos), o modificar sus datos (mostrando en otra página un formulario con susdatos para editarlos).

Servlets y JSP

129Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 130: Servlets y JSP - Experto Java

19. Creación de librerías de tags

Como hemos visto en JSTL, las librerías de tags encapsulan funcionalidad Java en losJSP sin necesidad de insertar código. Podría ser útil por tanto desarrollar nuestras propiastags para el uso en nuestras aplicaciones. JSP nos ofrece esta posibilidad desde lasprimeras versiones del API.

Veremos en esta sesión cómo podemos definir nuestros propios tags y formar con ellosuna librería, tratando distintos tipos de tags (aunque no todos) los que se pueden hacer.

19.1. Consideraciones previas

Para ello iremos incorporando tags a una librería nueva, que llamaremos pruebatags.Antes de comenzar a ver cómo crear tags, tendremos en cuenta las siguientesconsideraciones:

• Para definir los tags haremos clases Java, que contendrán el código de cada tag.Luego desde las páginas JSP llamaremos a los tags (con lo que se ejecutará el códigode las clases Java que los implementan). Colocaremos todas las clases de nuestralibrería de tags en el paquete pruebatags.

• Utilizaremos los paquetes javax.servlet.jsp y javax.servlet.jsp.tagext principalmentepara definir las librerías de tags. Para poder acceder a ellos deberemos tener en elclasspath el fichero JAR correspondiente (el fichero j2ee.jar que viene con J2EE, oalgún fichero específico del servidor que incorpore estas librerías, como por ejemploservlet.jar en Tomcat 4, o jsp-api.jar en Tomcat 5).

• Emplearemos el servidor Apache Tomcat para probar los tags. Crearemos undirectorio tags a partir del raíz webapps, y en él definiremos el directorio WEB-INF,con el fichero web.xml:

<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN""http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app><display-name>Pruebas de Tags</display-name><description>

Ejemplos de Creacion de Tags</description>

<taglib><taglib-uri>pruebatags</taglib-uri><taglib-location>/WEB-INF/pruebatags.tld</taglib-location>

</taglib></web-app>

donde indicamos que se va a utilizar la librería pruebatags, cuyo fichero descriptor

Servlets y JSP

130Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 131: Servlets y JSP - Experto Java

pruebatags.tld) está en WEB-INF (lo añadiremos más adelante).

19.2. Tags simples

Como ejemplo de tag simple haremos un tag que muestre la fecha actual. Veremos lospasos que se siguen:

1. Creación de la clase que implementa el tag

Llamaremos FechaActual a la clase que implementa al tag.

package pruebatags;

import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;

import java.util.Calendar;

public class FechaActual implements Tag{

private PageContext contexto; // Contexto del tagprivate Tag padre; // Tag padre del actual

// Metodo llamado cuando se comienza el tagpublic int doStartTag() throws JspException{

return SKIP_BODY;}

// Metodo llamado cuando se termina el tagpublic int doEndTag() throws JspException{

try{

// Mostramos la fecha y hora actualesCalendar c=Calendar.getInstance();contexto.getOut().write(

c.get(Calendar.DAY_OF_MONTH) +"/" +(c.get(Calendar.MONTH)+1) +"/" +c.get(Calendar.YEAR) +" - " +c.get(Calendar.HOUR_OF_DAY) +":" +c.get(Calendar.MINUTE) +":" +c.get(Calendar.SECOND));

} catch(java.io.IOException e) {throw new JspException("Error");

}return EVAL_PAGE;

}

// Metodo de limpiezapublic void release() {}

Servlets y JSP

131Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 132: Servlets y JSP - Experto Java

// Metodo para asignar el contextopublic void setPageContext(final PageContext contexto){

this.contexto = contexto;}

// Metodo para asignar el tag padrepublic void setParent(final Tag padre){

this.padre = padre;}

// Metodo para obtener el padrepublic Tag getParent(){

return padre;}

}

• Primero colocamos el nombre del paquete, los paquetes que necesitamos y definimosla clase. El paquete java.util.Calendar lo utilizamos para obtener la fecha y horaactuales. Los otros dos paquetes son los que se han dicho que se emplean para crearlibrerías de tags. La clase implementa la interfaz javax.servlet.jsp.tagext.Tag, con loque hay que definir todos sus métodos.

• Después creamos dos campos: uno para guardar el contexto del tag (campocontexto), y otro para guardar el tag padre del actual (campo padre).

• El método doStartTag() se llama cuando se inicia el tag. En este caso se devuelveSKIP_BODY para que no se evalúe el cuerpo del tag. En caso de que queramosevaluarlo, se debe devolver EVAL_BODY_INCLUDE.

• El método doEndTag() se llama cuando se termina el tag. Aquí se muestra por lasalida del contexto la fecha y hora actuales (usando un objeto java.util.Calendar),y se devuelve EVAL_PAGE para que se siga evaluando el resto de la página. Si noqueremos que se siga evaluando, se devuelve SKIP_PAGE.

• El resto de métodos es necesario ponerlos, al formar parte de la interfaz Tag. Conrelease() se pueden liberar recursos asociados al tag. Con setPageContext() seestablece el contexto para el tag, y con setParent() y getParent() se establece yobtiene el tag padre del actual. Estos métodos se llaman cuando se utiliza el tag. Notenemos que preocuparnos de llamarlos nosotros, sólo dejarlos definidos para quehagan lo correcto (establezcan el contexto y el tag padre).

Una vez que tengamos la clase definida, la compilamos.

2. Crear el fichero TLD

Creamos un fichero de texto con extensión .tld, que llamaremos por ejemplopruebatags.tld, y que contendrá la descripción de la librería de tags. Su contenido es:

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN""http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

Servlets y JSP

132Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 133: Servlets y JSP - Experto Java

<taglib>

<tlibversion>1.0</tlibversion><jspversion>1.1</jspversion><shortname>pt</shortname><uri>pruebatags</uri><info>Librería de prueba</info>

<tag><name>fechaactual</name><tagclass>pruebatags.FechaActual</tagclass><bodycontent>empty</bodycontent><info>Muestra la fecha y hora actual</info>

</tag>

</taglib>

La sintaxis del documento TLD se explicó anteriormente, viendo otras librerías de tags.Hemos creado una librería llamada pruebatags, donde tenemos un tag, llamadofechaactual, implementado por la clase pruebatags.FechaActual.

La estructura de tag la iremos repitiendo luego para cada tag de la librería que vayamoscreando. Nos queda llevar este fichero TLD al directorio WEB-INF del directorio tags

donde estamos creando la librería.

3. Crear un JAR con la librería

Podemos crear un fichero JAR (pruebatags.jar por ejemplo), que contenga los ficheros.class con las clases que implementen los tags (en este caso sólo está la claseFechaActual). Luego copiamos dicho fichero JAR en el directorio WEB-INF/lib denuestro directorio tags.

También podemos no crear el JAR, y colocar los ficheros .class en el directorioWEB-INF/classes (quedando así en la carpeta WEB-INF/classes/pruebatags). Laprimera opción es más recomendable si queremos llevar la librería a otras máquinas.

4. Probar el tag

Finalmente, probamos el funcionamiento del tag.

<%@ taglib uri="pruebatags" prefix="pt"%>

<HTML><BODY >

La fecha actual es:<pt:fechaactual/>

</BODY></HTML>

19.3. Tags con parámetros

Como ejemplo de tag parametrizado vamos a crear un tag que salude al nombre que se le

Servlets y JSP

133Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 134: Servlets y JSP - Experto Java

pase como parámetro:

1. Creación de la clase que implementa el tag

Llamaremos Saludo a la clase que implementa al tag.

package pruebatags;

import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;

public class Saludo implements Tag{

private PageContext contexto; // Contexto del tagprivate Tag padre; // Tag padre del actualString nombre = ""; // Nombre a saludar

// Metodo llamado cuando se comienza el tagpublic int doStartTag() throws JspException{

return SKIP_BODY;}

// Metodo llamado cuando se termina el tagpublic int doEndTag() throws JspException{

try{

// Mostramos el saludocontexto.getOut().write("¡Hola " +

nombre + "!");} catch(java.io.IOException e) {

throw new JspException("Error");}return EVAL_PAGE;

}

// Metodo de limpiezapublic void release() {}

// Metodo para asignar el contextopublic void setPageContext(final PageContext contexto){

this.contexto = contexto;}

// Metodo para asignar el tag padrepublic void setParent(final Tag padre){

this.padre = padre;}

// Metodo para obtener el padrepublic Tag getParent(){

return padre;}

Servlets y JSP

134Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 135: Servlets y JSP - Experto Java

// Establece el nombre al que saludarpublic void setNombre(String nombre){

this.nombre = nombre;}

}

El código es muy similar al visto para FechaActual, con algún cambio: se añade elcampo nombre, que contendrá el nombre al que se saluda. Luego, en doEndTag() semuestra el mensaje de saludo, en lugar de la fecha. Finalmente, se tiene el métodosetNombre() que establece el nombre al que saludar. Esto lo hará automáticamente JSP(de forma similar a los beans), tomando el nombre del parámetro que se le pase al tag.

2. Crear el fichero TLD

En este caso modificamos el fichero TLD anterior, añadiéndole una nueva marca tag conlos datos del nuevo tag:

<tag><name>saludo</name><tagclass>pruebatags.Saludo</tagclass><bodycontent>empty</bodycontent><info>Muestra un saludo</info><attribute>

<name>nombre</name><required>false</required><rtexprvalue>false</rtexprvalue>

</attribute></tag>

Llamamamos al tag saludo (el nombre que usaremos desde JSP). Al igual que el anterior,no tiene cuerpo. Con la etiqueta attribute le indicamos que tiene un atributo nombre,que es el nombre al que saludar.

3. Crear un JAR con la librería

Actualizamos el fichero JAR anterior o el directorio classes añadiendo la nueva clasecreada.

4. Probar el tag

Creamos una página similar a la del tag anterior:

<%@ taglib uri="pruebatags" prefix="pt"%>

<HTML><BODY >

Saludo:<pt:saludo nombre="Pepe"/>

</BODY></HTML>

19.4. BodyTags

Servlets y JSP

135Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 136: Servlets y JSP - Experto Java

Con los BodyTags podemos reevaluar el contenido del cuerpo del tag tantas veces comose quiera. Haremos con ello un iterador, que repetirá un número determinado de veces(pasada como parámetro) el contenido del cuerpo del tag:

1. Creación de la clase que implementa el tag

Llamaremos Iterador a la clase que implementa al tag.

package pruebatags;

import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;

public class Iterador extends BodyTagSupport{

private PageContext contexto; // Contexto del tagprivate Tag padre; // Tag padre del actualint veces = 10; // Num de iteracionesint valorActual = 0; // Valor del contador

// Metodo llamado cuando se comienza el tagpublic int doStartTag() throws JspException{

if (valorActual >= veces)return SKIP_BODY;

else{

valorActual++;return EVAL_BODY_BUFFERED;

}}

// Metodo llamado tras cada evaluacion del tagpublic int doAfterBody() throws JspException{

if (valorActual >= veces)return SKIP_BODY;

else{

valorActual++;return EVAL_BODY_BUFFERED;

}}

// Metodo llamado cuando se termina el tagpublic int doEndTag() throws JspException{

try{

if(bodyContent != null)bodyContent.writeOut(bodyContent.getEnclosingWriter());

} catch(java.io.IOException e) {throw new JspException("IO Error");

}return EVAL_PAGE;

}

Servlets y JSP

136Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 137: Servlets y JSP - Experto Java

// Establece el numero de iteracionespublic void setVeces(int veces){

this.veces = veces;}

}

Se hereda de la clase BodyTagSupport que implementa la interfaz BodyTag, con lo quesólo tendremos que sobreescribir los métodos que necesitemos. En el campo veces

guardamos el número de iteraciones a realizar. Luego con valorActual vamosincrementando el contador hasta llegar a veces. El método doStartTag() se ejecuta alempezar el tag, y luego es el método doAfterBody() quien permite repetir el contenidodel cuerpo mientras se cumpla la condición que se quiera. Al terminar, en doEndTag()imprimimos el resultado de procesar el cuerpo tras el número de iteraciones establecido.Con el método setVeces() asignamos el número de iteraciones (como en el caso anterior,esto lo hará automáticamente JSP tomando el número de iteraciones del parámetro que sele pase al tag).

2. Crear el fichero TLD

Modificamos el fichero TLD anterior, añadiéndole una nueva marca tag con los datos delnuevo tag:

<tag><name>itera</name><tagclass>pruebatags.Iterador</tagclass><bodycontent>JSP</bodycontent><info>Muestra un saludo</info><attribute>

<name>veces</name><required>true</required><rtexprvalue>true</rtexprvalue>

</attribute></tag>

Llamamamos al tag itera (el nombre que usaremos desde JSP). En bodycontent

ponemos JSP para que sea JSP quien se encargue de evaluar el cuerpo del tag. Comoatributo le pasamos el número de iteraciones, con un parámetro llamado veces. Dichoparámetro es requerido, y admite expresiones JSP en su valor.

3. Crear un JAR con la librería

Actualizamos el fichero JAR anterior o el directorio classes añadiendo la nueva clasecreada.

4. Probar el tag

Utilizamos una página como:

<%@ taglib uri="pruebatags" prefix="pt"%>

<HTML>

Servlets y JSP

137Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 138: Servlets y JSP - Experto Java

<BODY ><%int valor = 0;%><pt:itera veces="5">

Valor = <%=valor%><%valor+=10;%>

</pt:itera></BODY></HTML>

19.5. Tags anidados

Veremos por último cómo crear tags contenidos en otros tags. Como ejemplo haremos untag switch-case donde el tag padre contendrá el switch con un valor global, y dentropodrá tener uno o varios tag case que se ejecutarán en caso de que el valor globalcoincida con el suyo.

1. Creación de la clase que implementa el Tag

En este caso tenemos 2 clases (porque tenemos 2 tags). El switch padre loimplementamos en la clase TagSwitch:

package pruebatags;

import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;

public class TagSwitch implements Tag{

private PageContext contexto; // Contexto del tagprivate Tag padre; // Tag padre del actualString valor; // Valor para comparar

// Metodo llamado cuando se comienza el tagpublic int doStartTag() throws JspException{

return EVAL_BODY_INCLUDE;}

// Metodo llamado cuando se termina el tagpublic int doEndTag() throws JspException{

return EVAL_PAGE;}

// Metodo de limpiezapublic void release() {}

// Metodo para asignar el contextopublic void setPageContext(final PageContext contexto){

this.contexto = contexto;}

// Metodo para asignar el tag padrepublic void setParent(final Tag padre)

Servlets y JSP

138Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 139: Servlets y JSP - Experto Java

{this.padre = padre;

}

// Metodo para obtener el padrepublic Tag getParent(){

return padre;}

// Obtiene el valor con que comparar con los casepublic String getValor(){

return valor;}

// Establece el valor con que comparar con los casepublic void setValor(String valor){

this.valor = valor;}

}

En el campo valor se guarda el valor con que se compararán luego los case para ver cuálencaja. Con los métodos getValor() y setValor() se puede obtener/establecer dicho valor.Observar también que en doStartTag() se devuelve EVAL_BODY_INCLUDE para quese evalúe el cuerpo del tag. El resto es muy parecido a los primeros tags vistos.

Definimos también el tag case, implementado en la clase TagCase:

package pruebatags;

import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;

public class TagCase implements Tag{

private PageContext contexto; // Contexto del tagprivate Tag padre; // Tag padre del actualString valor; // Valor del case

// Metodo llamado cuando se comienza el tagpublic int doStartTag() throws JspException{

TagSwitch miPadre = (TagSwitch)getParent();

if(miPadre==null)throw new JspException("case sin switch");

try{

if(miPadre.getValor().equals(getValor()))return EVAL_BODY_INCLUDE;

elsereturn SKIP_BODY;

} catch(NullPointerException e) {

if(miPadre.getValor()==null ||

Servlets y JSP

139Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 140: Servlets y JSP - Experto Java

getValor()==null)return EVAL_BODY_INCLUDE;

elsereturn SKIP_BODY;

}}

// Metodo llamado cuando se termina el tagpublic int doEndTag() throws JspException{

return EVAL_PAGE;}

// Metodo de limpiezapublic void release() {}

// Metodo para asignar el contextopublic void setPageContext(final PageContext contexto){

this.contexto = contexto;}

// Metodo para asignar el tag padrepublic void setParent(final Tag padre){

this.padre = padre;}

// Metodo para obtener el padrepublic Tag getParent(){

return padre;}

// Obtiene el valor del casepublic String getValor(){

return valor;}

// Establece el valor del casepublic void setValor(String valor){

this.valor = valor;}

}

El campo valor aquí guarda el valor de cada case concreto. En el método doStartTag()se obtiene el tag padre, y se compara su valor con el del tag case actual. Si coinciden, seevalúa el cuerpo del tag, y si no no se evalúa.

2. Crear el fichero TLD

Modificamos el fichero TLD anterior, añadiéndole los dos tags:

<tag><name>switch</name><tagclass>pruebatags.TagSwitch</tagclass>

Servlets y JSP

140Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 141: Servlets y JSP - Experto Java

<bodycontent>JSP</bodycontent><info>Tag switch</info><attribute>

<name>valor</name><required>true</required><rtexprvalue>true</rtexprvalue>

</attribute></tag>

<tag><name>case</name><tagclass>pruebatags.TagCase</tagclass><bodycontent>JSP</bodycontent><info>Tag case</info><attribute>

<name>valor</name><required>true</required><rtexprvalue>true</rtexprvalue>

</attribute></tag>

Llamamamos a los tags switch y case respectivamente. Como atributo le pasamos elvalor de cada uno, con un parámetro llamado valor.

3. Crear un JAR con la librería

Actualizamos el fichero JAR anterior o el directorio classes añadiendo las nuevasclases creadas.

4. Probar el tag

Utilizamos una página como:

<%@ taglib uri="pruebatags" prefix="pt"%>

<HTML><BODY >

<pt:switch valor="a"><pt:case valor="b">

Si sale esto es que el valor es b</pt:case>

<pt:case valor="a">Si sale esto es que el valor es a

</pt:case>

<pt:case valor="c">Si sale esto es que el valor es c

</pt:case></pt:switch>

</BODY></HTML>

19.6. Método simplificado de creación de tags

Servlets y JSP

141Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 142: Servlets y JSP - Experto Java

La forma "clásica" de definir tags propias es muy potente y flexible, pero tambiéncompleja. Por ello, en la versión 2.0 de JSP se introdujeron alternativas más simples, queson las que veremos ahora.

• Tag files: permiten definir tags como bloques de código JSP, es decir, son similares alos includes que ya hemos visto en sesiones anteriores, pero en forma de tags.

• Simple tags: usan código Java para definir las tags, pero el API es mucho mássencillo de usar que el API "clásico".

19.6.1. Tag files

Un "tag file" es simplemente un archivo que encapsula un fragmento de código JSPreutilizable. Por convenio, estos archivos tienen extensión .tag. El caso más simple seríaun bloque de texto fijo. Por ejemplo, supongamos que la siguiente línea se guarda en unarchivo llamado copyright.tag

Copyright JTECH 2008

Los archivos .tag deben colocarse en un directorio tags dentro de la carpeta WEB-INF.Ahora podemos usar el tag en nuestro JSP de la misma forma que lo hacemos con taglibsde terceros:

<%@ taglib prefix="jtech" tagdir="/WEB-INF/tags" %><jtech:copyright/>

Nótese que el nombre del tag es el nombre físico del archivo en que está definido.

En este ejemplo tan trivial, usar un tag file sería equivalente a hacer un include. Noobstante,como veremos a continuación, los tag files permiten el paso de parámetros demanera más sencilla que con <jsp:include>, generando por tanto JSPs mucho másclaros y concisos.

19.6.1.1. Paso de parámetros

Los archivos de tags se pueden parametrizar. Estos parámetros se denominan en elestándar JSP atributos y se definen con la directiva JSP del mismo nombre. Dichadirectiva solo es válida en archivos de tag. Por ejemplo, podemos cambiarcopyright.tag por el siguiente:

<%@ attribute name="anyo" required="true" rtexprvalue="false"%>Copyright JTECH ${anyo}

El required especifica si el parámetro es o no obligatorio y rtexprvalue si puede usarseEL en el parámetro o tiene que ser un literal. En nuestro ejemplo debe ser esto último.Ahora para usarlo en un JSP, haríamos

Servlets y JSP

142Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 143: Servlets y JSP - Experto Java

<%@ taglib prefix="jtech" tagdir="/WEB-INF/tags" %><jtech:copyright anyo="2008"/>

Por supuesto, el parámetro será más útil si puede ser variable. El siguiente tag estápreparado para aceptar una variable Java de tipo Date y formatearla en el formatodía/mes/año:

<%@ tag import="java.util.Date"import="java.text.SimpleDateFormat"%><%@ attribute name="fecha" required="true" type="java.util.Date" %><%

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");out.print(sdf.format(fecha));

%>

Hay varios puntos interesantes en el archivo de tag anterior:

• En la directiva attribute, el type indica el tipo de dato que aceptará nuestro tagcomo parámetro

• La directiva tag, que hasta el momento no habíamos necesitado, nos permite importarlos packages necesarios. Es similar a la directiva page usada en los JSP.

• Hemos introducido un par de líneas de código Java en forma de scriptlet. Hay querecalcar que un archivo de tag no es más que un fragmento de JSP, por lo que seráválida cualquier construcción que se pueda usar en un JSP.

Ahora para demostrar el uso de nuestra recién creada etiqueta podemos hacer:

<%@ taglib prefix="jtech" tagdir="/WEB-INF/tags"%><jtech:fmtFecha fecha="<%= new java.util.Date() %>"/>

Obsérvese que como valor de fecha hemos usado un scriptlet en lugar de una constante, adiferencia del ejemplo anterior.

19.6.1.2. Etiquetas con contenido

En todos los ejemplos vistos hasta el momento, el tag creado no tenía "cuerpo", soloatributos. Podemos usar también el valor del cuerpo en nuestros tags. Por ejemplo,supongamos un tag propio que pase un texto a mayúsculas:

<%@ taglib prefix="test" tagdir="/WEB-INF/tags"%>...<test:capitalizar>Esto es un texto que la etiquetadebería pasar a mayúsculas</test:capitalizar>

La acción <jsp:body/> obtiene el contenido del cuerpo de nuestro tag. El atributo var deesta acción nos permite guardarlo en un objeto en ámbito de página, petición, sesión oaplicación. El ámbito se controla con el atributo scope. Veamos cómo se podríaimplementar nuestro tag:

Servlets y JSP

143Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 144: Servlets y JSP - Experto Java

<jsp:doBody var="texto" scope="request"/><%

String texto = (String) request.getAttribute("texto");out.print(texto.toUpperCase());

%>

19.6.2. Simple tags

En tags propios que requieran gran cantidad de código java, los scriptlets necesarios en elarchivo de tag pueden volverse demasiado difíciles de mantener, dándose el mismoproblema que tienen los JSP con gran cantidad de código Java. En ese caso, será muchomejor encapsular el código del tag en una clase Java aparte. Esta idea está presente enJSP desde las primeras versiones. El problema es que cuando se diseñó la forma "clásica"de definir tags con código Java se pensó en la potencia y flexibilidad, pero no en lafacilidad de desarrollo. Así, la complejidad de crear tags java de la forma clásica no estájustificada en la gran mayoría de casos, excepto los más sofisticados. Para resolver esteproblema, en la versión 2.0 de JSP se introdujo una forma simplificada de programar tagsque se llamó simple tags.

Crear un tag simple implica dos pasos:

• Escribir la clase Java que implementa el tag• Crear un descriptor de despliegue (.tld)

19.6.2.1. Clase Java para implementar el tag

La clase Java que implemente el tag debe implementar el interfaz SimpleTag. Dichointerfaz tiene los métodos que se muestran a continuación:

package javax.servlet.jsp.tagext;public interface SimpleTag extends JspTag {

public void doTag() throws JspException, IOException;public JspTag getParent();public void setJspBody(JspFragment jspBody);public void setJspContext(JspContext jspContext);public void setParent(JspTag parent);

}

Cuando el contenedor web se encuentra con uno de nuestros tags, instancia un objeto dela clase que lo implementa y va llamando a los métodos del interfaz en un cierto orden:

1. setJspContext: le pasa a nuestro tag la referencia al JspContext, que nos va aproporcionar, si lo necesitamos, acceso a los diferentes ámbitos (sesión, aplicación,...)y al JspWriter que representa la salida

2. setParent: nuestro tag recibirá información de quién es su tag "padre". Eso abre laposibilidad de anidar tags propios de manera que "colaboren" entre sí, modificando sucomportamiento y pasándose información cuando están anidados.

3. setJspBody: nuestro tag recibe también el cuerpo que contiene, en forma de objeto de

Servlets y JSP

144Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 145: Servlets y JSP - Experto Java

la clase JspFragment

4. doTag: es el método más importante. Indica que "es hora de hacer el trabajo".

Veamos un ejemplo sencillo, que se limita a mostrar la fecha del sistema en el formatodía/mes/año

package jtech;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.SimpleTagSupport;

public class TestSimpleTag extends SimpleTagSupport {public void doTag() throws JspException, IOException {

SimpleDateFormat sdf = newSimpleDateFormat("dd/MM/yy");

getJspContext().getOut().write(sdf.format(newDate()));

}}

En el código, en lugar de implementar directamente el interfaz SimpleTag, que nosobligaría a definir todos sus métodos, los necesitemos o no, hemos heredado de la claseSimpleTagSupport, que ya incluye una definición por defecto para ellos.

El trabajo de nuestro tag es muy sencillo. A través del getJspContext().getOut()obtenemos el JspWriter de la salida y en él escribimos la fecha formateada.

Evidentemente este es un ejemplo con un código tan trivial que no justifica el uso de untag simple en lugar de un archivo de tag. No obstante, conforme el número de líneas y lacomplejidad de código va creciendo, la balanza se inclina progresivamente más hacia estetipo de tag, sin olvidar las posibilidades que se nos dan de anidar tags propioscomunicándolos entre sí.

19.6.2.2. Descriptor de despliegue (.tld)

Se debe crear un archivo .tld en el que, con etiquetas XML describimos las característicasde nuestros nuevos tags. Por convenio, se suele colocar en WEB-INF/tlds, aunque esto noes obligatorio. Aquí tenemos el .tld para nuestro ejemplo:

<?xml version="1.0" encoding="UTF-8" ?><taglib xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"version="2.1"><description>Ejemplo de simple tag

</description><jsp-version>2.1</jsp-version><tlib-version>1.0</tlib-version><short-name>test</short-name>

Servlets y JSP

145Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 146: Servlets y JSP - Experto Java

<uri>http://www.jtech.ua.es/ayto/test</uri><tag><name>test</name><tag-class>jtech.TestSimpleTag</tag-class><body-content>empty</body-content><description>

Es una prueba tonta, en realidad</description>

</tag></taglib>

Como vemos, en el descriptor, entre otros datos, decimos qué clase Java implementa eltag y cuál va a ser su nombre en JSP (test). Ahora ya podemos usarlo en nuestros JSPs:

<%@ taglib prefix="jtech" uri="WEB-INF/tlds/test.tld"%>...<jtech:test/>

19.6.2.3. simple tags con atributos

Un ejemplo más realista de tag usaría atributos. Afortunadamente su uso es muy sencillo.Por cada atributo que acepte nuestro tag simplemente necesitamos un getter y un setter ennuestro código Java. Modificando el ejemplo anterior:

public class TestSimpleTag extends SimpleTagSupport {private Date fecha;

public void doTag() throws JspException, IOException {SimpleDateFormat sdf = new

SimpleDateFormat("dd/MM/yy");getJspContext().getOut().write(sdf.format(fecha));

}public Date getFecha() {

return fecha;}public void setFecha(Date fecha) {

this.fecha = fecha;}

}

Ahora nuestro tag admitirá un atributo fecha en el que le pasamos la fecha a formatear.Nos falta especificarlo en el .tld:

<?xml version="1.0" encoding="UTF-8" ?><taglib xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"version="2.1"><description>Ejemplo de simple tag

</description><jsp-version>2.1</jsp-version><tlib-version>1.0</tlib-version>

Servlets y JSP

146Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 147: Servlets y JSP - Experto Java

<short-name>test</short-name><uri>http://www.jtech.ua.es/ayto/test</uri><tag><name>test</name><tag-class>jtech.TestSimpleTag</tag-class><body-content>empty</body-content><description>

Es una prueba tonta, en realidad</description><attribute>

<name>fecha</name><required>true</required><rtexprvalue>true</rtexprvalue>

</attribute></tag>

</taglib>

Servlets y JSP

147Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 148: Servlets y JSP - Experto Java

20. Ejercicios de creación de librerías de tags

20.1. Gestor de tags para un tag que formatee números reales

En la plantilla tenemos una aplicación jsp-sesion10, y en su directorio de fuentestenemos una clase Java llamadaes.ua.jtech.jsp.sesion10.libtags1.FormateaDoubleTag. Dicha clase está vacía,pero deberá contener el código necesario para desarrollar un tag llamadoformateadouble. Dicho tag admitirá dos atributos:

• Uno llamado valor, que contendrá un valor real• Uno llamado decimales, que indicará un número de decimales concreto (un valor

entero: 0, 1, 2... etc).

Lo que hará el tag será formatear el valor real que le pasamos en valor, para sacarlo en lapágina con tantos decimales como indiquemos en decimales. El tag no tendrá cuerpo.

Para hacer eso, podemos utilizar la clase java.text.NumberFormat de Java, que permiteindicar con cuántos decimales queremos formatear un determinado número:

NumberFormat nf=NumberFormat.getInstance();nf.setMaximumFractionDigits(2);nf.setMinimumFractionDigits(2);...System.out.println (nf.format(2.34786)); // Sacaría2.35System.out.println (nf.format(2.7)); //Sacaría 2.70

Deberemos rellenar la clase, con los métodos doStartTag(), doEndTag() y los métodospara acceder y establecer el valor de los campos y atributos que se tengan. Podemosfijarnos en el tag Saludo visto en teoría como ejemplo.

20.2. Configuración y prueba de nuestro tag

Una vez hecha la clase del tag, vamos a probarla en una página JSP. Para ello:

• Creamos el fichero TLD (libtags1.tld) que dé soporte a la librería. Dicho ficherosólo tendrá información del tag que hemos creado, indicando su nombre, atributos, ycaracterísticas.

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc. ...<taglib>

<tlibversion>1.0</tlibversion><jspversion>1.1</jspversion><shortname>lt1</shortname><uri>libtags1</uri>

Servlets y JSP

148Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 149: Servlets y JSP - Experto Java

<info>Ejercicio de libreria propia</info>

<tag><name>formateadouble</name><tagclass>...</tagclass><bodycontent>...</bodycontent><info>Formatea un double con n decimales</info><attribute>

<name>valor</name><required>...</required><rtexprvalue>...</rtexprvalue>

</attribute><attribute>

<name>decimales</name><required>...</required><rtexprvalue>...</rtexprvalue>

</attribute></tag>

</taglib>

Las etiquetas que tienen puntos suspensivos (...) deben rellenarse adecuadamente:nombre de la clase que implementa el tag (tagclass), tipo de contenido(bodycontent), y características de los atributos: el primero (valor) será requerido, yadmitirá expresiones <%=...%>, y el segundo (decimales) no será requerido (tomarávalor de 0 decimales, por defecto), y no admitirá dichas expresiones.

Copiamos dicho fichero en el directorio WEB-INF de la aplicación.

• Modificamos el fichero descriptor (web.xml) para añadir el fichero TLD anterior:

<taglib><taglib-uri>libtags1</taglib-uri><taglib-location>/WEB-INF/libtags1.tld</taglib-location>

</taglib>

• Creamos una página pruebaformato.jsp, que invoque al tag anterior:

<%@ taglib uri="libtags1" prefix="lt1"%>

...Numero con 3 decimales:<lt1:formateadouble valor="2.35879" decimales="3"/>

...

La llamamos con:

http://localhost:8080/appmistags/pruebaformato.jsp

Y debería devolver 2.359 para el caso anterior.

20.3. (*) Iterador sobre una cadena

Construid sobre la librería anterior una etiqueta llamada iteraCadena de tipo BodyTag

Servlets y JSP

149Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 150: Servlets y JSP - Experto Java

(que permita iterar sobre su contenido), que tome como parámetro un atributo cadena,que sea un String. La etiqueta tendrá a su vez una subetiqueta llamada carActual quesacará por pantalla el carácter en la cadena correspondiente a la iteración actual. De estaforma, un código como:

<%@ taglib uri="libtags1" prefix="lt1"%>

...<lt1:iteraCadena cadena="miCad">

<lt1:carActual/> -</lt1:iteraCadena>

...

debería sacar por pantalla: m - i - C - a - d -

20.4. (*) Tag files

Crear un "tag file" que sirva para mostrar en un JSP el login del usuario actual de laaplicación y un enlace para hacer logout. Para simplificar, supondremos que el login delusuario está almacenado en el atributo login de la sesión. Para hacer logout supondremosque basta con borrar el objeto de la sesión. Además del tag file, se deberán implementarlos servlets y jsps necesarios para poder hacer login, logout, y probar la etiqueta creada.

20.5. (*) Simple tags

Crear un simple tag que sirva para colorear alternativamente elementos HTML que serepitan con un bucle (por ejemplo, filas de una tabla),de modo que vayan alternando endos colores. El tag se usaría así:

<table><c:forEach var="item" items="${cart}">

<jtech:colorea color1="yellow" color2="blue"><td> ${item} </td>

</jtech:colorea></c:forEach></table>

El coloreado se podría hacer generando finalmente un HTML como el siguiente:

<table><tr style="color:yellow">

<td> 100 </td></tr><tr style="color:blue">

<td> 50 </td></tr>...

</table>

Servlets y JSP

150Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 151: Servlets y JSP - Experto Java

21. Filtros y Wrappers

Hasta ahora hemos visto la forma en la que los servlets nos permiten encapsular elmecanismo de petición/respuesta. Se identifica al servlet como un recurso dentro del sitioweb, y cuando desde el cliente solicitamos dicho recurso, se ejecutará el código quehayamos definido dentro del método de servicio del servlet.

La limitación de los servlets es justamente esa, que un servlet se invocará sólo cuandosolicitemos dicho servlet desde el cliente. Pero, ¿y si queremos procesar cualquierpetición que se haga a cierta parte o toda nuestra aplicación web?

Si sólo contamos con servlets, para solucionar esto podríamos optar por alguna de lassiguientes opciones por ejemplo:

• Crear un servlet central que invocaremos siempre desde el cliente pasándole comoparámetro el recurso que deseamos obtener. Tiene el inconveniente de que no estransparente para desarrollador del contenido de nuestra aplicación web, ya quedeberá definir todos los enlaces del sitio para que vayan al servlet.

• Introducir al comienzo de todos los servlets de nuestra aplicación una llamada a ciertafunción que haga el procesamiento que queremos realizar. Esto no nos serviría para elcontenido estático de la aplicación web. Además tampoco es transparente ya que eldesarrollador de los servlets deberá realizar una llamada a este código. Otroinconveniente es que estaremos repitiendo código común en varios elementos, lo cualva en contra de la modularidad.

• Configurar el servidor web (si nos lo permite) para que cualquier petición de recursosea redirigida a un servlet que la procese. Esta sería la solución más apropiada, perotendremos el problema de que si el servlet internamente quiere hacer la petición delrecurso al servidor, volverá a redireccionarlo a si mismo, por lo que podemos entraren un bucle infinito. Por lo tanto, surgirán problemas con la identificación de losrecursos.

Como vemos, por ahora este problema no tiene ninguna solución totalmente satisfactoria.Para ello, a partir de la versión 2.3 de servlets, aparecen los denominados filtros.

21.1. ¿Qué es un filtro?

Un filtro es un componente que intercepta cualquier petición que se realice a undeterminado grupo de recursos de nuestra aplicación web, y la respuesta que se vaya adevolver al cliente por parte del servidor.

Normalmente los filtros no generarán por si mismos la respuesta, como es el caso de losservlets, sino que simplemente la modificarán si es necesario. Podrán modificar tanto lapetición HTTP, como la respuesta o las cabeceras de la misma.

Una ventaja importante de los filtros es que nos ayudarán a modularizar la aplicación, ya

Servlets y JSP

151Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 152: Servlets y JSP - Experto Java

que son componentes independientes que actuarán sobre cualquier grupo de recursos, noteniendo dichos recursos porque conocer la existencia de estos filtros. De esta forma estefiltrado de las peticiones y respuestas a nuestro servidor se realiza de un forma totalmentetransparente en todos los niveles, tanto para el cliente como para los desarrolladores delcontenido del sitio web (servlets, JSPs, páginas estática, y cualquier otro recurso).

Esta independencia implica por lo tanto que los filtros podrán ser reutilizados paracualquier elemento del sitio web, sin necesidad de incluir código común en todos loselementos que queramos que realicen dicha funcionalidad.

21.2. Funcionalidades de los filtros

Un filtro podrá acceder a la petición de un determinado recurso antes de que dichorecurso sea invocado, momento en el que podremos procesar o modificar dicha petición.

Una vez se ha invocado la petición, podremos procesar o modificar la respuesta que nosha devuelto el servidor.

Además, podremos tener múltiples filtros actuando sobre determinados grupos derecursos. De esta forma un recurso podrá no ser filtrado, o ser filtrado por uno o másfiltros. Cuando tenemos varios filtros, se organizarán en forma de cadena en el orden quenosotros especifiquemos, y cada uno procesará el resultado del anterior.

21.3. Aplicaciones de los filtros

Hemos descrito lo que es un filtro, pero entenderemos más claramente los filtros si vemosuna serie de posibles aplicaciones que les podemos dar:

• Autentificación de usuarios: Podemos definir un filtro que actúe sobre cierta zonarestringida de nuestra aplicación web. Si el usuario está registrado el filtro dejará verel contenido tal cual, si no le redirigirá a la página con el formulario de registro deusuarios.

• Transformación con hojas XSL-T: Si tenemos una serie de páginas escritas en XML,y una serie de hojas de transformación XSL-T para generar código para distintosnavegadores, podremos definir un filtro que actúe sobre el conjunto de documentosXML, y aplique una transformación según el tipo de navegador que hizo la petición.Devolverá al cliente la respuesta transformada, adaptada al navegador adecuado.

• Transformación de imágenes: Igual que transformamos documentos XML, tambiénpodemos aplicar los filtros a determinados formatos de imágenes, y transformardichas imágenes dinámicamente a un formato más adecuado.

• Encriptación de datos: Podemos utilizar un filtro para que encripte la salida decualquier recurso al que se acceda. El cliente deberá ser capaz de desencriptarlo parapoder visualizar dicho contenido.

• Compresión de datos: De forma similar al punto anterior, podemos comprimir losdatos que genera el servidor.

Servlets y JSP

152Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 153: Servlets y JSP - Experto Java

• Registro de acceso a recursos: Se puede contabilizar mediante un filtro la cantidad deaccesos a cada recurso de nuestra web. Como todas las peticiones pasan a través de él,simplemente tendrá que incrementar la cantidad de visitas al recurso que se solicite encada momento.

• Log de accesos: Podemos también elaborar un fichero de log de accesos a la web,para conocer los datos de todos los accesos que se han realizado.

21.4. Configuración de un filtro

Para que un filtro intercepte las peticiones a determinados recursos, deberemos configurarla aplicación web para que esto sea así. La forma de configurar los filtros es similar a laconfiguración de los servlets.

Los filtros, al igual que los servlets, serán clases Java que definamos, y que tendremosnormalmente en el directorio WEB-INF/classes de nuestra aplicación web, osubdirectorios de este si está en algún subpaquete. La configuración de los filtros deberáestablecerse en el fichero de configuración de nuestra aplicación web, WEB-INF/web.xml.

Es importante recordar que en este fichero de configuración, por ser un lenguaje definidomediante un DTD en XML, se debe respetar el orden en el que aparecen los distintoselementos. Los elementos para la configuración de filtros deben ir tras los elementoscontext-param, y antes de listener y servlet.

Primero deberemos declarar los filtros incluidos en nuestra aplicación web. Para ellodeberemos utilizar el elemento filter que se define de la siguiente forma en el DTD:

<!ELEMENT filter (icon?, filter-name, display-name?,description?, filter-class, init-param*)>

Un ejemplo de uso de este elemento en el fichero de configuración web.xml es elsiguiente:

<filter><filter-name>Filtro de ejemplo</filter-name><filter-class>FiltroEjemplo</filter-class><init-param>

<param-name>fichero_log</param-name><param-value>log.txt</param-name>

</init-param></filter>

Es muy similar a la forma de declarar un servlet. Asignamos un nombre al filtro, que seráasociado a la clase en la que está implementado dicho filtro. En este caso la clase esFiltroEjemplo, por lo que tendremos que tener el fichero FiltroEjemplo.class en eldirectorio WEB-INF/classes de nuestra aplicación.

A continuación podemos declarar una serie de parámetros de entrada para el filtro, deforma que para variar estos datos no tengamos que modificar y recompilar la clase delfiltro, sino que simplemente deberemos modificar el valor del parámetro en este fichero

Servlets y JSP

153Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 154: Servlets y JSP - Experto Java

de configuración. Podremos no tener ningún parámetro, tener uno, o tantos comoqueramos.

Una vez declarados los filtros deberemos mapearlos a los recursos. Las peticiones que sehagan al servidor a estos recursos, serán interceptadas por nuestro filtro. Podemos mapearfiltros a recursos de distintas formas, con la etiqueta filter-mapping que se define de lasiguiente forma en el DTD:

<!ELEMENT filter-mapping (filter-name, (url-pattern |servletname))>

Ejemplos de utilización de las dos formas posibles de mapeado son los siguientes:

<filter-mapping><filter-name>Filtro de ejemplo</filter-name><servlet-name>Servlet interceptado</servlet-name>

</filter-mapping>

<filter-mapping><filter-name>Filtro de ejemplo</filter-name><url-pattern>/*</url-pattern>

</filter-mapping>

La primera forma nos sirve para mapearlo a un servlet, dado el nombre del servlet al quelo vamos a asociar. La segunda forma asocia el filtro a todos los elementos cuya URLcumpla el patrón dado:

/* Se asocia con todos los elementos de nuestraaplicación web./zona_restringida/* Se asocia con todos los elementos en eldirectorio de nombre

zona_restringida, y con los de sussubdirectorios./web/* Se asocia con todos los elementos en eldirectorio de nombre

web, y con los de sus subdirectorios....

Podemos asociar varios filtros a un mismo recurso, si dicho recurso aparece mapeadopara varios filtros. En este caso tendremos una cadena de varios filtros cuando seproduzca una petición a este recurso.

Servlets y JSP

154Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 155: Servlets y JSP - Experto Java

Encadenamiento de filtros

21.5. Implementación básica de un filtro

Los filtros se definen mediante la interfaz Filter, contenida en el paquetejavax.servlet. Por lo tanto, para crear un filtro deberemos crear una clase queimplemente dicha interfaz:

import javax.servlet.*;import javax.servlet.http.*;

class MiFiltro implements Filter {FilterConfig config;

Dentro de este clase, el método básico que deberemos implementar será el métododoFilter, al que se llamará cada vez que dicho filtro intercepte una petición a recursos:

public void doFilter(ServletRequest request,ServletResponse response,

FilterChain chain)throws IOException, ServletException {

...

Vemos que a este método se le pasa como parámetro la petición y la respuesta, de formaque podamos procesarlas o modificarlas según la funcionalidad que queramos queimplemente el filtro. Hemos de fijarnos que toma una petición y respuesta genérica, no selimita únicamente a peticiones y respuestas HTTP.

Además también se nos proporciona un objeto que representa la cadena de filtros. Con élpodremos pasar la petición y la respuesta interceptadas al siguiente filtro de la cadena, obien al recurso destino en caso de que ya no hubiese más filtros. Esto lo haremos con unallamada a:

...chain.doFilter(request, response);

Servlets y JSP

155Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 156: Servlets y JSP - Experto Java

... // En este punto el servidor ya habrá producido//la respuesta en response

}

Justo después de haber llamado a este método, ya se habrá producido la respuesta, ya quecon él estamos indicando que se ejecuten todos los filtros que siguen al nuestro en lacadena, y en último lugar el recurso solicitado.

Por lo tanto, todas las modificaciones que queramos hacer en la petición que va a llegar alrecurso las deberemos hacer antes de la llamada a este método, mientras que todoprocesamiento que queramos hacer de la respuesta se hará después de esta llamada, queserá cuando se haya generado.

También podemos hacer que no se llegue a llamar, si queremos que nuestro filtro de larespuesta por si solo, sin acceder al recurso que se había pedido. Esto lo haremos porejemplo cuando queramos prohibir el acceso a un recurso.

Otros métodos que debemos definir en un filtro son:

public void init(FilterConfig config) throwsServletException {

// Código de inicialización del filtrothis.config = config;...

}

public void destroy() {// Libera recursos del filtroconfig = null;...

}

...

}

Que serán llamados en la inicialización y en la destrucción de este componenterespectivamente.

21.6. Acceso al contexto

Acabamos de ver que cuando se inicializa el filtro se llama a su método init. En estallamada se proporciona un objeto FilterConfig que contiene información sobre losparámetros del filtro, que vimos en el apartado de configuración, y además nos permiteacceder a la información global de contexto.

Para leer los parámetros del filtro especificados en el descriptor de despliegue de laaplicación web (fichero web.xml en Tomcat como hemos visto), este objeto proporcionael siguiente método:

Servlets y JSP

156Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 157: Servlets y JSP - Experto Java

String valor = config.getInitParameter(nombre_param);

Esta llamada nos devolverá una cadena con el valor del parámetro, o null en el caso deque el parámetro indicado no existiese. Si queremos obtener la lista de parámetrosdefinidos en el descriptor de despliegue, podemos usar el siguiente método:

Enumeration parametros = config.getInitParameterNames();

Con esto obtendremos una enumeración de todos los nombres de parámetros definidos.

Este objeto también nos permite obtener el nombre del filtro, que se habrá definido en eldescriptor de despliegue, con el método:

String nombre = config.getFilterName();

Este objeto además nos permitirá acceder al objeto de contexto global del contenedor deservlets, mediante el método:

ServletContext context = config.getServletContext();

Obtenemos este objeto con el cual podremos acceder a los atributos globales definidos ennuestra aplicación web, y además nos proporciona una serie de métodos que nospermitirán realizar en filtros las mismas operaciones que podíamos hacer en los servlets.

Será importante acceder a este objeto desde los filtros, ya que si queremos realizarredirecciones, o acceso a recursos estáticos por ejemplo, necesitaremos contar con dichoobjeto.

21.7. Ciclo de vida de un filtro

Justo después del despliegue de la aplicación web, y antes de que se produzca cualquierpetición a un recurso, el contenedor localizará los filtros que deben ser aplicados a cadarecurso. Instanciará los filtros que hayamos declarado, y tras ello llamará al método init

de cada filtro para inicializarlo.

Si hacemos que este método init lance una excepción UnavailableExeption estaremosindicando que el filtro no puede funcionar correctamente. Esta excepción tiene un métodoisPermament que indicará si el fallo es permanente o puede recuperarse pasado untiempo. De no ser permanente el contenedor intentará volver a instanciar el filtro másadelante. Podemos establecer en la excepción un tiempo estimado que puede tardar enestar disponible, para informar al contenedor de cuando puede volver a intentarinstanciarlo.

Al método init se le proporcionará el objeto FilterConfig, con la información de losparámetros y nombre del filtro obtenidos del descriptor de despliegue, además de unareferencia al objeto ServletContext de la aplicación web, como hemos visto en elapartado anterior.

Una vez terminada la fase de inicialización, el servidor ya podrá empezar a recibir

Servlets y JSP

157Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 158: Servlets y JSP - Experto Java

peticiones. Cuando se produzca una petición, el contenedor localizará el primer filtroasociado a dicho recurso, y llamará a su método doFilter proporcionando los objetosServletRequest, ServletResponse, y FilterChain. Una vez hecho esto seráresponsabilidad de nuestro filtro tratar estos objetos, y decidir si pasar el procesamiento alsiguiente filtro de la cadena.

Cuando lleguemos al ultimo filtro de la cadena, al llamar a doChain se invocarádirectamente el recurso que se solicitaba en la petición.

Si durante doFilter lanzamos una excepción UnavailableException, el contenedor nointentará seguir procesando la cadena de filtros. Si hemos indicado que es no permanente,tras un rato reintentará procesar la cadena entera.

Antes de poder hacer que el filtro deje de estar en servicio, llamará a su método destroy

para que libere los recursos que sea necesario.

21.8. Wrappers

Hasta ahora hemos visto como interceptar la petición que se realiza a un determinadorecurso de nuestra web mediante filtros, pero, ¿y si queremos interceptar la respuesta quenos devuelve el servidor para analizarla o modificarla?

Cuando desde nuestro filtro pasemos el procesamiento de la petición al siguienteelemento de la cadena (doFilter), delegaremos en este siguiente elemento elprocesamiento de la petición y la generación de la respuesta. Supongamos que esteelemento es el recurso final que se había solicitado. En este caso el contenido de esterecurso será escrito en el objeto respuesta, lo cual producirá que dicho contenido seadevuelto al cliente.

Sin embargo, nosotros no queremos que sea devuelto directamente al cliente, sino quequeremos procesarla previamente en nuestro filtro antes de devolverla. Con este objetoServletResponse (HttpServletResponse) no podremos hacer esto, ya que cuando seescribe en él lo que se hace es devolver la respuesta al cliente, y una vez escrita nopodemos acceder nuevamente a ella ni modificarla.

La solución a nuestro problema es sustituir el objeto respuesta que proporcionamos alsiguiente elemento de la cadena por un objeto de respuesta creado por nosotros.

21.8.1. ¿Qué es un wrapper?

Un wrapper es un objeto que envuelve al objeto original, de forma que no se accedadirectamente al objeto original sino al wrapper. El wrapper implementará la mismainterfaz del objeto al que envuelve, de forma que externamente se trabajará con él de lamisma forma, por lo que podemos sustituir el original por el wrapper siendo estotransparente a los sucesivos elementos que vayan a manipular este objeto.

Servlets y JSP

158Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 159: Servlets y JSP - Experto Java

Cuando se llame a un método del wrapper podrá, o bien redirigir la llamada alcorrespondiente método del objeto original al que envuelve, o bien tratar por si mismo lallamada a dicho método. De esta forma, podremos redefinir el comportamiento quetendrán determinadas operaciones.

Encontramos para nuestro fin wrappers para la petición y la respuesta:ServletRequestWrapper (HttpServletRequestWrapper) y ServletResponseWrapper

(HttpServletResponseWrapper). Con ellos podremos crear implementaciones propiasdel objeto petición y respuesta que envuelvan a los originales, pudiendo de esta formaredefinir el comportamiento de determinadas operaciones.

Nos centraremos en el wrapper de la respuesta. Con él podemos evitar que la respuesta seenvie directamente al cliente. En lugar de esto, cuando se escriba la salida en este objetowrapper de la respuesta podemos hacer que guarde dicha salida en un buffer interno. Unavez procesados todos los elementos de la cadena que están después de nuestro filtro (trasllamar a doFilter), se habrá escrito la salida generada en el buffer del wrapper. En estemomento podemos analizar esta salida, modificarla si es necesario, y enviarla a través delobjeto respuesta original.

21.8.2. Implementación de un wrapper

Para implementar un wrapper deberemos crearnos una subclase de la clase del wrapperadecuado para nuestro caso (petición o respuesta), y redefinir en esta subclase lasoperaciones cuyo comportamiento queramos cambiar. El funcionamiento por defecto delas operaciones que no redefinamos será redirigir la petición al método correspondientedel objeto (petición o respuesta) original.

Vamos a ver esto con un ejemplo de implementación de un wrapper de la respuesta queguarda en un buffer la respuesta generada por el servidor, para poder ser procesada pornuestro filtro.

Puesto que queremos envolver la respuesta, tendremos que crearnos una subclase deServletResponseWrapper:

public class GenericResponseWrapper extendsHttpServletResponseWrapper {

Dentro de esta clase deberemos tener el buffer donde vayamos a escribir la salida. Dadoque en la salida se puede escribir tanto como flujo de bytes como de caractéres, para quesea más genérico convendrá crear el buffer como array de bytes, de forma que se puedaescribir en él de las dos formas:

private ByteArrayOutputStream output;

En el constructor de la clase simplemente deberemos proporcionar el objeto respuestaoriginal (al cual estaremos envolviendo). Lo que hacemos aquí es utilizar el constructorde la superclase proporcionándole la respuesta original, de forma que se encargue de

Servlets y JSP

159Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 160: Servlets y JSP - Experto Java

redirigir a él las operaciones predeterminadas. Además deberemos crear nuestro buffer debytes donde se escribirá la respuesta:

public GenericResponseWrapper(HttpServletResponse response){

super(response);output = new ByteArrayOutputStream();

}

Proporcionaremos además un método para obtener los datos escritos en el buffer:

public byte[] getData() {rreturn output.toByteArray();

}

Cuando alguien quiera devolver una respuesta al cliente lo que hará será obtener el flujode salida del objeto respuesta y escribir en él. Por defecto este flujo envia los datos alcliente. Sin embargo podemos evitar que esto ocurra haciendo que los flujos que devuelvasirvan para escribir en el buffer, y no para enviar la respuesta al cliente. Se puede enviarla respuesta de dos formas: mediante un flujo de bytes (getOutputStream), o medianteun flujo de carácteres (getWriter), por lo que deberemos redefinir ambos métodos.

public ServletOutputStream getOutputStream() {return new FilterServletOutputStream(output);

}

public PrintWriter getWriter() {return new PrintWriter(getOutputStream(), true);

}}

En el caso del flujo de bytes, deberemos devolverlo como un ServletOutputStream. Porlo tanto tendremos que crearnos un tipo propio de ServletOutputStream que escriba ennuestro buffer:

public class FilterServletOutputStream extends ServletOutputStream{

private DataOutputStream stream;

public FilterServletOutputStream(OutputStream output) {stream = new DataOutputStream(output);

}

public void write(int b) throws IOException {stream.write(b);

}

public void write(byte[] b) throws IOException {stream.write(b);

}

public void write(byte[] b, int off, int len) throwsIOException {

stream.write(b, off, len);}

Servlets y JSP

160Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 161: Servlets y JSP - Experto Java

}

Este será el flujo que utilicemos para escribir la respuesta en forma de bytes en nuestrobuffer interno.

Aunque a primera vista parezca compleja la creación de dicho wrapper, tiene la ventajade ser reutilizable para cualquier aplicación en la que necesitemos interceptar la respuestagenerada por el servidor.

21.8.3. Utilización de un wrapper

Para utilizar el wrapper que hemos creado, deberemos instanciarlo a partir del objeto derespuesta original que le ha sido proporcionado a nuestro filtro. Esto lo haremos antes deque se haya generado el contenido del recurso solicitado, es decir, antes de llamar adoFilter.

public void doFilter(ServletRequest request,ServletResponse response, FilterChain

chain){

...GenericResponseWrapper wrapper = new

GenericReponseWrapper(response);

Una vez hemos creado nuestro propio objeto respuesta que envuelve a la respuestaoriginal, podemos utilizarlo para que el servidor escriba el contenido del recursosolicitado en él. Para esto realizaremos la llamada a doFilter proporcionando comorespuesta este wrapper que hemos creado:

chain.doFilter(request, wrapper);

Una vez ejecutado este método se habrá generado la respuesta en el objeto de respuestaproporcionado, en este caso habrá sido en nuestro wrapper. Por lo tanto podemos obtenery procesar la respuesta según la función de nuestro filtro:

byte [] datos = wrapper.getData();

... // Procesar datos segun la funcion del filtro

Por último, para que el cliente pueda ver esta respuesta, deberemos escribirla en el objetorespuesta original:

OutputStream out = response.getOutputStream();out.write(datos);out.close();

}

Con esto vemos que habremos podido procesar la salida generada en nuestro filtro, yenviarla al cliente para que pueda ser visualizada correctamente.

21.9. Ejemplos de filtros

Servlets y JSP

161Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 162: Servlets y JSP - Experto Java

Vamos a ver a continuación una serie de ejemplos de usos comunes de los filtros, y cómoimplementaríamos dichos filtros, utilizando distintos elementos que hemos visto duranteel curso.

21.9.1. Acceso restringido

Una primera aplicación sencilla de los filtros es prohibir el acceso a cierta parte denuestra web. Cuando un usuario intente acceder a dicha parte, se comprobará si esteusuario está registrado. Si lo está se le dejará pasar normalmente, pero si no se prohibiráel acceso, redireccionando a la página de login de usuarios.

public class RestringirAcceso implements Filter {

Cuando se invoca el filtro querrá decir que un usuario intenta acceder a la zonarestringida.

public void doFilter(ServletRequest request,ServletResponse response, FilterChain

chain){

// Se intenta acceder a la zona restringida

Comprobamos si el usuario está registrado en el servidor. Para ello utilizamos lainformación de sesión, donde almacenaremos el login del usuario en caso de estarregistrado.

// Solo podemos comprobar la sesión// en el caso de tener una petición HTTP

if(request instanceof HttpServletRequest &&response instanceof HttpServletResponse)

{

HttpServletRequest http_request =(HttpServletRequest)request;

HttpServletResponse http_response =(HttpServletResponse)response;

// * Comprobamos si el usuario se ha registrado *// En nuestra aplicación si el usuario// se ha registrado habremos establecido// el atributo usuario de la sesion al// nombre del usuario, si no será null.

if(http_request.getSession().getAttribute("usuario")!=null)

Si hay un login almacenado, procesamos la petición de forma normal.

{// Continuamos de forma normal con la peticiónchain.doFilter(request, response);

}

Servlets y JSP

162Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 163: Servlets y JSP - Experto Java

Si no, redireccionamos a la página de login, para que el usuario se registre.

else{

// Redireccionamos a la página de loginresponse.sendRedirect("/ejemplo/login.jsp");

}} else {

// Si no es una petición HTTP// simplemente procesamos la petición

chain.doFilter(request, response);}

}}

21.9.2. Ranking de páginas más visitadas

Otra posible aplicación es registrar el número de visitas que se hacen a cada página, deforma que podremos obtener un listado de las páginas favoritas de los usuarios dentro denuestro sitio web. Para ello instalaremos un filtro que intercepte las peticiones a cualquierpágina. Cada vez que el filtro se invoque, querrá decir que se ha visitado una página. Loque deberemos hacer en este momento es:

Determinar la dirección de la página que se ha solicitado

public class Ranking implements Filter {

public void doFilter(ServletRequest request,ServletResponse response, FilterChain

chain){

// Solo podemos ver el recurso solititado en el// caso de tener una petición HTTP

if(request instanceof HttpServletRequest){

HttpServletRequest http_request =(HttpServletRequest)request;

// Miramos que recurso está siendo solicitadoString uri = http_request.getRequestURI();

Tendremos una base de datos con una entrada para cada página, donde se contabilizan elnúmero de visitas. Si no existe entrada para la página visitada, la crearemos con unavisita.

PaginasDAO dao = new PaginasDAO();

if(dao.existePagina(uri){

// La página ya esta registrada en la BD// y solo tenemos que incrementar su contadordao.incrementaContador(uri);

}

Servlets y JSP

163Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 164: Servlets y JSP - Experto Java

Si ya existe entrada para esta página en la BD, incrementaremos el número de visitas.

else{

// La página se está visitando por primera vez// Debemos registrarla en la BD// con contador a 1 (1 visita)

dao.insertaPagina(uri);}

}

Procesamos la petición de forma normal.

chain.doFilter(request, response);}

21.9.3. Extracción automática de información

Imaginemos que en el ranking queremos, además de la dirección, registrar el título de lapágina. A partir de la información de la petición y la respuesta ordinaria no podemosobtener dicha información, ya que se refiere al contenido de la página. Para ellotendremos que utilizar un wrapper, que obtenga la respuesta generada por el servidor, demanera que podamos analizarla y extraer de ella el título de la página.

public class RankingTitulo implements Filter {

public void doFilter(ServletRequest request,ServletResponse response, FilterChain

chain){

// Solo podemos ver el recurso solititado en el caso// de tener una petición HTTP

if(request instanceof HttpServletRequest &&response instanceof HttpServletResponse)

{

HttpServletRequest http_request =(HttpServletRequest)request;

HttpServletResponse http_response =(HttpServletResponse)response;

// Miramos que recurso está siendo solicitadoString uri = http_request.getRequestURI();

PaginasDAO dao = new PaginasDAO();

if(dao.existePagina(uri){

// La página ya esta registrada en la BD// y solo tenemos que incrementar su contadordao.incrementaContador(uri);

}

Servlets y JSP

164Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 165: Servlets y JSP - Experto Java

Cuando se visite una página por primera vez, para registrarla en la base de datostendremos que obtener la información del título. Creamos un wrapper, y procesamos lapetición utilizando dicho wrapper como objeto respuesta.

else{

// La página se está visitando por primera vez// Debemos obtener su titulo para registrarla en la

BD

// Envolvemos la respuesta con nuestro wrappergenerico

GenericResponseWrapper wrapper =new GenericResponseWrapper(http_response);

// Procesamos la peticiónchain.doFilter(http_request, wrapper);

Una vez hecho esto, tendremos en el wrapper el contenido de la página generado.Podemos obtenerlo y analizarlo, buscando en él la etiqueta <title>.

// En este momento ya diponemos// de la respuesta en el wrapper

// La analizamos para obtener el// valor de su etiqueta <title>

byte [] datos = wrapper.getData();HtmlParser parser = new HtmlParser(datos);String titulo = parser.getTitle();

Una vez obtenido el título, podremos registrar en la base de datos la entrada de la página.

// Ahora podemos registrar ya la página con susdatos

dao.insertaPagina(uri, titulo);

Por último, tendremos que hacer que la respuesta del wrapper pase al cliente, enviándolaal objeto respuesta original.

// Por último, debemos devolver// la respuesta al cliente de forma// que pueda visualizar el recurso solicitadoOutputStream out = response.getOutputStream();out.write(datos);out.close();

}} else {

// Si no es HTTP procesamos la petición de formaordinaria

chain.doFilter(request, response);}

}

}

Servlets y JSP

165Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 166: Servlets y JSP - Experto Java

22. Ejercicios de Filtros y Wrappers

22.1. Filtro de acceso restringido

Vamos a probar la aplicación jsp-sesion11-filtro en la que tenemos un filtroRestringirAcceso que prohibe el acceso de los usuarios no registrados al contenido deldirectorio restringido. Se pide:

a) Desplegar la aplicación en Tomcat. Una vez instalada comprobamos que la aplicaciónse ha instalado correctamente. Tras esto intentamos acceder a uno de los recursos deldirectorio restringido:

http://localhost:8080/jsp-sesion11-filtro/restringido/index.htmlhttp://localhost:8080/jsp-sesion11-filtro/restringido/index.jsp

¿Qué ocurre? ¿Por qué?

b) Validarse como usuario y volver a intentar acceder al directorio restringido. ¿Ahoraque ocurre? ¿Qué ventajas tiene implementar esta restricción de acceso mediante unfiltro?

22.2. Restringir el acceso al chat

Recordemos que en sesiones anteriores realizamos un chat mediante servlets, en el quehabía que registrarse como usuario antes de entrar a hablar. Sin embargo, si se introducedirectamente la dirección:

http://localhost:8080/jsp-sesion05-chat/chat/chatFrames.html

Podemos acceder directamente al chat sin estar registrados. Se pide:

a) Implementar un filtro en el chat que restrinja el acceso al chat si no se ha registrado unnick en la sesión.

b) ¿A qué recursos deberá afectar este filtro? Introducir en el descriptor de despliegue(web.xml) la configuración necesaria para que el filtro intercepte los intentos de acceso alos recursos restringidos.

22.3. Wrapper de ejemplo (*)

La aplicación jsp-sesion11-wrapper incorpora un filtro que utiliza un wrapper paraanalizar la respuesta generada. Toma esta respuesta del wrapper (asumimos que escontenido HTML), y la analiza utilizando la librería htmlparser, para extraer su título.Una vez tiene el título registra que se ha accedido a dicha página en el log y devuelve larespuesta al cliente. Se pide:

Servlets y JSP

166Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 167: Servlets y JSP - Experto Java

a) Desplegar la aplicación en Tomcat. Probar a acceder a varios ficheros HTML estáticosde los incluidos dentro de la aplicación. Comprobar que en el log se ha registrado elacceso indicando el título de las páginas.

b) Si tuviesemos recursos que no fuesen HTML (como por ejemplo imágenes) dentro dela ruta a la que afecta el filtro, ¿que ocurriría?. Intentar acceder a una imagen dentro de laaplicación y ver el error que se produce. ¿A qué se debe esto? ¿Como podríamossolucionarlo?

22.4. Registro de accesos (*)

Vamos a realizar una aplicación que contabilice el número de accesos a las páginasmediante un filtro. Esta aplicación tiene el nombre jsp-sesion11-ranking. Para ellotendremos una base de datos, con una tabla PAGINAS en la que figurará:

ruta varchar(255) Ruta de la página visitada

titulo varchar(100) Título de la página

accesos integer Número de accesos realizados

El servlet RankingPaginasServlet nos genera un listado de las páginas ordenadas pornúmero de visitas.

Lo primero que deberemos hacer será instalar la base de datos. El script para la creaciónde esta base de datos se encuentra en el directorio db.

Se pide:

a) Desarrollar el filtro AccesoPaginaFilter que actue sobre todos los recursos estáticos,y que contabilice el número de visitas que se realiza a ellos almacenando esta informaciónen la base de datos. Deberá cumplir las siguientes características:

• Cuando una página sea visitada por primera vez, se deberá registrar una nueva entradaen la BD, con la URL de la página visitada y el contador de visitas inicializado a 1.Por el momento no obtendremos el título de la página, ya que para esto se requiereutilizar un wrapper, así que en este campo introduciremos siempre el valor (Títulodesconocido).

• Cuando la página ya estuviese registrada en la BD, lo que haremos será incrementar elnúmero de visitas en 1.

b) Actualizar el filtro AccesoPaginaFilter para que obtenga el título de la página a laque se ha accedido, utilizando para ello el wrapper genérico que se proporciona. Deberácumplir las siguientes características:

• Sólo registrará los recursos cuyo contenido sea html (tipo de contenido text/html).• Cuando una página sea visitada por primera vez, se deberá extraer su título de la

etiqueta <title>, para lo cual deberá usarse un wrapper. En este caso insertaremos

Servlets y JSP

167Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 168: Servlets y JSP - Experto Java

los datos de la página en la BD anotando una visita.• Cuando la página ya estuviese registrada en la BD, lo que haremos será incrementar el

número de visitas en 1.

c) Si la página HTML está almacenada en la caché del navegador, el acceso no secontabilizará correctamente. ¿Qué cabecera HTTP podriamos utilizar para solucionar esteproblema? ¿Donde podriamos establecer esta cabecera? Establecer las cabecerasnecesarias para evitar el uso de la caché y comprobar el correcto funcionamiento de laaplicación.

NotaPara asegurarnos de que funciona correctamente con los diferentes navegadores, podemos incluiruna serie de cabeceras destinadas a evitar que la página se almacene en la caché:Cache-control: no-cacheCache-control: no-storePragma: no-cacheExpires: 0

Servlets y JSP

168Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 169: Servlets y JSP - Experto Java

23. Comunicación con clientes ricos y AJAX

23.1. Servlets y clientes ricos

Vamos a ver a continuación cómo establecer una comunicación entre clientes ricos yservlets utilizando el protocolo HTTP. Este protocolo es la interfaz que nos ofrecen losservidores para comunicarnos con los componentes web que contengan, por lo tantopodremos utilizarlo desde un cliente rico Java para comunicarnos con los servlets o JSPalojados en el servidor. Además tiene la ventaja de que al ser un protocolo web estándarnos va a permitir realizar las comunicaciones sin problemas, ya que los firewallsintermedios normalmente dejarán pasar las conexiones de este tipo. Aunque losnavegadores web normalmente utilizan este protocolo simplemente para obtenercontenido HTML, a continuación veremos que podemos utilizarlo para intercambiarcualquier tipo de contenido.

23.1.1. HTTP Tunneling

Si queremos establecer una comunicación entre un cliente rico y un servlet, deberemosestablecer desde el cliente una conexión con la URL en la que está publicado el servlet.La información se intercambiará a través de la conexión HTTP con dicha URL, y esto eslo que se denomina HTTP tunneling. Lo que haremos será construir en el cliente unobjeto URL con la URL del servlet que queramos utilizar, y abrir una conexión con dichaURL para realizar la petición y recibir el resultado generado por el servlet. Al realizar laconexión en conveniente indicar que no utilice la caché, para que siempre se solicite alservidor que genere nuevamente el contenido:

URLConnection con = url.openConnection();con.setUseCaches(false);

Ahora podemos establecer las cabeceras de la petición que queramos. De esta formapodemos proporcionar información sencilla mediante pares (clave, valor):

con.setRequestProperty("header", "valor");

Entonces ya podemos crear la conexión con la URL:

InputStream in = con.getInputStream();

Es en este momento cuando se establece la conexión con el servlet y éste genera elresultado. Mediante el flujo de entrada que obtenemos podremos leer desde nuestro appletel contenido generado. Este flujo de entrada podrá ser de cualquier tipo, según el tipo decontenido generado por el servlet. Podemos leer directamente la secuencia de bytes,transformarlo a un flujo de carácteres, o bien a un flujo de procesamiento más complejo(por ejemplo DataInputStream).

Servlets y JSP

169Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 170: Servlets y JSP - Experto Java

23.1.2. Paso de objetos

También podremos hacer que el servlet nos devuelva objetos. Si el servlet serializa unobjeto y lo escribe en la respuesta (utilizando un ObjectOutputStream), desde el clientepodremos utilizar un ObjectInputStream para leer dicho objeto:

ObjectInputStream ois = new ObjectInputStream(in);MiClase obj = (MiClase)ois.readObject();

Por último, una vez leido todo el contenido, cerraremos el flujo de entrada:

in.close();

Para que el servlet devuelva un objeto deberá especificar como tipo del contenidogenerado el siguiente tipo MIME:

application/x-java-serialized-object

Y lo único que tendrá que hace entonces será obtener un ObjectOutputStream a partirdel flujo de salida de la respuesta, y escribir el objeto en él:

MiClase result = generaObjetoResultante();response.setContentType("application/x-java-serialized-object");ObjectOutputStream oos = newObjectOutputStream(response.getOutputStream());oos.writeObject(result);oos.flush();

Hemos visto que el applet podrá realizar una petición al servlet, y como resultado podrádevolvernos cualquier tipo de datos, pudiendo incluso enviarnos un objeto. Acontinuación veremos que también es posible enviar datos desde el cliente al servidorutilizando esta petición HTTP.

23.1.3. Envío de datos en la petición

Para poder enviar información al servidor podremos utilizar el bloque de contenido delmensajes de petición HTTP. Para ello la conexión que abrimos con la URL debe ser delectura/escritura:

URLConnection con = url.openConnection();con.setUseCaches(false);con.setDoOutput(true);

A continuación crearemos un array de bytes donde escribiremos la información queenviaremos al servidor:

ByteArrayOutputStream baos = new ByteArrayOutputStream();

Podemos usar distintos tipos de flujos sobre este objeto, según vayamos a escribircarácteres (PrintWriter), datos codificados en binario (DataOutputStream) u objetosserializados (ObjectOutputStream), por ejemplo.

Servlets y JSP

170Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 171: Servlets y JSP - Experto Java

Una vez escrito este contenido, deberemos establecer una cabecera con la longitud dedicho contenido:

con.setRequestProperty("Content-Length",String.valueOf(baos.size()));

Por cuestión de compatibilidad entre navegadores, será conveniente establecermanualmente el tipo de contenido:

connection.setRequestProperty("Content-Type","application/x-java-serialized-object");

Tipos MIME que podemos utilizar comunmente para intercambiar información son:

application/x-www-form-urlencoded Se envían los datos codificados de la mismaforma en la que son codificados por unformulario HTML con método POST.

text/plain Se envía como contenido texto ASCII.

application/octet-stream Se envía como contenido datos binarios. Dentrode la secuencia de bytes podremos codificar lainformación como queramos. Por ejemplo,podemos codificar de forma binaria un objetoserializado, utilizando un DataOutputStream.

application/x-java-serialized-object Se envía como contenido un objeto Javaserializado.

En este momento ya podremos enviar los datos al flujo de salida de la conexión:

baos.writeTo(connection.getOutputStream());

Una vez hecho esto ya podemos obtener el flujo de entrada de la conexión, para realizarla petición y obtener contenido que genera el servlet como respuesta, de la misma formaque lo haciamos en el caso anterior.

Nota:Si no abrimos el flujo de entrada (ni intentamos consultar ninguna otra propiedad de las respuestaque genera el servlet), la petición no se llegará a realizar y por lo tanto el servlet no recibirá losdatos que hayamos escrito para ser enviados)

23.2. Servlets y Javascript: AJAX

AJAX (Asynchronous Javascript And Xml) no es una tecnología, sino una técnica dedesarrollo que combina una serie de tecnologías para hacer que un navegador en el ladodel cliente pueda obtener información del servidor sin tener que recargar la página que seesté mostrando. Las tecnologías que se utilizan son:

• HTML y CSS para presentar la información.

Servlets y JSP

171Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 172: Servlets y JSP - Experto Java

• XML para intercambiar información con el servidor.• DOM y Javascript para analizar esta información.

Esta técnica consistirá en hacer una petición HTTP utilizando el objeto XMLHttpRequest

de Javascript. Con esto obtendremos del servidor un documento XML con la informaciónrequerida, que podremos analizar con el DOM (también de Javascript) Una vez tengamoslos datos obtenidos del servidor, podemos actualizarlos en el documento HTMLutilizando nuevamente el DOM.

23.2.1. Petición HTTP desde Javascript

Lo primero que deberemos hacer es obtener el objeto XMLHttpRequest que nos permitahacer una petición HTTP desde Javascript. Deberemos distinguir entre IE y Firefox:

function verMensajes() {//Preparar objeto para lanzar peticionif (window.XMLHttpRequest) { //Firefox,etc

peticion = new XMLHttpRequest();} else if (window.ActiveXObject) { //Explorer

peticion = new ActiveXObject("Microsoft.XMLHTTP");}

Una vez obtenido este objeto, deberemos especificar a qué función se deberá llamarcuando se reciba la respuesta HTTP del servidor. Especificaremos esta función callbackde la siguiente forma:

//a quien llamar cuando el servidor respondapeticion.onreadystatechange = atenderPeticion;

Por último, efectuaremos la petición propiamente dicha, especificando el tipo de petición,la URL a la que vamos a conectar, y si la llamada es asíncrona. Si no fuese asíncrona, elprograma quedaría bloqueado hasta recibir la respuesta. Por lo tanto, deberemos ponereste último parámetro siempre a true para evitar que la web queda bloqueada mientras seobtiene la información:

//lanzar la peticion propiamente dichapeticion.open("GET",

"http://localhost:7001/ChatXml/chat/listaMensajesXml.jsp", true);peticion.send(null);

}

NOTA: Por motivo de seguridad, sólo se permitirá hacer peticiones mediante el objetoXMLHttpRequest al servidor del que se ha descargado esta página.

Una vez se reciba la respuesta, se llamará a la función especificada como callback.Deberemos fijarnos en el estado en el que se encuentra la petición:

0 No inicializada

1 Cargando

2 Cargada

Servlets y JSP

172Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 173: Servlets y JSP - Experto Java

3 Interactiva

4 Completada

El significado de cada uno de estos estados es:

• No inicializada. Se ha creado el objeto de la petición HTTP pero ésta todavía no seha efectuado.

• Cargando. Se ha realizado la petición HTTP y se está esperando a recibir larespuesta.

• Cargada. La respuesta HTTP se ha recibido, pero todavía no se puede acceder almodelo DOM que representa al documento obtenido.

• Interactiva. El modelo DOM se ha empezado a construir pero todavía no estácompleto. Podremos consultar las partes del modelo que ya se hayan construido.

• Completada. El modelo DOM del documento obtenido está completo.

Sólo nos interesará el caso en el que la petición haya sido completada. Además tambiéndeberemos comprobar que la respuesta del servidor no nos haya devuelto un código deerror. Si todo ha ido bien, el estado de la respuesta debería ser 200 OK:

function atenderPeticion() {if (peticion.readyState == 4) {

//analizar respuestaif (peticion.status!=200) {

alert("ha habido un error");return;

}

En este punto tendremos el contenido de la respuesta en las propiedadespeticion.responseText y peticion.responseXML. La primera de ellas nos ofrecerá larespuesta como una cadena de texto, mientras que la segunda es un objeto del tipoXMLDocument al que podremos acceder mediante el DOM.

23.2.2. Lectura de la respuesta

Normalmente utilizaremos responseText cuando queramos incluir directamente en elHTML el contenido devuelto por el servidor, y responseXML cuando estemosintercambiando estructuras de datos.

A continuación se muestra un ejemplo en el que se analiza el documento XML obtenidopara incluir la información formateada en el HTML:

//mostrar mensajesvar areaMensajes = document.getElementById("mensajesChat");

var textoHTML = "";

docXml = peticion.responseXML;var raiz = docXml.getElementsByTagName('mensajes');mensajes = raiz[0].getElementsByTagName('mensaje');for(i=0;i<mensajes.length;i++) {

var nick =

Servlets y JSP

173Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 174: Servlets y JSP - Experto Java

mensajes[i].getElementsByTagName('nick').item(0).firstChild.data;var texto =

mensajes[i].getElementsByTagName('texto').item(0).firstChild.data;textoHTML += "<strong>&lt;" + nick +

"&gt;</strong> " + texto + "<br/>";}

areaMensajes.innerHTML = textoHTML;}

}

En el caso de este ejemplo, para intercambiar la información estaríamos utilizando undocumento XML con el siguiente formato:

<mensajes><mensaje><nick>Ana</nick><texto>Hola</texto>

</mensaje><mensaje><nick>Jose</nick><texto>Que tal?</texto>

</mensaje></mensajes>

Podremos invocar la función que efectua la petición HTTP de diferentes formas.Podemos utilizar un temporizador para hacer que la información se actualiceperiódicamente, o bien podemos hacer que se invoque como respuesta a algún evento delusuario (por ejemplo cuando pulse un botón).

Como alternativa a XML, resulta de especial interés el formato JSON. Se trata de unlenguaje ligero de intercambio de información, que puede utilizarse en lugar de XML(que resulta considerablemente más pesado) para estas aplicaciones AJAX. De hecho, enJavascript puede leerse este tipo de formato simplemente utilizando el método eval().

23.2.3. Aplicaciones de AJAX

Esta técnica tiene numerosas aplicaciones, como por ejemplo:

• Validación de formularios: Podremos validar la información introducida en unformulario en el lado del servidor antes de enviarlo. Por ejemplo, al registrarnos enuna web podemos comprobar si un login ya está utilizado.

• Autocompletar campos: Mientras escribimos en un campo de un formulario, podemosconsultar en el servidor las coincidencias con lo que llevamos escrito para que nosmuestre una lista con las posibilidades existentes.

• Mostrar datos actualizados: Podemos mantener información de última hora en la websin tener que recargar. Por ejemplo, podemos ver el marcador de un partido de fútbolque se está jugando en este momento, la clasificación de la Fórmula 1, o informaciónde la bolsa.

Servlets y JSP

174Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 175: Servlets y JSP - Experto Java

23.2.4. Frameworks AJAX: jMaki

Hemos visto hasta ahora los fundamentos de AJAX y como utilizar esta técnicaprogramando directamente JavaScript a bajo nivel. Sin embargo, esta forma de trabajarpuede resultar compleja, sobretodo si no se cuenta con suficiente experiencia enJavaScript, y puede dar lugar a grandes cantidades de código mal estructurado y difícil deentender, haciendo la aplicación poco mantenible.

Por este motivo, y debido al éxito que AJAX ha cosechado, aparecen multitud de libreríasy frameworks destinados a facilitarnos el uso de esta técnica en nuestras aplicaciones.Tenemos por ejemplo librerías JavaScript como Scriptaculous o DOJO, que nos ofrecenuna serie de componentes de la interfaz de usuario predefinidos, con los que añadircontenido dinámico a nuestras webs (AJAX, animaciones, etc). También podemosencontrar componentes basados en AJAX proporcionados por diferentes proveedores,como Google (mapas, búsqueda) o Yahoo, que podemos introducir en nuestras páginasutilizando las librerías necesarias.

Aquí encontramos el problema de que cada proveedor ofrece su propia API JavaScriptpara utilizar los componentes AJAX que proporciona, lo cual nos forzará a aprender cadauna de estas APIs para poder introducir los correspondientes componentes en nuestraweb. Para evitar este problema aparecen frameworks como jMaki que tratan de definir unmodelo único de acceso a los diferentes tipos de componentes.

Pasaremos a continuación a estudiar jMaki con más detalle. Este framework estásoportado por los principales entornos de desarrollo (Eclipse, NetBeans), y nos permitiráintroducir en nuestras páginas componentes AJAX proporcionados por diferentesproveedores (Google, Yahoo, DOJO, etc) simplemente mediante el uso de tags ennuestros JSPs.

23.2.4.1. Instalación en Eclipse

Vamos a comenzar viendo como instalar en Eclipse el plugin que nos permita trabajar conjMaki.

Lo primero que deberemos hacer es ir al menú Help > Software Updates .... Aquíañadiremos el repositorio en el que se encuentra este plugin:

https://ajax.dev.java.net/eclipse

Una vez hecho esto, desplegaremos el contenido de este repositorio, seleccionaremos elelemento jMaki Ajax, y pulsamos sobre el botón Install ...

Con esto habremos instalado el plugin. Ahora cuando estemos editanto un JSP, abriremosla ventana Snippets y en ella veremos la paleta de componentes (widgets) jMaki quepodemos incorporar en nuestra web, simplemente arrastrándolos sobre el lugar del JSP enel que queramos incluirlo.

Servlets y JSP

175Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 176: Servlets y JSP - Experto Java

23.2.4.2. Componentes de los widgets

A la hora de desarrollar nuestra web simplemente utilizaremos etiquetas jMaki ennuestros JSPs. Cuando esta página se genere, dichas etiquetas se transformarán enelementos HTML y llamadas a librerías JavaScript que puedan ser correctamenteinterpretadas por el navegador. La forma de renderizar estos widgets se define mediante 3ficheros en jMaki. Estos ficheros son:

• component.html: Define una plantilla del código HTML que compondrá el widget enla página.

• component.js: Define una clase JavaScript que hará de adaptador entre la llamada alwidget desde la taglib y la librería concreta que implementa las funcionalidades delwidget que estemos utilizando. Esta capa es la que nos va a permitir tener una interfazde acceso única a widgets proporcionados por diferentes proveedores.

• component.css: Incluye los componentes de estilo necesarios para mostrar el widget.

Cada widget estará definido en un directorio distinto, que contendrá, por lo menos, estostres ficheros. El directorio asociado a cada widget corresponde a su nombre, de formasimilar a lo que ocurre con los paquetes en Java, y todos estos directorios estarán bajo lacarpeta resources. Por ejemplo, si un widget se llama google.map, estará en undirectorio /resources/google/map, dentro de nuestra carpeta web.

23.2.4.3. Tipos de widgets

Dentro de jMaki podemos encontrar diversos tipos de widgets. Podemos encontrardiferentes widgets de un mismo tipo, muchas veces proporcionados por diferentesproveedores. A continuación mostramos una tabla con los modelos generales de widgetsexistentes y una serie de widgets concretos de cada tipo.

Tipo Widgets

Menú Yahoo Menu, jMaki Menu, jMaki Tab Menu, jMaki AccordionMenu

Tabla Yahoo Datatable, Dojo Table

Árbol Yahoo Tree, Dojo Tree

Desplegable Dojo Combobox

Pestañas jMaki Dynamic Container, Dojo Accordion, Dojo Tabbedview,Yahoo Tabbedview, Spry Accordion

Fisheye Dojo Fisheye

Cajón Dojo Drawer

Mapas Yahoo Map, Google Map

Validación Spry validation

Servlets y JSP

176Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 177: Servlets y JSP - Experto Java

Todos los widgets de jMaki utilizan para su configuración una serie de atributos comunes.Estos atributos son:

• id: Identificador de un elemento, que podremos utilizar para referenciarloposteriormente.

• label: Etiqueta que se mostrará en el widget, como por ejemplo el título que figuraráen las pestañas, elementos de menús, nodos de árbol o columnas de una tabla.

• href: Sirve para indicar una URL que haga de enlace, y que al pulsar sobre ella seacceda a la dirección a la que apunta.

• include: Con este atributo especificaremos también una URL, pero en lugar de ponerel enlace lo que se hará será incluir el contenido de dicha URL en el contenedorcorrespondiente.

• action: Nos permite establecer una comunicación entre elementos de diferenteswidgets (por ejemplo podríamos añadir una acción en un botón para que se insertenfilas en una tabla, o hacer que al pulsar sobre un icono se abra una determinadapestaña).

• service: Indica la URL a la que se conectará el widget mediante AJAX para obtenero enviar la información necesaria.

Hemos mostrado los atributos generales, pero cada tipo de widget tiene además su propiomodelo de datos. A continuación pasaremos a ver algunos ejemplos concretos. Paraobtener más información sobre el modelo de datos concreto de cada tipo de widget ysobre como establecer una comunicación entre ellos, podemos consultar ladocumentación en:

https://ajax.dev.java.net/

23.2.4.4. Ejemplo: Múltiples pestañas

Vamos a ver en primer lugar un ejemplo de como crear una página con varias pestañas,cada una de ellas con un contenido diferente. Utilizaremos para ello el widgetTabbedview de Yahoo. Arrastraremos este widget sobre nuestro JSP y modificaremos eltexto generado de la siguiente forma:

<a:widget name="yahoo.tabbedview"value="{items:[

{label : 'A', content : 'Contenido de la pestaña A'},{id : 'tabB', label : 'B', include : 'pagB.jsp ',

lazyLoad : true },{label : 'C', include : 'pagC.jsp', selected : true,

iframe: true}]}" />

Deberemos crear dos nuevos JSPs: pagB.jsp y pagC.jsp, con el contenido que tendránlas pestañas B y C respectivamente. Hemos de hacer notar el uso de los atributos label einclude. Con el primero de ellos indicamos el título de cada pestaña. El segundo nospermite indicar el contenido que tendrá, cogiendo este contenido de otro JSP.

Servlets y JSP

177Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 178: Servlets y JSP - Experto Java

23.2.4.5. Ejemplo: Google Maps

Vamos a ver ahora como podemos incluir mapas dinámicos en nuestra aplicación (GoogleMaps o Yahoo Maps). Para ello arrastraremos el widget Maps de Google sobre nuestroJSP. Veremos un código como el siguiente:

<a:widget name="google.map"args="{ centerLat : 37.4041960114344,

centerLon : -122.008194923401 }" />

Podemos ver que con esto podemos incluir de forma sencilla un mapa que indique unadeterminada dirección, especificando las coordenadas de dicha dirección comoparámetro. Pero también podemos utilizar el mapa junto a otro widget que nos permitaobtener las coordenadas a partir de la dirección del lugar. Para hacer esto arrastraremossobre el JSP el widget Geocoder de Yahoo:

<a:widget name="yahoo.geocoder" service="/xhp" />

En este caso podemos ver que este widget necesita un parámetro service en el que seindica el servicio al que deberá conectar el widget mediante AJAX para obtener lascoordenadas a partir del texto de la dirección. Esta conexión debe hacerse a través de unproxy incluido en jMaki, que deberemos mapear como servlet en nuestra aplicación.

Este servlet está ya implementado en la clase XmlHttpProxyServlet, por lo que enEclipse deberemos indicar que cree un nuevo servlet, pero utilizando una clase yaexistente (esto lo haremos en el mismo asistente de crear nuevo servlet). Mapearemos esteservlet a la dirección que hemos especificado en el widget: /xhp. En el web.xml quedaráde la siguiente forma:

<servlet><description></description><display-name>XmlHttpProxyServlet</display-name><servlet-name>XmlHttpProxyServlet</servlet-name>

<servlet-class>com.sun.jmaki.services.XmlHttpProxyServlet</servlet-class></servlet><servlet-mapping><servlet-name>XmlHttpProxyServlet</servlet-name><url-pattern>/xhp</url-pattern>

</servlet-mapping>

Si ahora probamos la página, veremos que al introducir una dirección en el campo detexto del Geocoder, se nos muestra esta dirección en el mapa.

23.2.4.6. Ejemplo: Autocompletar texto

Para terminar, vamos a ver un ejemplo de como autocompletar texto con AJAX utilizandojMaki. Tendremos un campo de texto, en el que conforme escribamos nos mostrará lasposibles coincidencias con las que podríamos autocompletar. Vamos a utilizar el widgetAutocompleter de Scriptaculous. Arrastramos el widget sobre nuestro JSP y lo

Servlets y JSP

178Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 179: Servlets y JSP - Experto Java

modificamos como se muestra a continuación:

<a:widget name="scriptaculous.autocompleter" service="lista.jsp" />

En este caso, en service especificamos la página de la que sacará las opciones con lasque autocompletar. Estas opciones se definirán como una lista HTML. Por ejemplo,podríamos definir lista.jsp como se muestra a continuación:

<ul><li>Seleccionar <span class="selectme">A</span></li><li>Seleccionar <span class="selectme">B</span></li></ul>

Es posible que esto no nos funcione debido a un bug en algunas versiones de jMaki. Paracorregirlo deberemos abrir el fichero component.js correspondiente a este widget (estaráen el directorio /resources/scriptaculous/autocompleter). En la línea 12 debedeclarar una variable service, pero por error podría aparecer servicei. Si es asídeberemos corregirlo y dejarlo como se muestra a continuación:

var service = wargs.service;

De especial interés es también el fichero component.htm. Aquí se especifica la plantillautilizada para mostrar este componente en el HTML. Podemos ver que tiene un campo detexto, donde introduciremos el contenido a autocompletar. Este widget envía al servicioun parámetro con el texto introducido hasta el momento, para que éste pueda devolvernoslas coincidencias con ese texto. Este parámetro recibe como nombre el nombre que lehayamos dado al campo de texto. Sin embargo, podemos ver que el campo de texto notiene asignado ningún nombre (falta el atributo name), por lo que será buena ideaañadirlo:

<input id="${uuid}" name="texto" type="text"/>

Con esto, nuestra página lista.jsp recibirá un parámetro texto con el texto introducidohasta el momento. Entonces tendrá que buscar las coincidencias con ese texto (porejemplo elementos en nuestra base de datos que comiencen de esa manera), y devolverlasformateadas como una lista HTML.

Servlets y JSP

179Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 180: Servlets y JSP - Experto Java

24. Ejercicios de Comunicación

24.1. Chat con XML y AJAX (*)

Vamos a añadir a la aplicación de chat realizada en anteriores sesiones la posibilidad deobtener la lista de mensajes publicados en XML. Esto nos permitirá acceder al chatmediante una interfaz web utilizando AJAX, o utilizar un cliente rico. Se pide:

a) Crear un JSP llamado listaMensajesXml.jsp que formatee la lista de mensajespublicados en el chat en XML. Debe utilizar un formato como el siguiente:

<mensajes><mensaje><nick>Ana</nick><texto>Hola</texto>

</mensaje><mensaje><nick>Jose</nick><texto>Que tal?</texto>

</mensaje></mensajes>

ImportanteSe deberá hacer que el tipo MIME de este documento sea text/xml, ya que de lo contrario elcliente no lo reconocerá como tal y no podremos analizarlo.

Actualizar el servlet ListaMensajesServlet para que tome como entrada un parámetroformato. Los posibles valores para el formato serán:

• 0: Formato Web (HTML)• 1: Formato XML (para utilizar AJAX)• 2: Formato serializado (para comunicación con cliente ricos Java)

Si no se especifica este parámetro, por defecto el servlet servirá la versión web del chat.

Al especificar el formato 1 (XML), se deberá redirigir la salida al JSP que acabamos decrear, proporcionando la lista de mensajes como un atributo de la petición. Publicar unaserie de mensajes mediante la interfaz web ya existente. Consultar la lista de mensajes enXML accediendo a la siguiente dirección:

http://localhost:8080/jsp-sesion05-chat/servlet/ListaMensajesServlet?formato=1

b) En el directorio jsp-sesion12-ajax de las plantillas de la sesión se proporciona elfichero chatAjax.html que contiene la página web de la versión AJAX del chat, queobtiene los mensajes del servidor en el formato visto en el punto anterior. Observar elcódigo fuente de esta página. En él encontraremos el código que hace la petición HTTP alservidor y analiza la respuesta recibida. Copiar este fichero al directorio chat de nuestra

Servlets y JSP

180Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 181: Servlets y JSP - Experto Java

aplicación de chat, probar a acceder ella mediante esta interfaz y comprobar que el chatfunciona correctamente.

NotaSe recomienda probar la aplicación en un navegador real, ya que el que está integrado en Eclipsepodría no funcionar correctamente con determinadas funciones de Javascript.

24.2. Applet para el chat (*)

Vamos a utilizar un cliente rico para acceder la aplicación de chat. Esta aplicación clienteya está desarrollada en el proyecto jsp-sesion12-cliente. Se pide:

a) La aplicación invoca cada 5 segundos al servlet ListaMensajesServlet . Esperarecibir como respuesta un objeto ColaMensajes, del cual mostrará todos los mensajes enel área de texto de la aplicación. Implementar en el servlet ListaMensajesServlet laopción de devolver serializado el objeto ColaMensajes al cliente.

b) Probar el cliente rico para acceder al chat. Comprobar que se puede accedercorrectamente desde las diferentes interfaces que hemos creado.

24.3. Autocompletar con jMaki (*)

Vamos a crear una aplicación que nos permita consultar determinados atributos delámbito del contexto. Tendremos un campo de texto en el que tendremos que introducir elnombre del atributo, y que debe permitirnos autocompletar el texto introducido con todaslas coincidencias encontradas. Utilizar el widget Autocompleter de Scriptaculous paraimplementar dicho campo de texto.

Servlets y JSP

181Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 182: Servlets y JSP - Experto Java

25. Roadmap

25.1. Puntos destacados

• Concepto de servlet• Estructura básica del paquete javax.servlet. Clases más comunes.• Ciclo de vida de un servlet• Estructura básica de un servlet (elemenos básicos que deberá tener la clase)• Llamada a los servlets de las 3 formas posibles: con su nombre de clase, con su

nombre mapeado, o con una URL alternativa. Modificación del web.xml para permitirestas tres llamadas.

• Otras opciones en el web.xml: cargar servlets al inicio, definir parámetros de inicio enlos servlets, deshabilitar el alias /servlet/

• Uso de logging en servlets con commons-logging y log4j

• El objeto HttpServletRequest y sus métodos principales: toma de parámetros depetición, flujos de entrada...

• El objeto HttpServletResponse y sus métodos principales: flujo de salida, cabecerasde respuesta...

• Definir pruebas con Cactus en los servlets• Acceder a las cabeceras de petición y enviar cabeceras de respuesta• Acceder a variables CGI• Enviar códigos de estado, tanto solos como asociados a ciertas cabeceras• Gestión de cookies: enviar y obtener cookies desde servlets• Obtener una sesión (nueva o existente), e invalidarla• Guardar y obtener datos de la sesión• Reescritura de URLs para preservar la información de sesión si no se permiten

cookies• Acceso al objeto ServletContext

• Compartir información en el ámbito de la aplicación (atributos del contexto)• Redirecciones mediante el objeto RequestDispatcher: include y forward

• Listeners del contexto• Relación entre JSP y Servlets• Estructura básica de un JSP• Elementos de los JSP: directivas, acciones y código• Inserción de código en los JSP mediante expresiones, scriptlets y declaraciones• Objetos implícitos de los JSP• Comunicación entre servlets y JSP• Concepto de JavaBean• Uso de beans desde páginas JSP• Ambito de los beans. Compartir beans entre diferentes páginas• El lenguaje de expresiones en JSP 2.0: expresiones, atributos, elementos del lenguaje,

palabras reservadas, operadores, nombres de variables

Servlets y JSP

182Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 183: Servlets y JSP - Experto Java

• Qué es una librería de tags• Elementos que componen una librería de tags: el descriptor TLD y las librerías JAR• La librería request: acceso a parámetros de la petición, cabeceras, cookies, etc• La librería dbtags: creación de conexiones, ejecución de consultas y actualizaciones,

recorrido de resultados• Comunicación entre taglibs y scripts JSP. El contexto• Qué es JSTL. Qué librerías la componen• Uso de la librería Core: definición de variables, condicionales, iteradores...• Uso de la librería SQL: definicion de DataSources, consultas, actualizaciones,

iteración de resultados. Transacciones• La librería FMT: formatos de fechas y números• Otras librerías: XML y la librería de funciones• Diferentes tipos de tags: tags simples (sin atributos ni cuerpo), tags con atributos, tags

con cuerpo (iterable y no iterable), tags anidados• Creación de cada uno de estos tipos de tags. Agrupación de tags en una librería.

Definición del fichero TLD• Concepto y motivación de los filtros• Aplicaciones de los filtros• Configuración de los filtros. Cadenas de filtros• Implementación de filtros• Concepto y motivación de los wrappers• Implementación de wrappers• Utilización de wrappers• Comunicación entre servlets y clientes ricos• Intercambio de datos y objetos Java entre cliente y servidor mediante protocolo HTTP• Comunicación asíncrona entre Javascript y la aplicación web: AJAX

25.2. Certificación Sun

Los conceptos vistos en este módulo cubren parte de los objetivos del certificadoSCWCD (Sun Certified Web Component Developer - Certificado Sun de Desarrollador deComponentes Web):

• Sección 1: El Modelo de la Tecnología de los Servlets• Sección 2: La Estructura y Despliegue de las Aplicaciones Web (Se estudia en el

módulo de Servidores Web)• Sección 3: El Modelo del Contenedor Web• Sección 4: Manejo de Sesiones• Sección 5: Seguridad en las Aplicaciones Web (Se estudia parcialmente en Servidores

Web)• Sección 6: El Modelo de la Tecnología de las JavaServer Pages (JSP)• Sección 7: Construir páginas JSP utilizando el Lenguaje de Expresiones (EL)• Sección 8: Construir páginas JSP utilizando Acciones Estándar• Sección 9: Construir páginas JSP utilizando Librarías de Tags

Servlets y JSP

183Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 184: Servlets y JSP - Experto Java

• Sección 10: Construir una Librería de Tags propia• Sección 11: Patrones J2EE (Se estudia en los módulos Patrones de Diseño y Struts y

JSF)

Este certificado tiene como prerequisito el haber obtenido previamente el Certificado Sunde Programador Java (SCJP). El examen consiste en 69 preguntas de tipo test, de lascuales hay que acertar al menos 44 (un 62%) para obtener el aprobado, en un tiempolímite de 135 minutos.

Más información sobre esta certificación enhttp://www.sun.com/training/catalog/courses/CX-310-081.xml.

25.3. Recursos adicionales

25.3.1. Bibliografía

• Core Servlets and JavaServer Pages, Marty Hall, Prentice Hall• More Servlets and JavaServer Pages, Marty Hall, Prentice Hall• Java Servlet & JSP Cookbook, Bruce W. Perry, O'Reilly• Java Servlet Programming, Jason Hunter, O'Reilly

25.3.2. Enlaces

• Web oficial de servlets, http://java.sun.com/products/servlet/index.jsp• Web oficial de JSP, http://java.sun.com/products/jsp/• Web de taglibs de Jakarta, http://jakarta.apache.org/taglibs/index.html• Web de JSTL, http://jakarta.apache.org/taglibs/doc/standard-doc/intro.html

Servlets y JSP

184Copyright © 2008-09 Depto. CCIA All rights reserved.

Page 185: Servlets y JSP - Experto Java

Servlets y JSP

185Copyright © 2008-09 Depto. CCIA All rights reserved.