Download Programación web en Java

Document related concepts
no text concepts found
Transcript
Programación web en Java
AULA
MENTOR
educacion.es
Nipo: 030-12-335-9
Autores:
José Miguel Ordax Cassá
Pilar Aranzazu Ocaña Díaz-Ufano
Ilustración de portada:
María Guija Medina
Unidad de Aprendizaje 1
INTRODUCCIÓN A JAVA EE
ÍNDICE
1.1 Introducción ..........................................................................3 1.1.1 Java Card .......................................................................... 3 1.1.2 Java Micro Edition (Java ME) ......................................... 4 1.1.3 Java Standard Edition (Java SE).................................... 4 1.1.4 Java Enterprise Edition (Java EE) .................................. 4 1.2 El modelo de aplicación Java EE........................................5 1.2.1 Componentes Java EE .................................................... 6 1.2.2 Contenedores Java EE .................................................... 7 1.2.3 Servicios Java EE ............................................................. 8 1.3 El diseño de aplicaciones Java EE .....................................8 1.4 Las especificaciones Java EE...........................................10 1.5 El ensamblado y despliegue de aplicaciones Java EE ..13 1.6 El Servidor de Aplicaciones Java EE................................15 PARA RECORDAR ....................................................................18 MÓDULO A – Unidad 1: Introducción a Java EE
1.1
Introducción
Debido a la naturaleza del lenguaje Java: portable, seguro, multithread, etc…, está siendo
utilizado en multitud de ámbitos y tecnologías, desde el chip de una tarjeta de crédito hasta un
servidor de la más alta gama.
Evidentemente,
estos
distintos
ámbitos
o
entornos,
tienen
unas
características
y
peculiaridades muy distintas entre sí. Por ejemplo, la cantidad de memoria disponible en el
chip de una tarjeta de crédito y la de un servidor es muy distinta, por lo que habrá que tenerlo
en cuenta a la hora de desarrollar las aplicaciones.
Es por ello que existen distintas plataformas Java, dependiendo del ámbito en el que se vaya a
trabajar.
Son las siguientes:

Java Card.

Java Micro Edition (Java ME).

Java Standard Edition (Java SE).

Java Enterprise Edition (Java EE).
Podemos verlas resumidas en el siguiente gráfico:
1.1.1 Java Card
La plataforma Java Card define las APIs y requerimientos necesarios para poder ejecutar
aplicaciones Java en los chips de las tarjetas. Debido a las mínimas prestaciones del entorno
de ejecución contiene el API más escueto.
El estudio de esta plataforma no es el objetivo de este curso, pero si el alumno quiere
profundizar en este tema podrá encontrar más información en la siguiente URL:
http://www.oracle.com/technetwork/java/javame/javacard/overview/getstarted/index.html
3
1.1.2 Java Micro Edition (Java ME)
La plataforma Java Micro Edition define las APIs y requerimientos necesarios para poder
ejecutar aplicaciones Java en dispositivos embebidos. Debido a la gran diversidad de estos
dispositivos, desde teléfonos móviles o buscas con pocas prestaciones hasta televisores o
automóviles mucho más potentes, se definieron distintas configuraciones con más o menos
APIs y por tanto, posibilidades.
Por defecto existen estos dos:
 CLDC (Connected Limited Device Configuration): Define las APIs y la JVM
(denominada KVM) para dispositivos con muy pocas prestaciones.
 CDC (Connected Device Configuration): Define las APIs para dispositivos con pocas
prestaciones pero conectados a la red. No requiere una JVM especial.
El estudio de esta plataforma no es el objetivo de este curso, pero si el alumno quiere
profundizar en este tema podrá encontrar más información en la siguiente URL:
http://www.oracle.com/technetwork/java/javame/index.html
1.1.3 Java Standard Edition (Java SE)
La plataforma Java Standard Edition (Java SE) define las APIs y requerimientos necesarios
para poder ejecutar aplicaciones Java de escritorio en ordenadores personales o portátiles.
El estudio de esta plataforma no es el objetivo de este curso, pero si el alumno quiere
profundizar en este tema, Aula Mentor cuenta con otros dos cursos que la cubren:
 Programación en Java – Inicial
 Programación en Java – Avanzado
Puedes consultar la información de estos cursos en www.aulamentor.es, en el apartado
“Cursos” – “Programación”.
1.1.4 Java Enterprise Edition (Java EE)
La plataforma Java Enterprise Edition (Java EE) define las APIs y requerimientos necesarios
para poder ejecutar aplicaciones Java servidoras, con todo lo que ello supone: clienteservidor, multiusuario, transaccionalidad, escalabilidad, etc…en definitiva, características que
no eran importantes o imprescindibles en aplicaciones de escritorio.
Se apoya en la plataforma Java SE, por lo que es imprescindible conocer y dominar dicha
plataforma antes de aventurarse en esta otra. Utiliza la misma Máquina Virtual Java (JVM).
Este curso se centra precisamente en esta plataforma, aunque no en su totalidad. Como
veremos un poco más adelante, las aplicaciones Java EE pueden dividirse en varias capas y
este curso se centra la denominada capa web o de presentación.
La plataforma Java Enterprise Edition ha pasado por distintas nomenclaturas y versiones a lo
largo de su vida, de manera que hubo momentos en el tiempo en el que se denominó Java 2
y luego simplemente Java. Las versiones también han sufrido modificaciones, comenzando a
numerarse como 1.2, 1.3… para a posteriori pasar a numerarse como 5.0, 6.0…
Actualmente estamos en la versión 6.0, pero en su totalidad han existido:
 Java 2 EE 1.2
4
MÓDULO A – Unidad 1: Introducción a Java EE
 Java 2 EE 1.3
 Java 2 EE 1.4
 Java EE 5.0
 Java EE 6.0
La definición de esta y las otras plataformas se realiza mediante un proceso colaborativo
entre distintas empresas denominado Java Community Process (JCP). Para cada plataforma,
API, funcionalidad… se crea lo que se denomina como Java Specification Request (JSR)
donde se sientan las bases y especificaciones de dicha plataforma, API o funcionalidad.
En concreto la discusión y definición de la futura plataforma Java EE 7.0 se puede seguir en
la siguiente URL: http://www.jcp.org/en/jsr/detail?id=342
1.2
El modelo de aplicación Java EE
El modelo de aplicaciones Java EE define una arquitectura para implementar servicios como
aplicaciones multicapa que aseguren la escalabilidad, accesibilidad y facilidad de gestión
necesarias en un ámbito empresarial.
El modelo divide el trabajo a realizar en la implementación en dos partes:

La lógica de presentación y de negocio a implementar por el desarrollador.

Los servicios estándar que ofrece la plataforma Java EE.
El desarrollador puede apoyarse en los servicios ofrecidos por la plataforma Java EE en vez de
reinventar la rueda una y otra vez, facilitándole así el concentrarse únicamente en la lógica
específica de su aplicación.
La plataforma Java EE utiliza un modelo de programación distribuido en distintas capas. La
lógica de la aplicación se divide en distintos componentes dependiendo de su funcionalidad, y
estos son desplegados en las distintas capas dependiendo de a cuál pertenecen.
Las distintas capas son:

Capa cliente (Client Tier): responsable de la interacción con el usuario.

Capa web (Web Tier): responsable del control de la aplicación y en ocasiones también
de la interacción con el usuario.

Capa de negocio (Business Tier): responsable de la lógica de la aplicación
propiamente dicha.

Capa de datos (EIS Tier): responsable de la persistencia de datos y/o lógica
especializada (conocida con el nombre de EIS: Enterprise Information System, o
Sistema
de
Información
Empresarial).
Por
ejemplo
ERPs,
BBDD,
Motores
Transaccionales (CICS, IMS, Tuxedo…).
A continuación mostramos este concepto de multicapa en un diagrama:
5
Es muy importante tener en cuenta, que esta división es puramente lógica y no física. Es decir,
físicamente cada capa no tendrá por qué estar en máquinas independientes, sino que podrán
compartir hardware. Por ejemplo, veremos que lo normal será que el entorno de desarrollo que
montaremos para resolver las distintas actividades de este curso tendrá todas las capas
físicamente en la misma máquina.
Adicionalmente al tema multicapa, el modelo de aplicación Java EE define otros tres
conceptos claves para entender la plataforma:

Componentes: Unidades de software que forman o componen la aplicación.

Contenedores: Entorno de ejecución donde se ejecutan los componentes.

Servicios: Funcionalidades estándar que todo contenedor debe proveer a los
componentes.
Veamos qué son y en qué consisten cada uno de estos conceptos.
1.2.1 Componentes Java EE
Una aplicación Java EE está compuesta de componentes. Un componente Java EE es una
unidad de software funcional auto contenida que se ensambla como parte de una aplicación
Java EE y que puede interactuar con otros componentes.
Las especificaciones Java EE definen lo siguientes tipos de componentes:

Componentes cliente: son aplicaciones Java SE (AWT/Swing, Applets) o un navegador
web (Firefox, Chrome, IExplorer…). Se despliegan en la capa cliente.
6
MÓDULO A – Unidad 1: Introducción a Java EE

Componentes web: son Java Servlets, JavaServer Pages (JSP) o JavaServer Faces
(JSF). Se despliegan en la capa web.

Componentes de negocio: Enterprise JavaBeans (EJB). Se despliegan en la capa de
negocio.
1.2.2 Contenedores Java EE
Normalmente el desarrollo de una aplicación empresarial es muy complicado dado que el
desarrollador tiene que tener en cuenta temas muy importantes como la gestión multiusuario,
la gestión de la transaccionalidad, la gestión de la seguridad, la compartición de recursos,
etc…
El modelo de programación de la plataforma Java EE facilita enormemente esta tarea con la
definición de los contenedores Java EE. Estos contenedores ofrecen al desarrollador una
serie de servicios sobre los que se puede apoyar permitiéndole centrarse en el desarrollo de
la lógica de negocio de la aplicación propiamente dicha.
Dependiendo del tipo de contenedor, ofrecerá unos servicios u otros, y permitirá desplegar
en él un tipo de componente u otro. Los tipos de contenedores Java EE son:
 Contenedor cliente (Application Client Container o Applet Container).
 Contenedor web (Web Container).
 Contenedor de negocio o de EJBs (EJB Container).
Como podemos ver, cada tipo de contenedor corresponde con una de las capas definidas, a
excepción de la capa de datos que está implementada por otro tipo de productos (ya
mencionados anteriormente) ajenos a la plataforma Java EE.
En el siguiente diagrama, podemos observar la relación entre los distintos tipos de
contenedores Java EE:
7
1.2.3 Servicios Java EE
Las especificaciones Java EE, definen una serie de funcionalidades que los distintos tipos de
contenedores deberán implementar y ofrecer a los desarrolladores de aplicaciones Java EE.
Existen multitud de servicios, pero simplemente destacaremos algunos:
 De directorio: para la indexación y búsqueda de componentes y recursos.
 De despliegue: para facilitar la descripción y personalización de componentes a la hora
de su instalación.
 De transaccionalidad: para poder ejecutar distintas acciones en una misma unidad
transaccional.
 De seguridad: para poder autenticar y autorizar a los usuarios de una aplicación.
 De acceso a datos: para facilitar el acceso a las Bases de Datos.
 De conectividad: para facilitar el acceso a los distintos Sistemas de Información
Empresarial (EIS).
 De mensajería: para poder comunicarse con otros componentes, aplicaciones o EISs.
1.3
El diseño de aplicaciones Java EE
Todos los informáticos saben, que antes de ponerse a programar hay una fase muy importante
de análisis y de diseño donde se estudia y define la solución. Para ello, contamos con el
lenguaje UML (Unified Modeling Language) que define una serie de diagramas y notaciones
para poder plasmar estos análisis y diseños.
Nota: El lenguaje UML no es objeto de este curso pero se cubre con cierta profundidad en el
curso de Aula Mentor: Programación en Java – Inicial.
Adicionalmente, existe el concepto de Patrones de Diseño, que son un conjunto de soluciones
(o diseños) a los problemas más comunes en la programación de aplicaciones, que han
demostrado ser útiles y eficientes en la resolución de dichos problemas. Su existencia, permite
poder reutilizar y aplicar soluciones existentes, y no estar reinventando la rueda
constantemente.
Pues bien, existe un conjunto importante de estos patrones de diseño muy relacionados con el
desarrollo de aplicaciones Java EE. A lo largo del curso iremos viendo algunos, pero si el
alumno quiere profundizar en este tema tiene el catálogo completo en las Blue Prints de Java
EE:
http://www.oracle.com/technetwork/java/catalog-137601.html
8
MÓDULO A – Unidad 1: Introducción a Java EE
En este capítulo de introducción a Java EE, vamos a hablar de uno que ataca directamente
las problemáticas derivadas del modelo de una aplicación Java EE multicapa. Es conocido con
el nombre de: Modelo-Vista-Controlador (MVC).
Las aplicaciones que manejan acceso a datos, gestionan distintas presentaciones y tienen
lógica de negocio compleja, suelen sufrir un problema serio a la hora de mantenerlas debido a
interdependencias entre todos los componentes. Dichas interdependencias también dificultan
la reutilización de código, obligando a rescribir más veces de las deseadas una lógica muy
parecida.
El patrón de diseño MVC resuelve estos problemas desacoplando el acceso a datos de la
lógica de negocio y esta de la presentación. De esta forma, se podrá reutilizar un acceso
desde distintas funcionalidades, o reutilizar la misma funcionalidad desde distintos tipos de
presentación, etc… facilitando también el mantenimiento posterior:

El Modelo (Model): Representa los datos y cualquier lógica de negocio relacionada con
ellos.

La Vista (View): renderiza el contenido de los modelos dependiendo de la tipología de
cliente (navegador web, teléfono móvil, etc…), permitiendo su visualización.

El Controlador (Controller): define el comportamiento general de la aplicación
coordinando a las otras dos partes (Modelo y Vista).
Veamos el patrón de diseño en un diagrama:
9
Pues bien, los distintos tipos de componentes que hemos introducido en el apartado del
modelo de aplicación Java EE, encajan perfectamente en este diseño:
 Modelo: Enterprise JavaBeans, POJOs (Plain Old Java Objects).
 Vista: JavaServer Pages (JSP), JavaServer Faces (JSF).
 Controlador: Java Servlets.
Un ejemplo del flujo de una aplicación Java EE sería algo así:
1. El cliente, por ejemplo un navegador, solicitará una funcionalidad desde el interface
visual (Vista).
2. Dicha petición entrará a través de un Java Servlet (Controlador).
3. Dicho Java Servlet, analizará qué se está pidiendo, qué información adicional aporta y
decidirá que Enterprise JavaBean o POJO (Modelo) cubre dicha petición.
4. Lo invocará, y tras recibir un resultado, decidirá qué JavaServer Page (JSP) muestra
dicho resultado al cliente (Vista).
5. El resultado será devuelto y mostrado.
Y visualmente:
Evidentemente, las aplicaciones se pueden desarrollar sin tener en cuenta estos patrones de
diseño, pero está demostrado sobradamente en el mercado, el aumento de productividad y
mejora del mantenimiento con su uso.
A lo largo del curso iremos insistiendo en este punto y detallando y practicando tanto este
patrón como otros.
1.4
Las especificaciones Java EE
Las especificaciones Java EE son el conjunto de las definiciones detalladas de los conceptos
que forman parte de la plataforma Java EE: componentes, contenedores y servicios.
10
MÓDULO A – Unidad 1: Introducción a Java EE
No entraremos en el detalle de cada una. A lo largo del curso, iremos desgranando aquellas
especificaciones relacionadas con la programación web.
En concreto, las especificaciones Java EE 6.0 (última versión en el momento de la redacción
de este manual) están compuestas por las siguientes definiciones (en negrita las que
cubriremos en el curso):

Java API for RESTful Web Services (JAX-RS) 1.1

Implementing Enterprise Web Services 1.3

Java API for XML-Based Web Services (JAX-WS) 2.2

Java Architecture for XML Binding (JAXB) 2.2

Web Services Metadata for the Java Platform

Java API for XML-Based RPC (JAX-RPC) 1.1

Java APIs for XML Messaging 1.3

Java API for XML Registries (JAXR) 1.0

Java Servlet 3.0

JavaServer Faces 2.0

JavaServer Pages 2.2/Expression Language 2.2

Standard Tag Library for JavaServer Pages (JSTL) 1.2

Debugging Support for Other Languages 1.0

Contexts and Dependency Injection for Java (Web Beans 1.0)

Dependency Injection for Java 1.0

Bean Validation 1.0

Enterprise JavaBeans 3.1 (incluye Interceptors 1.1)

Java EE Connector Architecture 1.6

Java Persistence 2.0

Common Annotations for the Java Platform 1.1

Java Message Service API 1.1

Java Transaction API (JTA) 1.1

JavaMail 1.4

Java Authentication Service Provider Interface for Java Authorization Contract for
Containers 1.3

Java EE Application Deployment 1.2
11

J2EE Management 1.1
Dado que la plataforma Java EE extiende la Java SE, existen especificaciones Java SE
incluidas en Java EE:

Java API for XML Processing (JAXP) 1.3

Java Database Connectivity 4.0

Java Management Extensions (JMX) 2.0

JavaBeans Activation Framework (JAF) 1.1

Streaming API for XML (StAX) 1.0

Java Naming and Directory Interface (JNDI) 1.2
Como ya hemos comentado, la plataforma Java EE es un tema muy extenso que toca gran
cantidad de ámbitos y tecnologías. Nosotros en este curso titulado “Programación Web” nos
centraremos exclusivamente en aquellas especificaciones relacionadas con la presentación y
el acceso a Bases de Datos.
Existe documentación on-line de todas estas especificaciones o APIs que serán de enorme
utilidad a la hora de desarrollar aplicaciones Java EE:
http://download.oracle.com/javaee/6/api/
12
MÓDULO A – Unidad 1: Introducción a Java EE
1.5
El ensamblado y despliegue de aplicaciones Java EE
Una aplicación Java EE está formada por un empaquetamiento de una o varias unidades
conocidas con el nombre de módulos. Estos módulos contienen a su vez:
 Uno o varios componentes (Java Servlets, Enterprise JavaBeans (EJB)…).
 Un descriptor de despliegue que describe el contenido y características del módulo
(desde la versión 5.0 estos descriptores son opcionales, ya que el propio código
puede ser auto descriptivo mediante el uso de anotaciones).
Existen distintos tipos de módulos dependiendo de su contenido y el contenedor donde se
vaya a ejecutar. Los distintos módulos van empaquetados en un fichero JAR (Java ARchive).
No obstante, la extensión de dicho fichero dependerá del tipo de módulo:
 Módulo Web (Web Module): contiene normalmente Java Servlets, JavaServer Pages
(JSP), JavaServer Faces (JSF), contenidos estáticos como imágenes, HTMLs, CSSs…
La extensión del fichero empaquetado será WAR (Web ARchive).
 Modulo de EJBs (EJB Module): como su nombre indica, contiene Enterprise
JavaBeans (EJB). La extensión del fichero empaquetado es la de por defecto, JAR
(Java ARchive).
 Modulo cliente (Application Client Module): contiene el código de la aplicación cliente.
La extensión del fichero empaquetado es la de por defecto, JAR (Java ARchive).
 Modulo
Adaptador
(Resource
Adapter
Module):
contiene un conector para
comunicarse con un Sistema de Información Empresarial (EIS). La extensión del
fichero empaquetado será RAR (Resource ARchive).
La aplicación Java EE a su vez, también es un empaquetado de los distintos módulos que la
forman. La extensión del fichero empaquetado será EAR (Enterprise ARchive).
Una aplicación Java EE no tiene por qué contener módulos de todos los tipos, lo que si es
necesario, es que tenga como mínimo uno independientemente del tipo.
Gráficamente, la estructura de una aplicación Java EE empaquetada sería la siguiente,
partiendo desde la raíz del EAR (Assembly Root):
13
El descriptor de despliegue de una aplicación Java EE es un fichero XML llamado
application.xml que reside en un directorio denominado META-INF.
Como ya hemos mencionado, desde la versión 5.0 de las especificaciones Java EE, este
descriptor de despliegue es opcional si se han usado anotaciones en el código. No obstante,
no está mal seguir utilizándolos para que los administradores de los sistemas de una manera
legible y sencilla puedan entender el contenido y las características de la aplicación.
Un ejemplo de descriptor de despliegue sería:
<?xml version="1.0" encoding="UTF‐8"?> <application xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd
" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="PruebaEAR" version="6"> <module> <connector>PruebaConnector.rar</connector> </module> <module> <java>PruebaClient.jar</java> </module> <module> <ejb>PruebaEJB.jar</ejb> </module> <module> <web> <web‐uri>PruebaWeb.war</web‐uri> <context‐root>PruebaWeb</context‐root> </web> </module> </application> Se trata de una aplicación Java EE que contiene un módulo de cada tipo. No hay que
preocuparse si no se entiende el contenido del fichero como tal, ya que de momento,
simplemente se trata de ver un ejemplo del concepto de descriptor de despliegue.
14
MÓDULO A – Unidad 1: Introducción a Java EE
Debido a que este curso es sobre programación web, nos centraremos únicamente en los
módulos web, aunque no está de más conocer la existencia de otro tipo de módulos.
1.6
El Servidor de Aplicaciones Java EE
Hasta aquí, todo han sido especificaciones, definiciones… pero para poder ejecutar una
aplicación Java EE necesitamos un entorno de ejecución. Dicho entorno de ejecución se
conoce con el nombre de Servidor de Aplicaciones.
Un Servidor de Aplicaciones por tanto, es un producto de software que implementa todas las
especificaciones Java EE. De manera que al desplegar o instalar una aplicación Java EE en el
servidor, sabemos seguro que va a encontrarse con todos los contenedores y servicios
definidos por la especificación y que seguramente utiliza y necesita la aplicación.
Existe una batería de pruebas estándar que todo proveedor de Servidores de Aplicaciones
debe pasar satisfactoriamente para poder decir que es Java EE. Es lo que se conoce con el
nombre de JCK (java Compatibility Kit o Kit de Compatibilidad Java).
Gracias a la existencia del estándar Java EE, podemos tener la tranquilidad de que nuestra
aplicación debe funcionar perfectamente en el Servidor de Aplicaciones de cualquier
proveedor, asegurándonos así que no debemos de trabajar con ninguno en concreto.
Existen multitud de Servidores de Aplicaciones en el mercado. Podríamos categorizarlos de la
siguiente forma:
 Gratuitos o de pago.
 Certificados Java EE o no.
A continuación comentamos algunos. No están todos los que son, ni son todos los que están,
pero si los más usados y conocidos:
 Apache Tomcat: Es gratuito de código abierto. No cumple con el 100% de las
especificaciones Java EE por lo que no se puede decir que sea un Servidor de
Aplicaciones Java EE. Pero si que cubre algunas de las especificaciones relacionadas
con la programación web que estudiamos en este curso: Java Servlet 3.0, JavaServer
Pages 2.2, Java Database Connectivity 4.0 y Java Naming and Directory Interface 1.2
Este es el Servidor de Aplicaciones que usaremos en este curso. En los Materiales de
Apoyo de la Mesa del Alumno, encontraréis las instrucciones de descarga, instalación
y configuración del servidor.
URL: http://tomcat.apache.org
15
 Jetty: Es gratuito y de código abierto. Al igual que pasara con Apache Tomcat,
tampoco implementa el 100% de las especificaciones Java EE. Una vez más, se
centra exclusivamente en algunas especificaciones web.
URL: http://jetty.codehaus.org/jetty/
 WebSphere Application Server: Es de pago de la empresa IBM. Se trata de un Servidor
de Aplicaciones Java EE completo.
URL: http://www-01.ibm.com/software/webservers/appserv/was/

Apache Gerónimo: Es gratuito y de código abierto. Se trata de un Servidor de
Aplicaciones Java EE completo.
URL: http://geronimo.apache.org

Oracle Weblogic Server: Es de pago de la empresa Oracle. Se trata de un Servidor de
Aplicaciones Java EE completo.
16
MÓDULO A – Unidad 1: Introducción a Java EE
URL: http://www.oracle.com/us/products/middleware/application-server/

GlassFish: Es gratuito y de código abierto. Se trata de un Servidor de Aplicaciones
Java EE completo.
URL: http://glassfish.java.net/

JBoss: Es gratuito y de código abierto. Se trata de un Servidor de Aplicaciones Java
EE completo.
URL: http://www.jboss.org/jbossas
17
PARA RECORDAR
 En esta unidad hemos visto la diferencia entre las distintas versiones de Java: Java
Card, Java Micro Edition, Java Standar Edition y Java Enterprise Edition (Java
EE).
 Las aplicaciones Java EE, están distribuidas en distintas capas para una mejor
organización funcional: capa cliente (para interactuar con el usuario), capa web
(para llevar el control de la aplicación y a veces interactuar con el usuario), capa de
negocio (contiene la lógica del negocio como tal) y la capa de datos (contiene la
información de negocio).
 A su vez la plataforma Java EE, para poder ejecutar las aplicaciones Java EE
multicapa, está formada por:
 Componentes: Unidades de software que forman o componen la aplicación
 Contenedores: Entorno de ejecución donde se ejecutan los componentes.
 Servicios: Funcionalidades estándar que todo contenedor debe proveer a los
componentes.
 Para poder diseñar aplicaciones Java EE, ya existen distintos patrones de diseño
muy extendidos que posibilitan la reutilización de los componentes y un mejor
mantenimiento de los mismos, como es el patrón Modelo-Vista-Controlador
(MVC).
 Para que una aplicación Java EE, pueda ejecutarse en un servidor Java EE, estos
deben de cumplir las especificaciones determinadas en una versión dada o al
menos aquellas necesarias para el tipo de aplicación que se desea implementar.
 Las aplicaciones Java EE (fichero EAR) están formadas por al menos un módulo de
los siguientes tipos: Módulo Web (fichero WAR), Modulo de EJBs (fichero JAR),
Modulo cliente (fichero JAR), Modulo Adaptador (fichero RAR).
18
 En el mercado existen una multitud de servidores de aplicaciones, pudiendo ser
clasificados por dos categorías:

Gratuitos o de pago.

Certificados Java EE o no.
19
20
Unidad de Aprendizaje 2
EL ENTORNO DE DESARROLLO
ÍNDICE
2.1
Introducción ................................................................... 23
2.2
Descarga, instalación y configuración del entorno de
desarrollo........................................................................ 24
2.2.1 Java Runtime Environment (JRE) .................................24
2.2.2 Eclipse IDE for Java EE Developers ............................29
2.2.3 Apache Tomcat...............................................................34
PARA RECORDAR.................................................................... 40
MÓDULO A – Unidad 2: El Entorno de Desarrollo
2.1
Introducción
Existen multitud de herramientas de desarrollo y ejecución de aplicaciones Java EE. Muchas
de ellas son de pago, pero existen también gratuitas proporcionadas por la Comunidad Open
Source.
Aunque en condiciones normales, en el día a día de una empresa se suelen utilizar soluciones
de pago, principalmente por su estabilidad y soporte oficial, para la realización de este curso
nos vamos a apoyar en herramientas gratuitas.
En concreto:

Eclipse IDE for Java EE Developers 3.7.x de Eclipse.org: Herramienta para el
desarrollo.

Apache Tomcat 7.0.x de The Apache Software Foundation: Herramienta para la
ejecución de aplicaciones web propuestas en este curso.
Como decimos, ambas dos son gratuitas y descargables de la red.
No obstante, vamos a comentar algunas otras herramientas de desarrollo, aunque no las
vayamos a utilizar, para el conocimiento del alumno (los servidores de aplicaciones ya se han
mencionado en la Unidad 1):

Java Enterprise Edition SDK: Es el entorno de desarrollo de referencia. Es gratuito y no
cuenta con herramientas visuales. Es decir, sería el homónimo a la JDK de Java SE.
URL: http://www.oracle.com/technetwork/java/javaee/downloads/index.html

Eclipse IDE for Java EE Developers: Es gratuito y de código abierto. En concreto, es el
que utilizaremos en este curso como hemos mencionado anteriormente.
URL: http://www.eclipse.org/

Rational Application Developer: Es de pago de la empresa IBM.
23
URL: http://www.ibm.com/software/awdtools/developer/application/

NetBeans IDE: Es gratuito y de código abierto.
URL: http://netbeans.org/

Oracle JDeveloper: Es de pago de la empresa Oracle.
URL: http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html
2.2
Descarga, instalación y configuración del entorno de desarrollo
A continuación, describiremos los pasos para descargar, instalar y configurar las herramientas
seleccionadas
en
este
curso
anteriormente
mencionadas
para
poder
realizar
satisfactoriamente las actividades de este curso.
2.2.1 Java Runtime Environment (JRE)
Como seguramente ya conocerá el alumno, el Java Runtime Environment (JRE) es el entorno
de ejecución Java, conocido también con el nombre de Java Virtual Machine (o Máquina
Virtual Java).
Es imprescindible para poder ejecutar código Java en un ordenador, y debido a que las dos
herramientas que vamos a utilizar: Eclipse IDE for Java EE Developers y Apache Tomcat
están desarrollados en Java, es necesaria la existencia de un JRE en nuestra máquina para
poder ejecutarlas.
Ir a la siguiente URL http://www.oracle.com/technetwork/java/javase/downloads mediante un
navegador, y descargar el JRE 7. Para ello, seleccionar “Download JRE”:
24
MÓDULO A – Unidad 2: El Entorno de Desarrollo
En la siguiente pantalla, aceptar la Licencia (“Accept License Agreement”) y elegir la
plataforma deseada pulsando el enlace correspondiente (por ejemplo, para Windows x64,
sería jre-7u1-windows-x64.exe).
Nota: En el momento de la redacción de este manual, el número de Update del JRE 7.0 es el
1, de ahí el nombre jre-7u1-windows-x64.exe; pero en el momento en el que el alumno esté
siguiendo este manual, puede que ya exista un Update más moderno y por tanto que haya
cambiado el número.
No obstante, a excepción del cambio de número y por tanto de nomenclatura, todos los
pasos de descarga, instalación y configuración aquí descritos deberían seguir siendo válidos,
por lo que el alumno puede elegir utilizar el Update 1 o uno posterior.
25
Guardar el fichero en algún directorio temporal del ordenador:
Para instalarlo, ejecutar el fichero descargado (en nuestro ejemplo, jre-7u1-windowsx64.exe), mediante doble click del ratón.
26
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Pulsar el botón “Install >” para comenzar la instalación. Durante dicho proceso, aparecerá
una barra mostrando el progreso de la instalación.
Nota: La ubicación por defecto donde se instalará el JRE es C:\Program Files\Java\jre7; si
deseamos instalarlo en una ubicación distinta, marcar la casilla “Change destination folder”
antes de pulsar el botón “Install >”.
27
Cuando la instalación haya terminado, y si ha sido satisfactoria, debería aparecer la siguiente
pantalla:
Pulsar el botón “Close”.
28
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Aunque el instalador nos diga que la instalación ha sido satisfactoria, nunca está de más
comprobar que efectivamente todo está bien. Para ello, una manera habitual de comprobarlo
es abrir una sesión de DOS y ejecutar el comando:
java.exe -version
Si todo está correcto, debería devolver la versión del JRE instalado:
2.2.2 Eclipse IDE for Java EE Developers
A continuación, pasaremos a descargar e instalar Eclipse IDE, la herramienta de desarrollo
Java que vamos a utilizar durante este curso. Recordar que es importante asegurarse de la
existencia de un Java Runtime Environment (JRE) en el ordenador. Si no existiese, seguir los
pasos del apartado anterior.
Ir a la siguiente URL http://www.eclipse.org/downloads mediante un navegador, y descargar
Eclipse IDE for Java EE Developers para la plataforma deseada, pulsando sobre el enlace
correspondiente (en nuestro ejemplo, Windows 64 bits):
29
Aparecerá una página con el mejor servidor para descargar el fichero que hemos solicitado
dependiendo de nuestra conexión y localización. Simplemente pulsar sobre la flecha verde y
guardar el fichero en un directorio temporal:
30
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Nota: En el momento de la redacción de este manual, la versión de Eclipse es la 3.7.1, es
decir, el número de revisión es el 1, de ahí el nombre eclipse-jee-indigo-SR1-win32x86_64.zip; pero en el momento en el que el alumno esté siguiendo este manual, puede que
ya exista una revisión más moderna y por tanto que haya cambiado el número.
31
No obstante, a excepción del cambio de número y por tanto de nomenclatura, todos los
pasos de descarga, instalación y configuración aquí descritos deberían seguir siendo válidos.
El alumno puede elegir por tanto el instalar el Update 1 o elegir otro Update posterior.
Descomprimir el fichero que hemos descargado (en nuestro ejemplo, eclipse-jee-indigo-SR1win32-x86_64.zip) en el disco duro donde queramos tener Eclipse. Por ejemplo:
D:\eclipse-jee-indigo-SR1-win32-x86_64
Arrancar Eclipse ejecutando:
D:\eclipse-jee-indigo-SR1-win32-x86_64\eclipse.exe
Nos preguntará por la ubicación del workspace (o área de trabajo) donde Eclipse va a ir
guardando todos los proyectos y ficheros que vayamos desarrollando:
Una vez hayamos seleccionado la ubicación, pulsar el botón “OK”:
32
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Cerrar la pestaña de “Welcome” (Bienvenida):
33
2.2.3 Apache Tomcat
Por último, vamos a instalar el servidor Apache Tomcat, necesario para poder ejecutar las
aplicaciones Java EE que desarrollemos en el Eclipse IDE for Java EE Developers.
Para ello, ir a la siguiente URL http://tomcat.apache.org/download-70.cgi mediante un
navegador, y descargar Tomcat para la plataforma deseada desde la sección “Core”,
pulsando sobre el enlace correspondiente (en nuestro ejemplo, 64-bit Windows zip):
Descargar y descomprimir el fichero (en nuestro ejemplo, apache-tomcat-7.0.22-windowsx64.zip) en el disco duro donde queramos tener Eclipse. Por ejemplo:
D:\apache-tomcat-7.0.22
34
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Nota: En el momento de la redacción de este manual, la versión de Tomcat es la 7.0.22, es
decir, el número de revisión es el 22, de ahí el nombre apache-tomcat-7.0.22-windowsx64.zip; pero en el momento en el que el alumno esté siguiendo este manual, puede que ya
exista una revisión más moderna y por tanto que haya cambiado el número.
No obstante, a excepción del cambio de número y por tanto de nomenclatura, todos los
pasos de descarga, instalación y configuración aquí descritos deberían seguir siendo válidos.
Como se ha mencionado en las herramientas anteriores, es decisión del alumno, el decidir
utilizar esta revisión o una posterior.
Una vez hecho esto, ya solo queda configurar Eclipse IDE for Java EE Developers para que
utilice el Apache Tomcat que acabamos de descargar e instalar. Para ello, arrancamos de
nuevo Eclipse y seleccionamos la vista “Servers”:
35
Pulsaremos el botón derecho del ratón sobre la zona en blanco de esta vista, y elegiremos la
opción “New” -> “Server” del menú:
Del listado de posibles servidores, seleccionaremos “Tomcat v7.0 Server” y pulsaremos el
botón “Next >”:
36
MÓDULO A – Unidad 2: El Entorno de Desarrollo
En la siguiente pantalla del asistente, añadiremos la ubicación donde hemos instalado
Apache Tomcat (en nuestro ejemplo, D:\apache-tomcat-7.0.22
37
Y ya por último, pulsaremos el botón “Finish”.
Si todo ha ido bien, ahora en la vista de Eclipse denominada “Servers”, debería aparecer
nuestro servidor Apache Tomcat:
Si seleccionamos con el ratón el nuevo servidor, y pulsamos el botón derecho deberíamos
ver un menú con las distintas acciones que podemos realizar con él:
38
MÓDULO A – Unidad 2: El Entorno de Desarrollo
Seleccionaremos la opción “Start” y veremos como aparecerá una nueva vista denominada
“Console” donde irá apareciendo el log del servidor. En este caso, deberíamos ver cómo va
saliendo toda la información del arranque. Algo parecido a esto:
Volviendo a la vista “Servers”, veremos como el estado del servidor ahora ha cambiado
poniendo “[Started, Synchronized]”.
Podemos parar el servidor nuevamente desde el mismo menú de opciones desde donde lo
arrancamos en el paso anterior y una vez lo haya hecho, cerrar Eclipse.
Con esto damos por finalizada la instalación y configuración del entorno de desarrollo
necesario para llevar a cabo este curso.
39
PARA RECORDAR
 En esta unidad hemos aprendido a instalar la herramienta de desarrollo, Eclipse
IDE for Java EE Developers, el servidor de aplicaciones Apache Tomcat y la Java
Runtime Environment (JRE) necesarias para la implementación de las aplicaciones
web propuestas en este curso.
40
Unidad de Aprendizaje 3
PROTOCOLO HTTP Y
LENGUAJE HTML
ÍNDICE
3.1
Introducción ................................................................... 43
3.2
El protocolo HTTP ......................................................... 44
3.2.1 Dirección de Internet o URL..........................................45
3.2.2 Conversaciones HTTP ...................................................46
3.2.3 Sniffer HTTP ....................................................................51
3.3
El lenguaje HTML........................................................... 54
3.3.1 La etiqueta HTML ...........................................................55
3.3.2 La página HTML..............................................................56
3.3.3 El formulario HTML.........................................................57
3.3.3.1 Campos de texto ......................................................58
3.3.3.2 Áreas de texto ..........................................................59
3.3.3.3 Checkboxes...............................................................60
3.3.3.4 Radiobuttons............................................................61
3.3.3.5 Listas y Combos ........................................................62
3.3.3.6 Botones ....................................................................63
3.3.3.7 Campos ocultos ........................................................64
3.4
Ensamblado y despliegue ............................................ 64
PARA RECORDAR.................................................................... 67
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
3.1
Introducción
Al estudiar las aplicaciones Java EE (o Web), es imposible no hablar primero de la red de
redes: Internet, y de los fundamentos sobre los que se apoya. Simplificando mucho, esos dos
fundamentos son el protocolo de comunicaciones HTTP (HiperText Transfer Protocol) y el
lenguaje de etiquetado HTML (HiperText Markup Language).
Vamos a hablar un poco más en detalle de lo que es un sistema de comunicaciones en
general, y el sistema de comunicaciones en el que se basa Internet: TCP/IP.
Un sistema de comunicaciones en general, se representa como una pila de capas en las que
cada una aporta una funcionalidad concreta a la comunicación. Existe el modelo de referencia
OSI, que representa los sistemas de comunicación desde un punto de vista teórico en 7
capas y luego sistemas de comunicación concretos reales, que implementan ese modelo de
referencia de distintas formas, como por ejemplo el TCP/IP o el SNA.
En el siguiente diagrama se puede ver la comparativa entre el modelo de referencia OSI y el
TCP/IP que es el sistema de comunicaciones que utiliza Internet:
Muy brevemente, repasamos lo que cubre cada uno de los niveles:
1. Físico: Define las características físicas de la red material.
2. Enlace: Proporciona el servicio de envío de datos a través del enlace físico.
3. Red: Gestiona las conexiones de red para las capas superiores.
4. Transporte: Proporciona servicios de detección y corrección de errores.
5. Sesión: Gestiona las conexiones entre aplicaciones cooperativas.
6. Presentación: Estandariza la forma en la que se presentan los datos a las aplicaciones.
7. Aplicación: Aplicaciones que usan la red.
43
Cono podemos observar, el TCP/IP implementa los niveles teóricos en cuatro, a través de
distintos protocolos como IP en el nivel que llama Internet, TCP y UDP entre otros en el nivel
que llama Transporte, y HTTP, FTP, Telnet, etc… en el nivel que llama Aplicación. Es en este
último nivel donde se encuentra el protocolo HTTP que realmente nos interesa para programar
aplicaciones Java EE aunque este, sin el resto de los niveles sería inútil. De ahí que se hayan
mencionado en esta introducción.
Por otro lado, teníamos el lenguaje de etiquetado HTML, la otra piedra angular sobre la que se
sustenta Internet. El HTML es el lenguaje mediante el cual definimos los contenidos que fluyen
por Internet, conocidas como páginas HTML o páginas Web.
Y quizás sin saberlo, todos los días estamos usando ambos dos fundamentos. Los
navegadores web (IExplorer, Firefox, Chrome, Opera…) no son mas que aplicaciones que
implementan el protocolo HTTP a través del cual se reciben bajo petición páginas HTML.
¿Por qué es tan importante tener claro los conceptos del HTTP y HTML entonces? Porque las
aplicaciones Java EE que vamos a aprender a desarrollar, son las que están al otro lado
sirviendo las peticiones de los navegadores web. Por tanto, van a tener que entender el
protocolo HTTP y van a tener que saber contestar con páginas HTML que muestran la
información solicitada.
Nota: como decíamos al inicio de esta introducción, esta es una visión muy simplista pero que
proporciona una idea clara. Es simplista en el sentido de que no solo se utiliza el protocolo
HTTP (aunque si en la mayoría de los casos) ni siempre se utiliza HTML como medio para
mostrar la información (aunque nuevamente si en la mayoría de los casos). Otras opciones a
modo de ejemplo, mucho menos utilizadas, serían protocolos como FTP o Telnet, y lenguajes
de etiquetado como WML o cHTML.
3.2
El protocolo HTTP
Como hemos dicho ya, el protocolo HTTP es el protocolo fundamental desde el punto de vista
del desarrollo de aplicaciones Java EE. Es el encargado de la transferencia de los recursos
que componen la red.
Es un protocolo que sigue un esquema de petición – respuesta (request – response) entre un
cliente (habitualmente un navegador) y un servidor (habitualmente un servidor de aplicaciones
Java EE como ya vimos en las unidades anteriores) donde el cliente solicita un recurso y el
servidor se lo devuelve.
Actualmente se encuentra en su versión 1.1, y es un estándar definido por el IETF (RFC 2616):
http://www.ietf.org/rfc/rfc2616.txt
44
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
3.2.1 Dirección de Internet o URL
Las URLs (Uniform Resource Locator) identifican de forma unívoca un recurso en la red. Un
recurso que puede ser una página HTML, una imagen JPG o incluso un componente Java EE
como un Java Servlet o una JavaServer Page (JSP).
Las URLs constan de las siguientes partes:
 Protocolo: HTTP, HTTPS, FTP, Telnet… a utilizar para acceder al recurso.
 Servidor: Dirección IP o nombre del servidor donde reside el servicio o aplicación que
sabe servir el recurso.
 Puerto: Donde está escuchando el servicio o aplicación que sabe servir el recurso.
 Path (o camino): Donde está ubicado el recurso.
 Recurso: El recurso como tal que estamos solicitando.
Utilizando el siguiente formato:
Protocolo://Servidor:Puerto/Path/Recurso
Nota: Es importante mantener el formato de los dos puntos y las barras.
Lo entenderemos mucho mejor con un ejemplo muy sencillo que la mayoría hemos usado
alguna vez al buscar algo en Google. Para ello, lo que hacemos es escribir en el navegador la
siguiente dirección de Internet o URL:
http://www.google.es:80/index.html
¿Qué significa realmente esto que escribimos habitualmente para buscar cosas en Internet?
Significa que mediante el protocolo HTTP, nos conectamos a la aplicación que está
escuchando en el puerto 80 del servidor www.google.es y le solicitamos el recurso
index.html que está en el directorio raíz (porque no hemos especificado ningún path).
Muchos estaréis pensando que vosotros no escribís nunca ese 80, o que nunca habíais
especificado eso de index.html; correcto. ¿Qué ocurre entonces? Lo que ocurre, es que para
ahorrar trabajo a los usuarios, se establecen muchas cosas por defecto.
Por ejemplo, se ha establecido un puerto por defecto para cada protocolo de manera que si
no decimos el puerto a utilizar, en este caso el navegador añade sin que nosotros lo
sepamos el puerto correspondiente. Algunos puertos por defecto son:
 HTTP: 80
 HTTPS: 443
 FTP: 21
 Telnet: 23
 etc…
45
Y con el nombre del recurso ocurre igual. Está establecido que por defecto si no se
especifica el nombre del recurso, las aplicaciones prueben con unos nombres por defecto
que suelen ser:
 index.html
 index.htm
 index.jsp
 etc…
Por tanto, una URL equivalente a la analizada y con mismo resultado sería:
http://www.google.es
Los servidores en Internet se identifican mediante direcciones IP que consisten en cuatro
grupos de números desde el 0 al 255 separados por puntos, por ejemplo:
74.125.39.103
Todo servidor en Internet tiene asignada una dirección IP única. Si no fuese así, sería
inaccesible porque al hacer una petición, el sistema de comunicaciones TCP/IP no sabría
con cuál conectar. Como el uso de estas direcciones es algo complejo para los usuarios
(difíciles de recordar, fácil de cometer un error), existen unos servidores especiales
denominados DNS (Domain Name Server o Servidores de Nombres de Dominio) que se
encargan de traducir nombres legibles y fáciles de recordar por los usuarios a direcciones IP.
Esta traducción mediante la conexión a los servidores DNS la hace el sistema de
comunicaciones TCP/IP, que comentamos en la introducción, automáticamente sin la
intervención del usuario.
Por ejemplo, en el momento de la redacción de este manual, la dirección IP de
www.google.es era la del ejemplo: 74.125.39.103, es decir, que en el navegador deberíamos
ver la misma página si escribiéramos:
http://74.125.39.103
o si escribiéramos:
http://ww.google.es
3.2.2 Conversaciones HTTP
Como ya comentamos al inicio de este capítulo, HTTP es un protocolo que sigue un
esquema de petición – respuesta (request – response) entre un cliente (habitualmente un
navegador) y un donde el cliente solicita un recurso y el servidor se lo devuelve.
Una petición HTTP se compone a grandes rasgos de:
 Método HTTP: se trata de la acción a realizar. Algunos ejemplos como veremos mas
adelante son GET y POST.
 Recurso sobre el que actuar: es decir, una URL.
46
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
 Parámetros: como los argumentos de un método Java.
Por el otro lado, una respuesta HTTP se compone de:
 Código de estado: un código numérico que indica qué ocurrió con la petición.
 Tipo del contenido: que indica el formato de la respuesta. Por ejemplo, una página
HTML, un documento XML, una imagen JPG, etc…
 Contenido: la respuesta como tal.
El envío de peticiones y respuestas, se realiza mediante un mensaje HTTP, es decir, una
estructura bien definida que sigue una serie de reglas que todo cliente y servidor que
mantengan una conversación HTTP deben conocer y cumplir.
Un mensaje HTTP se compone de:
 Una cabecera: que incluye información técnica.
 Un cuerpo: que incluye el contenido del mensaje como tal.
Los métodos HTTP que se pueden utilizar como parte de una petición HTTP son los
siguientes:
 HEAD: solicita un recurso al servidor, pero que la respuesta no ha de incluir el
contenido, solo las cabeceras.
 GET: solicita un recurso al servidor (normalmente estático como por ejemplo un
fichero).
 POST: solicita un recurso al servidor (normalmente dinámico, es decir, la ejecución de
una aplicación).
 PUT: solicita el envío de un recurso al servidor.
 DELETE: solicita la eliminación de un recurso en el servidor.
 TRACE: solicita al servidor que le conteste lo mismo que le solicita. Se utiliza
normalmente para analizar problemas en la comunicación donde entre el cliente y el
servidor existen otra serie de elementos de comunicaciones como proxies, firewalls,
etc…
 OPTIONS: solicita al servidor conocer qué métodos HTTP soporta.
 CONNECT: solicita al servidor cambiar a un sistema de comunicación cifrada (HTTPS).
Mas adelante, veremos un poco más en detalle los métodos GET y POST que son los
utilizados habitualmente en la programación de aplicaciones Java EE incluyendo algún
ejemplo.
Los códigos de estado que se pueden recibir en una respuesta HTTP son muchos y
variados. Aquí comentamos algunos:
 Códigos 2xx: Petición realizada con éxito.
47
o 200: OK. Este es el código que deberíamos recibir habitualmente.
o 204: Sin contenido.
o 205: Sin contenido, recargar.
o 206: Contenido parcial.
 Códigos 3xx: Redirección.
o 301: Recurso movido de forma permanente.
o 303: Ver otro recurso.
o 307: Recurso movido de forma temporal.
 Códigos 4xx: Error del cliente.
o 400: Petición incorrecta. Se produce si el mensaje HTTP de petición tiene
errores. No es habitual cuando se usa un navegador, pero si, sí estamos
programando un cliente HTTP.
o 403: Prohibido. Se produce cuando intentamos acceder a un recurso
protegido y no tenemos acceso.
o 404: No encontrado. Se produce cuando se solicita un recurso no existente en
el servidor.
 Códigos 5xx: Error en el servidor.
o 500: Error interno. Más habitual de lo que desearíamos.
o 503: Servicio no disponible.
o 505: Versión HTTP no soportada.
Vamos a centrarnos en los dos métodos, es decir, en los dos tipos de petición HTTP más
comunes en el desarrollo de aplicaciones Java EE y que con total seguridad utilizaremos:
GET y POST.
GET es el más simple, y se suele utilizar para solicitar un recurso estático, es decir, un
fichero de tipo HTML, JPG, XML…. No obstante, también puede ser usado para solicitar un
recurso dinámico, es decir, por ejemplo un componente de una aplicación web, y por tanto,
permite el envío de parámetros. Eso si, dichos parámetros van añadidos como parte de la
URL y son visibles, lo que desde un punto de vista de seguridad puede ser un problema.
Veamos un ejemplo de una petición HTTP con el método GET de un servlet Java que suma
dos números:
GET /EjemploWeb/Sumador?param1=12&param2=41 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Referer: http://127.0.0.1/Practica23a/index.html
Accept-Language: en-us,es;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;
SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: 127.0.0.1:8080
48
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Connection: Keep-Alive
Este mensaje HTTP, que en concreto es una petición (lo sabemos porque su primera línea es
un método HTTP en vez de un código de estado) solo tiene cabecera. No tiene cuerpo.
La primera línea de toda petición HTTP siempre es el método HTTP, seguido del recurso
sobre el que queremos ejecutar la acción, y por último la versión de protocolo HTTP utilizada
por el cliente.
Después, hay una secuencia de distintas propiedades (de la forma nombre: valor) que
añaden información técnica al mensaje. Por ejemplo, qué tipo de cliente se está utilizando
(User-Agent). Hay muchas, y solo comentaremos a lo largo del curso aquellas que tengan
relevancia.
En este ejemplo, estamos pidiendo el recurso /EjemploWeb/Sumador pasándole dos
parámetros: param1 y param2 con los valores 12 y 41. Como se puede ver, se indica que
hay parámetros mediante el símbolo ? y se separan los parámetros (parejas de
nombre=valor) mediante el símbolo &.
Veamos ahora la respuesta HTTP de este mismo ejemplo:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=304CE17CCEB55869A606CE06271F915B;
Path=/EjemploWeb
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 314
Date: Sun, 08 Jun 2008 09:19:19 GMT
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<TITLE>Calculadora</TITLE>
</HEAD>
<BODY>
El resultado de la suma de 12 y 41 es: 53
</BODY>
</HTML>
En este caso, el mensaje HTTP si que incluye tanto cabecera como cuerpo.
Lo primero, sabemos que es una respuesta porque la primera línea comienza con la versión
HTTP utilizada por el servidor, seguido del código de estado. En este caso, un 200 que
indica que todo ha ido bien.
Hay otras cabeceras adicionales muy importantes para saber interpretar la respuesta como
son: Content-Type, que indica el tipo de contenido del cuerpo (en este caso un fichero
HTML) y Content-Lenght, que indica el tamaño del contenido (en este caso 314 bytes).
Separado por un salto de línea viene el cuerpo del mensaje HTTP que como ya nos indicaba
la cabecera es un fichero HTML (más adelante, en esta misma unidad, hablaremos del
lenguaje HTML).
49
POST es el método que habitualmente se utiliza para enviar parámetros, porque van en el
cuerpo de la petición en vez de añadidos a la URL del recurso solicitado.
Veamos el mismo ejemplo que antes para identificar las diferencias. En este caso la petición
sería:
POST /EjemploWeb/Sumador HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, */*
Referer: http://127.0.0.1/EjemploWeb/index.html
Accept-Language: en-us,es;q=0.5
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;
SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Host: 127.0.0.1:8080
Content-Length: 19
Connection: Keep-Alive
Cache-Control: no-cache
param1=45&param2=21
Nuevamente identificamos que se trata de una petición HTTP porque la primera línea
comienza con un método HTTP. Y vemos, que a diferencia de lo que ocurría con el método
GET, en esta ocasión la URL no incluye ningún parámetro sino que el mensaje tiene un
cuerpo con dichos parámetros.
Hay alguna diferencia en alguna cabecera más, pero tampoco entraremos en tanto detalle.
La respuesta sería:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=304CE17CCEB55869A606CE06271F915B;
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 314
Date: Sun, 08 Jun 2008 09:27:24 GMT
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html;
charset=ISO-8859-1">
<TITLE>Calculadora</TITLE>
</HEAD>
<BODY>
El resultado de la suma de 45 y 21 es: 66
</BODY>
</HTML>
Como vemos, es igual que la del ejemplo anterior, ya que lo que nos devuelve el servidor si
le pedimos lo mismo (aunque sea por dos métodos distintos) siempre será lo mismo.
Los parámetros que se envían en una petición, pueden ser cualquier carácter alfanumérico
ASCII, incluyendo los caracteres: . (punto), - (guion), * (asterisco) y _ (subrayado). Cualquier
otro tipo de carácter ha de ir codificado:
 El espacio en blanco con el carácter + (suma).
 Cualquier otro carácter con un valor hexadecimal de la forma %xx. Por ejemplo, la ñ
(eñe), con %F1. En Internet están las tablas de conversión y el propio lenguaje Java
50
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
tiene métodos para decodificar y decodificar caracteres de una URL en la clase
java.net.Encoder y java.net.Decoder
Es importante tener presente, que si se usa el método GET para el envío de dichos
parámetros, es responsabilidad del desarrollador la codificación. Por el contrario, si se usa el
método POST, la codificación se realiza de forma automática.
No obstante, en los casos en los que el cliente HTTP sea un navegador, como ocurrirá la
mayoría de las veces en este curso, es el propio navegador el que se encarga de dicha
codificación automáticamente.
3.2.3 Sniffer HTTP
En principio, toda esta comunicación HTTP suele ocurrir sin un conocimiento muy profundo
por parte del desarrollador de aplicaciones Java EE. Pero como iremos viendo en las
sucesivas unidades, si que hay conceptos de los tratados hasta este momento en esta
unidad que son imprescindibles de conocer.
E incluso, en muchas ocasiones, para depurar un problema de nuestras aplicaciones, será
imprescindible analizar los mensajes HTTP que fluyen entre el cliente (por ejemplo, un
navegador) y nuestra aplicación Java EE servidora.
Ahora, ¿y cómo podemos ver los mensajes HTTP que viajan por la red entre el cliente y el
servidor? Para esto existen unas herramientas habituales en el mundo de las redes de
comunicaciones que se llaman “sniffers”, que se encargan de monitorizar el tráfico de red. El
funcionamiento habitual, consiste en ponerse entre medias del cliente y del servidor, y
registrar todo el tráfico que fluye: tanto peticiones como respuestas.
La herramienta de desarrollo que utilizamos en este curso, Eclipse IDE for Java EE
Developers, incluye un sniffer denominado TCP/IP Monitor.
Para acceder a él, ir a las opciones de menú “Window” -> “Show view” -> “Other…”:
51
Seleccionar la vista de “TCP/IP Monitor” de la carpeta “Debug”:
52
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Se abrirá el TCP/IP Monitor en una pestaña más:
En sus propiedades, añadimos una configuración mediante el botón “Add…”, estableciendo
el puerto por el que escucha, y a qué dirección y puerto debe renviar todo el tráfico. En
nuestro caso, si monitorizamos el tráfico con el Servidor de Aplicaciones Tomcat que
tenemos en el propio Eclipse IDE, podríamos decirle que escuche en el puerto 80 (por
ejemplo) y que renvíe a nuestra misma máquina al puerto 8080 (puerto por donde escucha
por defecto el Servidor de Aplicaciones Tomcat):
Por último, lo arrancamos mediante el botón “Start”.
Ahora solo queda, realizar peticiones desde nuestro navegador al servidor, pero en vez de
hacerlo directamente al puerto 8080, lo haremos a través del puerto 80 para que el sniffer
intercepte las comunicaciones y las renvíe. Así, escucharemos en el puerto 80 de nuestra
53
máquina y lo renviaremos al 8080 del servidor de aplicaciones (que en este ejemplo, también
está en nuestra máquina):
De momento, no hay que preocuparse mucho por su funcionamiento. Ya tendremos ocasión
de probarlo con las primeras aplicaciones Java EE que desarrollemos
en la siguiente
unidad.
3.3
El lenguaje HTML
El HTML (HiperText Markup Languaje) es el lenguaje utilizado para crear documentos web (o lo
que comúnmente se denominan páginas web). Básicamente se trata de un lenguaje de
etiquetado, que define la estructura y el contenido de un documento a ser compartido y
accedido en Internet a través de un navegador web.
Junto con el protocolo HTTP son la base sobre la que se construyó la red de redes conocida
como Internet.
Este lenguaje está estandarizado bajo la supervisión del W3C. En el momento de la redacción
de este manual, la última versión del lenguaje HTML es la 4.01:
http://www.w3.org/TR/html4/
aunque la siguiente versión, 5.0, está en proceso de definición:
http://www.w3.org/TR/html5/
No obstante, el lenguaje HTML requeriría un manual dedicado para cubrir todas sus
características y posibilidades. En nuestro caso, al igual que hemos hecho con el protocolo
HTTP, solo haremos un breve recorrido introductorio para conocer lo imprescindible que nos
permita desarrollar aplicaciones Java EE.
54
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Para profundizar en el lenguaje HTML recomendamos el curso de Aula Mentor HTML.
Adicionalmente, junto con el lenguaje HTML, han ido surgiendo otras tecnologías y lenguajes
para dotar a las páginas web de cierto dinamismo y potencia. Algunas de ellas son el lenguaje
JavaScript, tecnologías AJAX, etc… que no cubriremos en este curso.
Nuevamente, en la oferta de cursos de Aula Mentor, los hay orientados a estas tecnologías.
3.3.1 La etiqueta HTML
Como ya hemos dicho, el lenguaje HTML está orientado a etiquetas. Una etiqueta no es más
que un elemento que define qué se debe hacer o cómo se debe presentar la información
que viene a continuación de ella dentro de una página web.
Normalmente, las etiquetas se utilizan a pares, es decir, etiqueta de inicio de definición y
etiqueta de final de definición.
El formato es el siguiente:
<nombre_etiqueta [atributo1="valor1", atributo2="valor2",...]>
[contenido]
[</nombre_etiqueta> ]
Como podemos observar, las etiquetas van definidas entre los caracteres < y >. Y para
diferenciar cuándo se trata de una etiqueta de apertura o de cierre, en la de cierre se utiliza
el carácter / después del carácter <.
Entre la pareja de etiquetas, se añade el contenido que se verá afectado por el significado
de dichas etiquetas.
Adicionalmente, las etiquetas pueden permitir atributos que complementan el significado y
comportamiento de la etiqueta.
Veámoslo con un ejemplo rápido:
<FONT size="3" color="red"> Hola mundo </FONT> Este ejemplo es un fragmento de una página o documento HTML. Y en él, podemos
observar fácilmente, que se trata del uso de la etiqueta FONT. En la primera línea vemos el
uso de la etiqueta de inicio <FONT>, y en la tercera línea la etiqueta de final </FONT>.
El contenido que se va a ver afectado por el significado y comportamiento de la etiqueta es
el texto Hola mundo de la segunda línea.
Adicionalmente, podemos observar que la etiqueta de inicio incluye una serie de atributos,
como son ‘size’ (tamaño) y ‘color’. Una etiqueta de final, nunca lleva atributos.
El resultado visual en un navegador web de una página web, que incluyera este fragmento
sería este:
55
3.3.2 La página HTML
Una vez visto la base del lenguaje HTML (las etiquetas), vamos a centrarnos en la página o
documento HTML (también nombrada página web).
Una página o documento HTML, es un fichero de texto con extensión *.htm o *.html que
contiene una información formateada mediante el lenguaje HTML.
Aunque los navegadores web, desde siempre han sido muy permisivos con las páginas
HTML mal formateadas (etiquetas de final no añadidas, estructura de la página errónea,
etc…) vamos a intentar crearlas siempre correctamente.
La estructura mínima de una página HTML sintácticamente correcta, es la siguiente:
<!DOCTYPE HTML PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN"> <HTML> <HEAD> <TITLE>Mi primer HTML</TITLE> </HEAD> <BODY> Mi primer ejercicio </BODY> </HTML>
Este código HTML debería ir salvado en un fichero de extensión *.html y al abrirlo en un
navegador, veríamos algo así:
La primera línea es un tanto especial. Se trata de una etiqueta de descripción técnica del
fichero HTML donde especifica la versión de HTML utilizada, entre otras cosas.
56
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Pero lo realmente importante viene después, y es, la estructura de una página HTML. Toda
página HTML debe ir siempre definida por la etiqueta HTML.
Una página HTML se divide en dos secciones distintas:
 La cabecera, definida por la etiqueta HEAD.
 El cuerpo, definido por la etiqueta BODY.
En la cabecera de una página HTML se añadirá información relacionada con la página, como
por ejemplo su título (definido por la etiqueta TITLE), mientras que en el cuerpo, irá el
contenido de la página como tal. En nuestro caso, simplemente va el texto Mi primer
ejercicio.
Como se puede observar en la imagen de ejemplo, los navegadores web normalmente
muestran el título de la página HTML en la pestaña que está mostrando dicha página (u
otros, en la barra de título del navegador).
Otro contenido típico de la cabecera de una página HTML, es información específica para
algunos buscadores de Internet, que les ayuda a indexar y categorizar la página.
3.3.3 El formulario HTML
Como ya hemos comentado, este curso no tiene como objetivo el lenguaje HTML sino la
programación de aplicaciones Java EE. Por ello, no vamos a enumerar y explicar las
decenas de etiquetas existentes en el lenguaje HTML,
Solo nos vamos a centrarnos en un subconjunto que si son imprescindibles para interactuar
con aplicaciones Java EE servidoras que son las relacionadas con los formularios HTML.
Un formulario es la presentación visual de entrada de datos en una página HTML para ser
enviados a una aplicación servidora.
La etiqueta que lo define es FORM. Dicha etiqueta puede contener distintos atributos,
algunos obligatorios y otros opcionales.
Los dos atributos obligatorios son:
 Method: El método HTTP que se va a utilizar al enviar al servidor la información
recogida en el formulario.
 Action: El recurso o componente del servidor al que se le va a enviar la información.
Otros atributos posibles son: ‘name’, ‘target’, ‘id’, etc…
Ejemplo:
<FORM method=”POST” action=”/EjemploWeb/EjemploServlet”> </FORM>
57
Este formulario va a enviar a un Java Servlet del servidor mediante el método HTTP POST
toda la información que contenga. De momento, tal cual está en el ejemplo, no contiene
ninguna información.
Un formulario puede contener distintos elementos para recoger información del usuario:
 Campos de texto.
 Áreas de texto.
 Checkboxes.
 Radiobuttons.
 Listas y combos.
 Botones.
 Campos ocultos.
Veamos uno por uno.
3.3.3.1 Campos de texto Un campo de texto se define mediante la etiqueta INPUT y su atributo ‘type’ con el valor
‘text’.
Admite otros atributos como son:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
 Value: valor que debe aparecer por defecto si así se desea.
 Size: tamaño del campo en la pantalla desde un punto de vista visual.
 Maxlength: número máximo de caracteres que se pueden introducir en este campo.
 Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
Esta etiqueta no requiere su homónima de final.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Introduzca su nombre: <INPUT type=”text” name=”nombre” maxlength=”20”> </FORM>
El navegador mostraría algo así:
58
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Existe un caso particular de campo de texto, que es el utilizado para introducir información
secreta (como por ejemplo una contraseña) donde no se quiere que se pueda leer la
información tecleada.
Se define igual que el campo de texto con la diferencia de que el atributo ‘type” debe tener
el valor ‘password’.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Introduzca su contraseña: <INPUT type=”password” name=”contrasena” maxlength=”20”> </FORM>
El navegador mostraría algo así:
3.3.3.2
Áreas de texto Un área de texto se define mediante la etiqueta TEXTAREA.
Admite los siguientes atributos:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
 Cols: el número de columnas visible.
 Rows: el número de filas visible.
 Readonly: no tiene un valor, sino que su sola presencia significa que el campo es de
solo lectura.
 Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
59
Esta etiqueta si requiere su homónima de final. Y el contenido que queramos que aparezca
por defecto en ella si así lo deseamos, debe ir entre ambas etiquetas.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Introduzca sus comentarios: <BR> <TEXTAREA name=”comentarios” cols=”10” rows=”20”> </TEXTAREA> </FORM> El navegador mostraría algo así:
3.3.3.3
Checkboxes Una checkbox se define mediante la etiqueta INPUT y su atributo ‘type’ con el valor
‘checkbox’.
Admite otros atributos como son:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
 Value: el valor del campo en caso de estar seleccionado.
 Checked: no tiene un valor, sino que su sola presencia significa que la checkbox está
seleccionada por defecto.
 Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
Esta etiqueta no requiere su homónima de final.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Seleccione sus deportes favoritos: <BR> Fútbol: <INPUT type="checkbox" name="futbol" value="true" checked> <BR> 60
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Baloncesto: <INPUT type="checkbox" name="baloncesto" value="true"> <BR> Petanca: <INPUT type="checkbox" name="petanca" value="true"> </FORM> El navegador mostraría algo así:
3.3.3.4
Radiobuttons Un radiobutton se define mediante la etiqueta INPUT y su atributo ‘type’ con el valor ‘radio’.
Admite otros atributos como son:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
Si varios radiobuttons comparten el mismo nombre, entonces forman un grupo donde
solo uno de ellos puede estar seleccionado.
 Value: el valor del campo en caso de estar seleccionado.
 Checked: no tiene un valor, sino que su sola presencia significa que el radiobutton está
seleccionada por defecto.
 Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
Esta etiqueta no requiere su homónima de final.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Seleccione su sexo: <BR> <INPUT type="radio" name="sexo" value="tipo1" checked> Hombre <BR> <INPUT type="radio" name="sexo" value="tipo2"> Mujer <BR> </FORM>
El navegador mostraría algo así:
61
3.3.3.5
Listas y Combos Tanto las listas como los combos se definen mediante la etiqueta SELECT.
Admite los siguientes atributos:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
 Size: especifica el número de valores visible. Si solo es visible un valor, se mostrará
como un Combo. Si son visibles dos o más, se mostrará como una lista.
 Multiple: no tiene un valor, sino que su sola presencia significa que se pueden
seleccionar más de un elemento a la vez.
 Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
Esta etiqueta si requiere su homónima de final. Y las distintas opciones que vayan a formar
parte de la lista deberán ir definidas entre ambas mediante la etiqueta OPTION.
La etiqueta OPTION admite los siguientes atributos:
 Value: el valor del campo en caso de estar seleccionado.
 Selected: no tiene un valor, sino que su sola presencia significa que esta opción está
seleccionada por defecto.
Esta etiqueta si requiere su homónima de final. Y el contenido que queramos que aparezca
como opción debe ir entre ambas etiquetas.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> Seleccione el postre: <BR> <SELECT name="postre" size="3"> <OPTION value="op1">Fruta</OPTION> <OPTION value="op2" selected>Helado</OPTION> <OPTION value="op3">Cuajada</OPTION> <OPTION value="op4">Tarta</OPTION> </SELECT> </FORM> 62
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
El navegador mostraría algo así:
3.3.3.6
Botones Un botón se define mediante la etiqueta INPUT. Y dependiendo del valor que tenga su
atributo “type” será de un tipo u otro:
 Button: se trata de un botón genérico que por sí solo no hace nada. Hay que
acompañarlo de JavaScript, por ejemplo, para que realice alguna operativa.
 Submit: se trata de un botón que al ser pulsado envía toda la información recogida en
el formulario al recurso del servidor identificado en el atributo “action” del formulario
mediante el método HTTP especificado en el atributo “method” del formulario.
 Reset: se trata de un botón que al ser pulsado borra toda la información recogida en el
formulario.
Admite otros atributos como son:
 Name: el nombre del botón, que puede ser útil cuando se programa con JavaScript en
la página HTML.
 Value: el texto que aparece escrito en el botón.
 Disabled: no tiene un valor, sino que su sola presencia significa que el botón está
deshabilitado.
Esta etiqueta no requiere su homónima de final.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> <INPUT type="submit" value="Enviar"> <INPUT type="reset" value="Borrar"> </FORM> El navegador mostraría algo así:
63
3.3.3.7
Campos ocultos Existen ocasiones, en las que nos interesará que como parte del formulario se envíe
información no visible para el usuario pero necesaria para la lógica de nuestra aplicación.
Dichos campos se definen mediante la etiqueta INPUT y su atributo ‘type’ con el valor
‘hidden’.
Admite otros atributos como son:
 Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
 Value: el valor del campo, no modificable por el usuario.
Esta etiqueta no requiere su homónima de final.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”> <INPUT type=”hidden” name=”usuario” value=”1234”> </FORM> Evidentemente, en el navegador no se vería nada.
Pues bien, esto es todo lo que hay que conocer de HTML para poder interactuar entre el
usuario y la aplicación Java EE mediante un navegador web. Cualquier otra etiqueta HTML
ya sería para dar formato a la página: tablas, cabeceras, imágenes, enlaces, frames, etc…
3.4
Ensamblado y despliegue
Las páginas HTML pueden desplegarse de distintas maneras.
Por ejemplo, se pueden desplegar en un Servidor Web como Apache HTTP Server
(http://httpd.apache.org/) o Internet Information Server (http://www.iis.net/) entre otros. Estos
servidores, se limitan a servir webs estáticas basadas en páginas HTML y sus recursos:
imágenes, hojas de estilo, etc...
Pero como vimos en la primera unidad de este curso, también se pueden desplegar como
parte de una aplicación Java EE (dentro de un módulo web) en un Servidor de Aplicaciones
Java EE.
64
MÓDULO A – Unidad 3: El protocolo HTTP y el lenguaje HTML
Esta segunda opción será la que estudiaremos y utilizaremos a lo largo del curso, pero a partir
de la siguiente unidad.
De momento, en las actividades de esta unidad, nos limitaremos a crear las páginas HTML en
el sistema de archivos local y abrirlas con el navegador accediendo al disco duro (no
escribiendo ninguna URL de un servidor).
Por ejemplo, con Mozilla Firefox 10:
O con Internet Explorer 9:
65
66
PARA RECORDAR
 El modelo de referencia OSI representa los sistemas de comunicación desde un
punto de vista teórico en 7 capas implementado en un sistema de comunicación
real como es el TCP/IP.
 El protocolo HTTP es el encargado de la transferencia de los recursos, de las
aplicaciones web, que componen la red. Estos recursos son identificados de forma
unívoca mediante las URLs, que tienen el siguiente formato:
Protocolo://Servidor:Puerto/Path/Recurso
 Las conversaciones HTTP, de petición – respuesta se componen de:
 La petición contiene un método HTTP (GET y POST.), un recurso o URL y los
parámetros o argumentos.
 Una respuesta contiene un código de estado o resultado, tipo del contenido de
la respuesta y el contenido como tal.
 Se han estudiado los métodos GET y POST para las solicitudes de recursos
estáticos y dinámicos a un servidor de aplicaciones, su formato tanto en las
peticiones como en las respuestas y la utilización de sniffers para poder depurar
las solicitudes.
 HTML es el lenguaje mediante el cual definimos los contenidos que fluyen por
Internet, conocidas como páginas HTML o páginas Web. Básicamente se trata de
un lenguaje de etiquetado, que define la estructura y el contenido de un documento
a ser compartido y accedido en Internet a través de un navegador web.
 Una etiqueta es un elemento que define qué o como se debe presentar la
información que viene a tras la etiqueta, dentro de una página web.

Una página HTML, es un fichero de texto con extensión *.htm o *.html que
contiene una información formateada mediante el lenguaje HTML. Está formada
normalmente por una cabecera <HEAD> y un cuerpo <BODY>.

Un formulario (FORM) es la presentación visual de entrada de datos en una
página HTML para ser enviados a una aplicación servidora. Se han estudiado
distintos elementos como INPUT, TEXTAREA ….
67
68
Unidad de Aprendizaje 4
JAVA SERVLETS
ÍNDICE
4.1
Introducción ................................................................... 71
4.2
Mi primer Java Servlet .................................................. 72
4.3
Java Servlets .................................................................. 84
4.3.1 El ciclo de vida de un Java Servlet ..............................84
4.3.2 Petición y respuesta de un Java Servlet .....................88
4.3.3 Procesamiento de un formulario HTML ......................93
4.3.4 Empaquetado y despliegue ..........................................97
RECORDAR............................................................................. 103
MÓDULO B – Unidad 4: Java Servlets
4.1
Introducción
Ya vimos en la primera unidad del curso, que los Java Servlets eran un tipo de componente
Java EE que se empaquetaba en un módulo web (WAR) y se desplegaba y ejecutaba en el
contenedor web de un Servidor de Aplicaciones Java EE.
Adicionalmente, dentro del patrón de diseño MVC ocupaban el espacio del Controlador, como
receptor/validador de peticiones, seleccionador de la lógica a ejecutar, y seleccionador de la
vista a presentar como resultado.
No obstante, de momento, dado que es el primer componente que vamos a estudiar, va a
cubrir completamente todas las responsabilidades del MVC. Y según vayamos avanzando en
el curso, le iremos quitando responsabilidades que no debieran ser del Java Servlet, para
dárselas a otro tipo de componente como la JavaServer Page (JSP).
Repetimos, esto es un mal diseño y una mala práctica de programación. Pero consideramos
que es imprescindible ir aprendiendo poco a poco. Por tanto, este diseño es temporal
mientras avanzamos en las sucesivas unidades del curso.
71
Por último, desde un punto de vista del lenguaje de programación Java, un Java Servlet no es
más que una clase Java que implementa una determinada interface definida en las
especificaciones.
4.2
Mi primer Java Servlet
Antes de entrar a estudiar en profundidad los Java Servlets, vamos a guiar los pasos para
desarrollar nuestro primer Java Servlet con Eclipse IDE for Java EE Developers y desplegarlo
en Apache Tomcat. Es requisito indispensable, haber seguido los pasos de instalación y
configuración de ambas dos herramientas detallados en la unidad 2 de este curso.
Estos mismos pasos nos servirán para los sucesivos ejemplos y actividades del resto del
curso.
Arrancamos Eclipse IDE for Java EE Developers y mediante el las opciones de menú “File” ->
“New” -> “Dynamic Web Project”:
Creamos la estructura de desarrollo de un módulo web (WAR). Como nombre del proyecto,
pondremos “HolaMundoWeb”, y nos aseguraremos que seleccionamos “Apache Tomcat v7.0”
72
MÓDULO B – Unidad 4: Java Servlets
como entrono de ejecución y “3.0” como el nivel de especificaciones Java EE (en cuanto a
contenedor web) que queremos utilizar. Pulsamos el botón “Next” dos veces:
En la última ventana del asistente, antes de pulsar el botón “Finish”, nos aseguramos de
marcar la opción “Generate web.xml deployment descriptor”:
73
La estructura del proyecto creado debería ser algo así:
74
MÓDULO B – Unidad 4: Java Servlets
En el directorio /Java Resources/src es donde iremos colocando el código fuente de nuestras
clases Java.
En el directorio /WebContent es donde iremos colocando los recursos web, como por
ejemplo, las páginas HTML, las JavaServer Pages (JSP), imágenes, etc…
Y el fichero web.xml de /WebContent/WEB-INF es el descriptor de despliegue del módulo web
(en nuestro caso, del proyecto HolaMundoWeb).
Ahora crearemos un Java Servlet. Botón derecho sobre el nuevo proyecto -> “New” ->
“Class”:
75
En la siguiente ventana, rellenamos el nombre del paquete Java (Package) con
“es.aulamentor”, el nombre de la clase Java (Name) con “HolaMundoServlet” y la clase padre
(Superclass) con “javax.servlet.http.HttpServlet”.
Nota: No incluir las comillas en los nombres mencionados
Y pulsamos el botón “Finish”:
76
MÓDULO B – Unidad 4: Java Servlets
Escribimos el siguiente código Java en la clase creada y salvamos:
package es.aulamentor; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HolaMundoServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF‐8"); PrintWriter out = resp.getWriter(); 77
out.println("<!DOCTYPE HTML PUBLIC \"‐//W3C//DTD HTML 4.01 Transitional//EN\">"); out.println("<HTML>"); out.println(" <HEAD>"); out.println(" <TITLE>Hola Mundo!</TITLE>"); out.println(" </HEAD>"); out.println(" <BODY>"); out.println(" Hola Mundo!"); out.println(" </BODY>"); out.println("</HTML>"); } } No nos preocupemos en este momento por no entender el código. De momento, simplemente
queremos mostrar los pasos para el desarrollo y despliegue de un Java Servlet. En los
sucesivos apartados iremos entendiendo el por qué de cada línea.
A continuación, editaremos el descriptor de despliegue del módulo web, el fichero web.xml de
/WebContent/WEB-INF y añadiremos este código XML salvando al final el fichero:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>HolaMundoServlet</servlet‐name> <servlet‐class>es.aulamentor.HolaMundoServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>HolaMundoServlet</servlet‐name> <url‐pattern>/HolaMundoServlet</url‐pattern> </servlet‐mapping> </web‐app> Ya solo queda, probar la aplicación. Para ello, pulsamos el botón derecho sobre la clase del
Java Servlet -> “Run As” -> “Run on Server”:
78
MÓDULO B – Unidad 4: Java Servlets
En la siguiente ventana, seleccionar “Tomcat v7.0 Server at localhost” y pulsar el botón
“Finish”:
79
En la vista de “Console” veremos las trazas que va dejando el Servidor de Aplicaciones Java
EE al arrancar, cómo despliega la aplicación y automáticamente abre un navegador interno de
Eclipse IDE con la URL: http://localhost:8080/HolaMundoWeb/HolaMundoServlet donde se ve
el resultado de nuestro primer Java Servlet:
80
MÓDULO B – Unidad 4: Java Servlets
Perfectamente podríamos utilizar otro navegador web (tipo Mozilla Firefox o Internet Explorer)
y escribir la misma URL. El comportamiento debería ser el mismo.
Para abrir el navegador interno de Eclipse IDE a mano, utilizar el botón de la barra de
herramientas:
Otra opción también válida habría sido utilizar el asistente de Java Servlets directamente en
vez del asistente de una clase Java convencional, pero preferíamos que se viera un ejemplo “a
mano”. Esta opción, habría sido con las opciones de menú “New” -> “Servlet”:
81
Este asistente, añade una anotación especial sobre la clase Java en el código fuente de
manera que no es necesario añadir nada al descriptor de despliegue. Como ya comentamos
en la primera unidad, esta era una novedad de la última versión de la especificación Java EE.
En este curso, comentaremos ambas dos opciones.
Ya solo nos queda desinstalar la aplicación mediante la opción “Add and Remove…”:
82
MÓDULO B – Unidad 4: Java Servlets
Y apagar el servidor mediante la opción “Stop”:
83
4.3
Java Servlets
Todas las clases Java relacionadas con los Java Servlets, están en los paquetes:
Los

javax.servet

javax.servlet.http
Java
Servlets
fueron
concebidos
para
ser
independientes
del
protocolo
de
comunicaciones. Pero la realidad ha sido, que el 99% de su uso está relacionado con el
protocolo HTTP (redes Internet e Intranets). De ahí, que existan clases en el API que nos
ayudan a gestionar las peculiaridades de dicho protocolo en el segundo paquete mencionado:
javax.servlet.http
4.3.1 El ciclo de vida de un Java Servlet
Un Java Servlet tiene definido un ciclo de vida, forzado por la interface javax.servlet.Servlet,
por tanto, siempre que queramos implementar un Java Servlet, nuestra clase deberá
84
MÓDULO B – Unidad 4: Java Servlets
implementar dicho interface. Es una especie de contrato entre el Java Servlet y el
contenedor web del Servidor de Aplicaciones Java EE para poder funcionar.
Dicho ciclo de vida tiene los siguientes estados:
 Cuando se recibe una petición de la ejecución de un Java Servlet en el Servidor de
Aplicaciones Java EE y este no ha sido invocado nunca, el contenedor web instancia
la clase del Java Servlet (llama a su constructor) y acto seguido invoca el método:
public void init(ServletConfig config);
Dicho método, solo se ejecuta una vez en la vida del Java Servlet y se suele utilizar
para llevar a cabo todas las labores de inicialización que necesitemos para su
posterior ejecución.
Como se puede observar, recibe como parámetro una instancia de la clase
ServletConfig, que representa información de configuración que el administrador del
Servidor de Aplicaciones Java EE haya podido añadir. Veremos este método en más
detalle en los siguientes apartados.
 Una vez está ya inicializado, entonces invoca el método:
public void service(ServletRequest request, ServletResponse response);
Dicho método se ejecuta cada vez que se recibe una petición para este java Servlet.
En su implementación, colocaremos la lógica para la que se creó dicho Java Servlet.
Como se puede observar, recibe como parámetros un par de instancias de las clases
ServletRequest y ServletResponse. Ambos dos parámetros representan la petición (la
usaremos para entender qué nos están pidiendo) y la respuesta (la utilizaremos para
devolver el resultado de la ejecución del java Servlet al peticionario).
 Si por alguna razón el contenedor web necesita eliminar al Java Servlet (se detiene el
Servidor de Aplicaciones Java EE, se queda sin recursos de memoria y necesita liberar
espacio, etc…), entonces invoca el método:
public void destroy();
Dicho método solo se ejecuta una vez en la vida del java Servlet y se suele utilizar para
liberar todos aquellos recursos que pudiéramos estar utilizando, para dejar el sistema
lo mas limpio posible.
Lo que ocurre, es que el API ya tiene una serie de clases que no solo implementan por
defecto el ciclo completo de vida de un Java Servlet, sino que como decíamos, también nos
ayuda con los temas relacionados con el protocolo HTTP.
Así, tenemos la clase javax.servlet.http.HttpServlet que además de implementar los métodos
comentados anteriormente (es decir, implementar el interface javax.servlet.Servlet), añade
otros más potentes que nos dan valor añadido al trabajar con el protocolo HTTP.
85
Por ejemplo, si recordamos de la unidad anterior donde hablábamos del protocolo HTTP,
comentábamos que existían distintos métodos utilizables en la petición: GET, POST, PUT,
etc…
Pues esta clase, implementa un método Java por cada método HTTP existente, de forma,
qué él ya se encarga de recibir la petición HTTP, examinarla, e invocar el método Java
correspondiente al método HTTP utilizado, así como darnos acceso a un par de objetos que
representan tanto la petición como la respuesta HTTP. Los más habituales que utilizaremos
nosotros son:

protected void doGet(HttpServletRequest request, HttpServletResponse response);

protected void doPost(HttpServletRequest request, HttpServletResponse response);
Dichos métodos normalmente los sobrescribiremos en nuestro Java Servlet para incluir
nuestra lógica particular.
Veamos un ejemplo de un Java Servlet que simplemente muestra por la consola del Servidor
de Aplicaciones Java EE trazas del ciclo de vida:
package es.aulamentor; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CicloDeVidaServlet extends HttpServlet { public CicloDeVidaServlet() { super(); System.out.println("CicloDeVidaServlet()"); } public void init(ServletConfig config) throws ServletException { System.out.println("init()"); } public void destroy() { System.out.println("destroy()"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException { System.out.println("doGet()"); } } El editor de despliegue tendría algo así:
86
MÓDULO B – Unidad 4: Java Servlets
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>CicloDeVidaServlet</servlet‐name> <servlet‐class>es.aulamentor.CicloDeVidaServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>CicloDeVidaServlet</servlet‐name> <url‐pattern>/CicloDeVidaServlet</url‐pattern> </servlet‐mapping> </web‐app> Al invocar varias veces a este Java Servlet desde un navegador, y después parar el Servidor
de Aplicaciones Java EE, deberíamos ver algo así:
Como podemos ver, en la consola salen en negro las trazas que dejamos desde nuestro
código: primero el constructor, seguido del init(), seguido de tres doGet() porque ese fue el
87
número de veces que invocamos seguidas el Java Servlet, y por último, al apagar el Servidor
de Aplicaciones Java EE el destroy().
En el navegador, evidentemente no se ve nada, puesto que no devolvimos ningún resultado
en el código del Java Servlet.
4.3.2 Petición y respuesta de un Java Servlet
La invocación de un Java Servlet independientemente del método HTTP que se utilice,
siempre
recibe
dos
parámetros:
javax.servlet.http.HttpServletRequest
y
javax.servlet.http.HttpServletResponse.
javax.servlet.http.HttpServletRequest, es un interfaz que define cómo interactuar con la
información que viene en una petición HTTP, como por ejemplo, las cabeceras HTTP de la
petición, los parámetros de la petición, etc…
Algunos métodos son:
 java.util.Enumeration<java.lang.String> getParameterNames(): devuelve una colección
con los nombres de todos los parámetros enviados en la petición.
 java.lang.String getParameter(java.lang.String name): devuelve el valor de un
parámetro concreto enviado en la petición.
 java.lang.String[] getParameterValues(java.lang.String name): devuelve todos los
valores de un parámetro concreto enviado en la petición (imaginemos un conjunto de
checkboxes con el mismo nombre de un formulario).
 java.util.Enumeration<java.lang.String> getAttributeNames(): devuelve una colección
con los nombres de todos los atributos de la petición.
 java.lang.Object getAttribute(java.lang.String name): devuelve el valor de un atributo
concreto de la petición.
 java.util.Enumeration<java.lang.String> getHeaderNames(): devuelve una colección
con los nombres de todas las cabeceras HTTP enviadas en la petición.
 java.lang.String getHeader(java.lang.String name): devuelve el valor de una cabecera
HTTP concreta de la petición.
 java.lang.String getContextPath(): devuelve la porción de URL de la petición que
corresponde al ContextPath. El ContextPath es el identificador que utiliza el Servidor
de aplicaciones Java EE para diferenciar una aplicación u otra. Siempre va en la URL
por delante del recurso pedido como tal.
Existen muchos métodos más, algunos muy importantes para el manejo de la Sesión HTTP
y de las Cookies (los veremos en la siguiente unidad), para redireccionar la petición a otro
java Servlet o JavaServer Page (también los veremos en una unidad posterior) y otros
88
MÓDULO B – Unidad 4: Java Servlets
muchos para acceder a más información disponible en una petición HTTP que podemos ver
en el siguiente ejemplo:
package es.aulamentor; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RequestServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ContextPath: " + request.getContextPath()); System.out.println("LocalAddr: " + request.getLocalAddr()); System.out.println("LocalName: " + request.getLocalName()); System.out.println("LocalPort: " + request.getLocalPort()); System.out.println("Method: " + request.getMethod()); System.out.println("Protocol: " + request.getProtocol()); System.out.println("QueryString :" + request.getQueryString()); System.out.println("RemoteAddr :" + request.getRemoteAddr()); System.out.println("RemoteHost :" + request.getRemoteHost()); System.out.println("RemotePort :" + request.getRemotePort()); System.out.println(); Enumeration<String> headers = request.getHeaderNames(); while(headers.hasMoreElements()) { String header = headers.nextElement(); System.out.println(header + ": " + request.getHeader(header)); } System.out.println(); Enumeration<String> parameters = request.getParameterNames(); while(parameters.hasMoreElements()) { String parameter = parameters.nextElement(); System.out.println(parameter + ": " + request.getParameter(parameter)); } } } Y el descriptor de despliegue:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>RequestServlet</servlet‐name> <servlet‐class>es.aulamentor.RequestServlet</servlet‐class> </servlet> <servlet‐mapping> 89
<servlet‐name>RequestServlet</servlet‐name> <url‐pattern>/RequestServlet</url‐pattern> </servlet‐mapping> </web‐app> Si en el navegador utilizamos la siguiente URL para invocar el Java Servlet:
http://localhost:8080/EjemplosWeb/RequestServlet?param1=valor1&param2=valor2
Nota: Fijaros, que hemos añadido dos parámetros en la URL.
En la consola del Servidor de Aplicaciones Java EE deberíamos ver algo como esto (en cada
caso dependerá un poco del entorno utilizado):
En el API Java EE, están detallados todos los métodos:
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
javax.servlet.http.HttpServletResponse, es un interfaz que define cómo trabajar y generar la
respuesta HTTP desde el Java Servlet, como por ejemplo, acceder al stream de escritura,
especificar el tipo y longitud del contenido, etc…
Algunos métodos son:
 java.io.PrintWriter getWriter() throws java.io.IOException: nos devuelve una referencia
al objeto de escritura en modo carácter de la respuesta, a través del cual escribiremos.
 ServletOutputStream getOutputStream() throws java.io.IOException: nos devuelve una
referencia al objeto de escritura en modo byte de la respuesta, a través del cual
escribiremos. La diferencia con el anterior es el modo de escritura: carácter o byte.
90
MÓDULO B – Unidad 4: Java Servlets
 void setContentType(java.lang.String type): nos sirve para especificar el tipo de
contenido que vamos a enviar en la respuesta. Por ejemplo: text/html, text/plain,
image/gif, etc… Los distintos tipos de contenido están estandarizados a través de las
especificaciones MIME (Multipurpose Internet Mail Extensions). En la siguiente URL
están documentados todos los posibles tipos:
http://www.iana.org/assignments/media-types/index.html
Recordemos de la tercera unidad de este manual, cuando hablábamos del protocolo
HTTP, que esta era una información que viajaba en la cabecera de una respuesta
HTTP. Los siguientes métodos, también sirven para añadir información específica de
una respuesta HTTP.
 void setContentLength(int len): nos sirve para especificar la longitud del cuerpo de la
respuesta
 void setStatus(int sc): nos sirve para devolver un código de estado HTTP.
 void sendError(int sc, java.lang.String msg) throws java.io.IOException: nos sirve para
devolver un código de error HTTP junto con un mensaje descriptivo.
Existen muchos métodos más, algunos muy importantes para el manejo de las Cookies (los
veremos en la siguiente unidad).
Veamos un ejemplo:
package es.aulamentor; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ResponseServlet extends HttpServlet { private byte[] buffer = new byte[0]; public void init(ServletConfig config) throws ServletException { try { File file = new File("C:\\images\\duke.gif"); FileInputStream in = new FileInputStream(file); buffer = new byte[(int)file.length()]; in.read(buffer); in.close(); } catch(FileNotFoundException ex) 91
{ ex.printStackTrace(); } catch(IOException ex) { ex.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("image/gif"); response.setContentLength(buffer.length); response.getOutputStream().write(buffer); response.setStatus(200); } } Y el descriptor de despliegue:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>ResponseServlet</servlet‐name> <servlet‐class>es.aulamentor. ResponseServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>ResponseServlet</servlet‐name> <url‐pattern>/ResponseServlet</url‐pattern> </servlet‐mapping> </web‐app> Si en el navegador utilizamos la siguiente URL para invocar el Java Servlet:
http://localhost:8080/EjemplosWeb/ResponseServlet
En el navegador deberíamos ver la imagen que hemos utilizado en el ejemplo
En el API Java EE, están detallados todos los métodos:
92
MÓDULO B – Unidad 4: Java Servlets
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html
4.3.3 Procesamiento de un formulario HTML
Hasta ahora, todos los ejemplos no han tenido interacción real con el usuario. Vamos a ver
cómo sería un Java Servlet que procese una información recogida a través de un formulario
HTML. Por ejemplo, una calculadora muy sencilla que simplemente sume dos números.
Tendremos la siguiente página HTML:
<!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐
8859‐1"> <TITLE>Calculadora</TITLE> </HEAD> <BODY> <FORM method="POST" action="/EjemplosWeb/SumadorServlet"> <TABLE border="0"> <TR> <TD>Primer número:</TD> <TD><INPUT name="param1"></TD> </TR> <TR> <TD>Segundo número:</TD> <TD><INPUT name="param2"></TD> </TR> <TR> <TD><INPUT type="submit" value="Sumar"></TD> </TR> </TABLE> </FORM> </BODY> </HTML> Y el siguiente Java Servlet:
package es.aulamentor; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SumadorServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { procesarPeticion(request, response); } 93
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { procesarPeticion(request, response); } private void procesarPeticion(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF‐8"); try { int param1 = Integer.parseInt(request.getParameter("param1")); int param2 = Integer.parseInt(request.getParameter("param2")); int result = param1 + param2; response.setStatus(200); PrintWriter out = response.getWriter(); out.println(""); out.println("<!DOCTYPE HTML PUBLIC \"‐//W3C//DTD HTML 4.01 Transitional//EN\">"); out.println("<HTML>"); out.println(" <HEAD>"); out.println(" <TITLE>Calculadora</TITLE>"); out.println(" </HEAD>"); out.println(" <BODY>"); out.println(" El resultado de la suma es: " + result); out.println(" <BR><BR>"); out.println(" <A href=\"/EjemplosWeb/calculadora.html\">Volver atrás...</A>"); out.println(" </BODY>"); out.println("</HTML>"); } catch(NumberFormatException ex) { response.sendError(500, "Alguno de los números no contenía dígitos válidos..."); } } } Nota: Recordar que los contenidos estáticos como una página HTML se ubican dentro del
directorio /WebContent.
Al cargar la página en el navegador, deberíamos ver algo así:
94
MÓDULO B – Unidad 4: Java Servlets
Al introducir los números 2 y 8 y pulsar el botón de Sumar, desde el navegador se lanzará
una petición HTTP al Servidor de Aplicaciones Java EE pidiendo la ejecución del Java
Servlet (que está en el mismo servidor que el HTML) con dichos parámetros y en el
navegador, deberíamos ver algo así:
En caso de que no hubiéramos introducido algún parámetro, o alguno de ellos llevase algún
carácter que no fuese un dígito, deberíamos ver una página de error parecida a esta:
95
En la siguiente unidad, hablaremos un poco mas del tratamiento de errores. En este ejemplo,
hemos optado por mostrar una página de error HTTP, pero podríamos perfectamente haber
contestado una página HTML al estilo de la que mostraba el resultado correcto, indicando
los motivos del error.
Aprovechando este ejemplo, vamos a comentar otro tema interesante. En la unidad donde
tratamos el protocolo HTTP, comentamos que la diferencia entre los métodos HTTP GET y
POST era que uno enviaba los parámetros en la URL (GET) y otro en el cuerpo del mensaje
HTTP (POST). En este ejemplo, hemos utilizado el método POST, pero fijaros lo que
veríamos en la URL del navegador si en vez de POST hubiéramos utilizado GET:
http://localhost:8080/EjemplosWeb/SumadorServlet?param1=2&param2=8
Por eso comentábamos, que lo habitual cuando se utilizan formularios es emplear el método
POST para evitar mostrar al usuario URLs farragosas, además de que por temas de
seguridad, se intente evitar que se lea en claro una contraseña (por ejemplo).
96
MÓDULO B – Unidad 4: Java Servlets
4.3.4 Empaquetado y despliegue
Como comentábamos en la primera unidad de este curso de introducción al Java EE, una
aplicación Java EE está formada por un empaquetamiento de una o varias unidades
conocidas con el nombre de módulos. Este empaquetamiento final era un EAR (Enterprise
ARchive).
Uno de los distintos tipos de módulos mencionados son los módulos Web, que contienen
normalmente Java Servlets, JavaServer Pages (JSP), JavaServer Faces (JSF), contenidos
estáticos como imágenes, HTMLs, CSSs… Su extensión del fichero empaquetado es WAR
(Web ARchive).
En este curso, nos vamos a centrar exclusivamente de este tipo de módulos, ya que
intentamos cubrir solo la parte web de la programación Java EE y no el resto de aspectos
que darían lugar a un curso demasiado extenso o a un segundo curso.
A pesar de que las aplicaciones Java EE se empaquetan en un EAR, los Servidores de
Aplicación que solo cubren parte de la especificación Java EE, como ocurre con Apache
Tomcat, permiten desplegar simplemente módulos Web aislados. Este será nuestro caso
durante este curso.
Gráficamente, la estructura de un módulo Web empaquetado sería la siguiente:
Como podemos observar, tiene bastante parecido a la estructura del proyecto web dentro
de Eclipse IDE for Java EE Developers aunque no es igual. En principio, el raíz del fichero
97
WAR correspondería al directorio /WebContent y el directorio /classes del fichero WAR
correspondería al directorio /build/classes.
Ahora bien, normalmente no nos preocuparemos mucho de la generación de un módulo
Web u otro tipo de módulo, porque son los IDEs los que nos van a ayudar a generarlo. Por
ejemplo, en nuestro caso, con Eclipse IDE for Java EE Developers basta con seleccionar el
proyecto, pulsar el botón derecho del ratón y seleccionar las opciones “Export” -> “WAR
file”:
98
MÓDULO B – Unidad 4: Java Servlets
En la siguiente ventana, nos aseguramos que el proyecto seleccionado es el correcto, y
decidimos donde y con que nombre se va a generar el fichero WAR, por ejemplo,
“C:\EjemplosWeb.war”. Pulsar el botón “Finish”:
Si vamos a una sesión de DOS, mediante el comando de la JDK jar.exe (jar tvf
nombreFichero.war), podemos ver su contenido y confirmar que la estructura generada es
exactamente la de la especificación Java EE:
99
Este fichero WAR, sería el que un administrador de Servidores de Aplicación Java EE
desplegaría y configuraría para que la aplicación estuviese disponible y dando servicio. Pero
en nuestro caso, simplemente añadiremos o quitaremos aplicaciones en el Apache Tomcat
de Eclipse IDE for Java EE Developers mediante el interfaz de usuario: botón derecho del
ratón y la opción “Add and Remove…”, o directamente sobre el componente y “Run As” ->
“Run on Server”.
Nos queda no obstante hablar un poco sobre el descriptor de despliegue. Como ya
adelantábamos en la primera unidad, se trata de un fichero XML donde se describe el
contenido y posible comportamiento del contenido del módulo.
En el caso concreto de los módulos Web, su descriptor de despliegue es el fichero web.xml
A lo largo de esta unidad, hemos visto en los ejemplos algunas etiquetas, pero ahora
hablaremos un poco más despacio de algunas de ellas:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>SumadorServlet</servlet‐name> <servlet‐class>es.aulamentor.SumadorServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>SumadorServlet</servlet‐name> <url‐pattern>/SumadorServlet</url‐pattern> </servlet‐mapping> </web‐app> La primera línea es obligatoria, y simplemente indica que el fichero es XML 1.0
Después, viene el bloque “web-app” que es el que delimita el contenido del descriptor de
despliegue del módulo Web. En la etiqueta de inicio, se añaden una serie de atributos entre
los cuales está la ubicación del esquema XML que contiene la especificación utilizada:
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
Los bloques “servlet” y “servlet-mapping” son más interesantes. Sirven para registrar los
Java Servlets que hay en el módulo Web, y especificar la URL para cada uno de ellos. Por
ejemplo, en el descriptor de despliegue que hemos usado, decimos que hay un Java Servlet
que
llamamos
SumadorServlet
que
está
implementado
en
la
clase
Java
es.aulamentor.SumadorServlet y que su URL es /SumadorServlet.
Si no tuviéramos esos dos bloques en el descriptor de despliegue, el Servidor de
Aplicaciones Java EE nos devolvería un error HTTP 404 que significaba que el recurso
solicitado no existe. Veamos el error visualmente:
100
MÓDULO B – Unidad 4: Java Servlets
Aunque el Java Servlet vaya en el módulo Web, si no está especificado en el descriptor de
despliegue, el Servidor de Aplicaciones Java EE no lo sabe identificar.
Existen muchas más etiquetas a utilizar en un descriptor de despliegue de un módulo Web,
pero las iremos viendo a lo largo del curso según las vayamos necesitando. De momento
nos quedamos con la general “web-app” y las necesarias para registrar e identificar un Java
Servlet.
No obstante, muchos recordaréis que en la primera unidad comentábamos que con la última
especificación Java EE, había aparecido la opción de obviar los descriptores de despliegue
a cambio de anotar el código fuente con unas anotaciones especiales. Esta es otra opción,
en cuyo caso no hace falta ni tener físicamente el fichero web.xml
Una anotación se identifica precediéndola del carácter @ (arroba) y acompaña a la definición
de una clase, de un atributo o de un método Java. Al igual que ocurre con las etiquetas del
descriptor de despliegue, hay muchas anotaciones, pero las iremos viendo poco a poco a lo
largo del curso.
De momento, para sustituir a los bloques “servlet” y “servlet-mapping” que como hemos
visto registran y definen un Java Servlet, existe la anotación:
@WebServlet
Que puede añadir atributos entre paréntesis para complementar si definición.
En nuestro caso, el código fuente Java de nuestro Java Servlet sería algo así:
.... import javax.servlet.annotation.WebServlet; .... @WebServlet(name="SumadorServlet", urlPatterns={"/SumadorServlet"}) public class SumadorServlet extends HttpServlet { .... } Mediante la anotación, al desplegar el módulo Web en el Servidor de Aplicaciones Java EE,
estamos registrando un Java Servlet que se llama SumadorServlet, cuya URL es
/SumadorServlet.
101
Todos los posibles atributos de la anotación @WebServlet están en el API:
http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebServlet.html
Si nuestro Java Servlet está desarrollado haciendo uso de la anotación, entonces no hace
falta que lo registremos en el descriptor de despliegue. Incluso, si el descriptor de
despliegue solo llevaba esa información, podemos prescindir de él.
Ambas dos opciones pueden convivir en un mismo módulo Web, es decir, podemos
describir algunas cosas en el descriptor de despliegue, y otras mediante anotaciones,
aunque normalmente no es una buena práctica el mezclar las dos opciones. Normalmente
se utiliza una u otra.
¿Y cuál es mejor utilizar? Pues depende. Normalmente los desarrolladores prefieren las
anotaciones porque les es más rápido el desarrollo, pero los administradores de sistemas
prefieren los descriptores de despliegue porque les permite entender el contenido de un
módulo web sin necesidad de saber interpretar código fuente (código fuente que en
ocasiones no tienen a su disposición debido a que solo reciben los bytecodes de las clases
Java).
A lo largo del curso, iremos explicando siempre ambas dos opciones.
102
RECORDAR
 Los Java Servlets son un tipo de componente Java EE que se empaquetan en un
módulo web (WAR) y se despliegan y ejecutan en el contenedor web de un Servidor
de Aplicaciones Java EE.
 Adicionalmente, dentro del patrón de diseño MVC ocupan el espacio del
Controlador, como receptor/validador de peticiones, seleccionador de la lógica a
ejecutar, y seleccionador de la vista a presentar como resultado
 Los Java Servlets siempre deben de implementar la interface javax.servlet.Servlet
o heredar de la clase javax.servlet.http.HttpServlet.
 El ciclo de vida viene determinado por los siguientes métodos
 init: se ejecuta una vez en la vida del Java Servlet y se suele utilizar para llevar a
cabo todas las labores de inicialización que necesitemos para su posterior
ejecución.
 service: se ejecuta cada vez que se recibe una petición para el Java Servlet. En
su implementación, se coloca la lógica para la que se creó. Si se ha heredado de
la clase javax.servlet.http.HttpServlet, se utilizan los métodos doGet o doPost.

destroy: se ejecuta una vez en la vida del Java Servlet y se suele utilizar para
liberar todos aquellos recursos que pudiéramos haber utilizado, con el afán de
dejar el sistema lo más limpio posible.
 Los
objetos
de
los
tipos
javax.servlet.http.HttpServletRequest
y
javax.servlet.http.HttpServletResponse. que reciben los métodos doGet y
doPost, se utilizan para identificar la petición realizada y la respuesta dada.
Contienen métodos para obtener de la petición parámetros, atributos, cabeceras …
poner en la respuesta la respuesta en si misma, su longitud, el estado de la petición
…
103
 Hemos aprendido que la principal diferencia entre las peticiones GET y POST es
que en las primeras el paso de parámetros es apreciable en la URL. Para poder
utilizar el POST, se utilizan los formularios (FORM) de HTML.
 Para poder desplegar una aplicación web, se puede realizar mediante un EAR o un
WAR (dependiendo del servidor de aplicaciones). El descriptor de despliegue
web.xml, aunque no es obligatorio si se utilizan anotaciones, conviene que exista
para poder determinar de una manera sencilla que es lo que se va a desplegar y el
comportamiento asociado.
104
Unidad de Aprendizaje 5
JAVASERVER PAGES
ÍNDICE
5.1
Introducción ................................................................. 107
5.2
Mi primer JavaServer Page ........................................ 108
5.3
JavaServer Pages ........................................................ 118
5.3.1 Etiqueta de comentario................................................119
5.3.2 Etiqueta de directiva.....................................................119
5.3.3 Etiqueta de declaración ...............................................120
5.3.4 Etiqueta de scriptlets ...................................................121
5.3.5 Etiqueta de expresión ..................................................122
5.3.6 Ejemplo con todas las etiquetas ................................123
5.4
Otros conceptos .......................................................... 127
5.4.1 El ciclo de vida de un JavaServer Page ....................127
5.4.2 Objetos implícitos de un JavaServer Page...............128
5.4.3 Empaquetado y despliegue ........................................129
PARA RECORDAR.................................................................. 134
MÓDULO B – Unidad 5: JavaServer Pages
5.1
Introducción
Ya vimos en la primera unidad del curso, que los JavaServer Pages, también conocidos por su
acrónimo JSP, eran un tipo de componente Java EE que se empaquetaba en un módulo web
(WAR) y se desplegaba y ejecutaba en el contenedor web de un Servidor de Aplicaciones Java
EE.
Adicionalmente, dentro del patrón de diseño MVC ocupaban el espacio de la Vista, como
encargado de mostrar el resultado de la petición al usuario final. Es decir, al contrario que los
Java Servlets, estas están enfocadas a la presentación.
No obstante, de momento, va a cubrir completamente todas las responsabilidades del MVC.
Y según vayamos avanzando en el curso, le iremos quitando responsabilidades que no
debieran ser del JavaServer Page, para dárselas a otro tipo de componente como los Java
Servlets.
Repetimos, esto es un mal diseño y una mala práctica de programación. Pero consideramos
que es imprescindible ir aprendiendo poco a poco. Por tanto, este diseño es temporal
mientras avanzamos en las sucesivas unidades del curso.
107
Por último, desde un punto de vista del lenguaje de programación Java, una JavaServer Page
no es más que un fichero con un lenguaje de etiquetado como HTML y trozos de código Java
embebidos.
5.2
Mi primer JavaServer Page
Antes de entrar a estudiar en profundidad los JavaServer Pages, vamos a guiar los pasos para
desarrollar nuestro primer JavaServer Page con Eclipse IDE for Java EE Developers y
desplegarlo en Apache Tomcat. Es requisito indispensable, haber seguido los pasos de
instalación y configuración de ambas dos herramientas detallados en la unidad 2 de este
curso.
Estos mismos pasos nos servirán para los sucesivos ejemplos y actividades del resto del
curso.
Arrancamos Eclipse IDE for Java EE Developers y mediante el las opciones de menú “File” ->
“New” -> “Dynamic Web Project”:
108
MÓDULO B – Unidad 5: JavaServer Pages
Creamos la estructura de desarrollo de un módulo web (WAR). Como nombre del proyecto,
pondremos “HolaMundoWeb”, y nos aseguraremos que seleccionamos “Apache Tomcat v7.0”
como entrono de ejecución y “3.0” como el nivel de especificaciones Java EE (en cuanto a
contenedor web) que queremos utilizar. Pulsamos el botón “Next” dos veces:
En la última ventana del asistente, antes de pulsar el botón “Finish”, nos aseguramos de
marcar la opción “Generate web.xml deployment descriptor”:
109
La estructura del proyecto creado debería ser algo así:
110
MÓDULO B – Unidad 5: JavaServer Pages
En el directorio /Java Resources/src es donde iremos colocando el código fuente de nuestras
clases Java.
En el directorio /WebContent es donde iremos colocando los recursos web, como por
ejemplo, las páginas HTML, las JavaServer Pages, imágenes, etc…
Y el fichero web.xml de /WebContent/WEB-INF es el descriptor de despliegue del módulo web
(en nuestro caso, del proyecto HolaMundoWeb).
Ahora crearemos un JavaServer Page. Botón derecho sobre el nuevo proyecto -> “New” ->
“JSP File”:
111
En la siguiente ventana, rellenamos el nombre del fichero (File name) con “HolaMundo.jsp”.
Nos aseguraremos de que el directorio donde se va a crear sea /WebContent (normalmente se
selecciona por defecto). Y pulsamos el botón “Finish”:
112
MÓDULO B – Unidad 5: JavaServer Pages
Escribimos el siguiente código y salvamos:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Hola Mundo!</TITLE> </HEAD> <BODY> Hola Mundo! </BODY> </HTML> No nos preocupemos en este momento por no entender el código. De momento, simplemente
queremos mostrar los pasos para el desarrollo y despliegue de un JavaServer Page. En los
sucesivos apartados iremos entendiendo el por qué de cada línea.
113
Ya solo queda, probar la aplicación. Para ello, pulsamos el botón derecho sobre el fichero JSP
-> “Run As” -> “Run on Server”:
En la siguiente ventana, seleccionar “Tomcat v7.0 Server at localhost” y pulsar el botón
“Finish”:
114
MÓDULO B – Unidad 5: JavaServer Pages
En la vista de “Console” veremos las trazas que va dejando el Servidor de Aplicaciones Java
EE al arrancar, cómo despliega la aplicación y automáticamente abre un navegador interno de
Eclipse IDE con la URL: http://localhost:8080/HolaMundoWeb/HolaMundo.jsp donde se ve el
resultado de nuestro primer JavaServer Page:
115
Perfectamente podríamos utilizar otro navegador web (tipo Mozilla Firefox o Internet Explorer)
y escribir la misma URL. El comportamiento debería ser el mismo.
Para abrir el navegador interno de Eclipse IDE a mano, utilizar el botón de la barra de
herramientas:
Ya solo nos queda desinstalar la aplicación mediante la opción “Add and Remove…”:
116
MÓDULO B – Unidad 5: JavaServer Pages
Y apagar el servidor mediante la opción “Stop”:
117
5.3
JavaServer Pages
Una JavaServer Page, es un fichero de extensión *.jsp que utiliza principalmente lenguajes de
etiquetado como el HTML (estudiado en la unidad 3) u otros menos extendidos como WML,
SVG, cHTML, etc, en el que se pueden embeber mediante unas etiquetas especiales, código
Java.
Es decir, vendrían a ser como el opuesto de los Java Servlets. Si aquellos eran código Java
con código de etiquetado embebido en las sentencias de escritura, estas son código de
etiquetado con código Java embebido.
A la hora de su ejecución, el Servidor Java EE convertirá estos ficheros en un Java Servlet
como los estudiados en la unidad anterior. Es decir, generará de forma automática, un Java
Servlet en el que incluirá todos los fragmentos de Java embebidos, y añadirá sentencias de
impresión con el lenguaje de etiquetado de presentación estático.
Aunque como decimos, este proceso ocurre a sin conocimiento directo del desarrollador y lo
realiza automáticamente el Servidor de Aplicaciones Java EE, siempre va bien tenerlo en
118
MÓDULO B – Unidad 5: JavaServer Pages
cuenta para entender correctamente el significado de las etiquetas específicas de las
JavaServer Pages.
Existen unas cuantas etiquetas específicas de las JavaServer Pages, que nada tienen que ver
con el lenguaje de etiquetado que se esté utilizando para la presentación, y son las que
estudiaremos a continuación como parte de la sintaxis.
5.3.1 Etiqueta de comentario
Los comentarios en una JavaServer Page se añaden delimitados por las siguientes dos
etiquetas de inicio y fin:
<%-- Comentario --%>
Dichos comentarios, no se envían como parte de la respuesta desde el Servidor Java EE. Es
decir, no es información que viaje por la red y por tanto no afectan al volumen de
información transferido.
Veamos un ejemplo:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Hola Mundo!</TITLE> </HEAD> <BODY> <%‐‐ Mi primera página JSP ‐‐%> Hola Mundo! </BODY> </HTML> Al ejecutar el ejemplo, en el navegador no veréis nada distinto. Y si al navegador se le pide
ver el código fuente de la página HTML que ha cargado, tampoco veréis ninguna de las
etiquetas relacionadas con las JavaServer Pages.
5.3.2 Etiqueta de directiva
Las etiquetas de directiva siguen la siguiente sintaxis:
<%@ directiva [atributo=”valor”] %>
Existen tres tipos de directivas. De hecho, en los ejemplos anteriores ya hemos utilizado una
de ellas: page, como primera línea de la JavaServer Page.
Los tres tipos son:
119
 page: añade información técnica a la página utilizada por el Servidor de Aplicaciones
Java EE para su posterior conversión a un Java Servlet.
Puede utilizar múltiples atributos, pero los más extendidos e importantes son:
o contentType: para identificar el contenido.
o pageEncoding: para identificar el juego de caracteres utilizado.
o import: fundamental para poder importar las clases Java utilizadas en los
trozos de código java embebido y poder compilar correctamente.
o Otras como errorPage, isThreadSafe o session, que veremos en siguientes
unidades.
Veamos un ejemplo:
<%@ page contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1" %> <%@ page import="java.util.Date, es.aulamentor.*" %>  include: se utiliza para incluir en ese punto el resultado de la ejecución de otra
JavaServer Page. Dichas JavaServer Pages suelen ser fragmentos de una
presentación, por ejemplo, una cabecera, un mensaje de copyright, etc. Es muy útil
para reutilizar código y no tener que escribirlo n veces, además de facilitar su posterior
mantenimiento.
Utiliza un único atributo que es “file”, para identificar la JavaServer Page a incluir.
Veamos un ejemplo:
<%@ include file="cabecera.jsp” %>  taglib: se utiliza para definir una librería de etiquetas (tags) propia que se va a utilizar
en la JavaServer Page. La estudiaremos en siguientes unidades.
No obstante, veamos un ejemplo:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 5.3.3 Etiqueta de declaración
En una JavaServer Page, es posible definir atributos y métodos, como si de una clase Java
se tratase, que serán accesibles desde toda la JavaServer Page.
Dichas declaraciones se realizan mediante las etiquetas:
<%! … %>
Por ejemplo, si queremos definir un atributo de tipo java.lang.String con el valor “Hola
Mundo!” lo haríamos así:
120
MÓDULO B – Unidad 5: JavaServer Pages
<%! String var = “Hola Mundo!” %> El Servidor de Aplicaciones Java EE, al generar el Java Servlet añadiría dicha variable como
un atributo en la clase Java generada.
Si lo que queremos es definir un método que sume dos números, por ejemplo, lo haríamos
así:
<%! public int suma(int param1, int param2) { return param1 + param2; } %> El Servidor de Aplicaciones Java EE, al generar el Java Servlet, añadiría dicha definición
como un método en la clase Java generada.
Nota: es muy importante en este punto, tener en cuenta que este tipo de aplicaciones Java
EE son multiusuario y por tanto multitarea. Es decir, se producen n ejecuciones paralelas del
mismo código y por tanto el uso de los atributos o variables de instancia pueden ser
“peligrosos” y producir efectos no deseados. Asumimos que el lector es conocedor de las
problemáticas asociadas a la programación concurrente tratadas en el Curso de Aula Mentor
“Programación en Java – Avanzado”. No obstante, volveremos de nuevo a este tema en las
siguientes unidades.
5.3.4 Etiqueta de scriptlets
Los scriptles son las porciones de código Java embebidos en la JavaServer Page.
Utilizan las siguientes etiquetas:
<% … %>
Por ejemplo:
<% String var = “Hola Mundo!”; %> Seguramente, os estaréis preguntando si esto no es lo mismo que la etiqueta de declaración
que vimos antes. La respuesta es no. La declaración, creaba un atributo, es decir, una
variable de instancia. Sin embargo, en este caso de ahora, al usar un scriptlet, se trata de
una variable local. Pero variable local, ¿de qué método?
Como ya hemos comentado varias veces, el Servidor de Aplicaciones Java EE
automáticamente convierte la JavaServer Page en un Java Servlet. Y por tanto, tendrá un
método service() como ya vimos en la unidad anterior dedicada a los Java Servlets.
Pues bien, todo el etiquetado de presentación de la JavaServer Page, así como los
scriptlets, son incluidos en el método service() del Java Servlet autogenerado. Es por tanto
en dicho método donde se crea la variable local de nuestro último ejemplo.
121
Un uso habitual de los scriptlets que dota de gran potencia y dinamismo a las JavaServer
Pages, es su integración con el etiquetado de presentación. Por ejemplo:
<% if(sexo.equals(“Hombre”)) { %> <H1>Buenos días señor</H1> <% } else { %> <H1>Buenos días señora</H1> <% } %> Como podemos observar, hemos conseguido dotar de dinamismo al lenguaje HTML que por
su naturaleza es estático. Dependiendo del valor de una variable, la etiqueta HTML que se
envía al cliente como parte de la respuesta es una u otra.
Igual que hemos utilizado una bifurcación, pensad en la flexibilidad que nos da poder usar
también un bucle para alimentar listas o tablas de forma dinámica.
5.3.5 Etiqueta de expresión
Este es el último tipo de etiquetas específicas de la tecnología JavaServer Page.
Este tipo lo que permite es devolver un valor de una variable o un método e insertarlo como
parte de la respuesta.
La sintaxis de la etiqueta es así:
<%= … %>
Por ejemplo:
<H1>El resultado de sumar 2 + 2 es: <%= 2 + 2 %>.</H1> O por ejemplo:
La hora actual es: <%= Calendar.getInstance().getTime() %>. Es importante fijarse, que la expresión Java no se termina con el signo de punto y coma (;)
como se hace habitualmente. Evidentemente, no se pueden encadenar expresiones, solo se
permite una.
El Servidor de Aplicaciones Java EE, incluirá en el Java Servlet autogenerado el mix de
código estático y código dinámico como ya aprendimos a hacerlo en la unidad de Java
Servlets.
122
MÓDULO B – Unidad 5: JavaServer Pages
5.3.6 Ejemplo con todas las etiquetas
Vemos un ejemplo completo con todos los tipos de etiquetas en funcionamiento:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1" %> <%@ page import="java.util.Calendar" %> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Calculadora</TITLE> </HEAD> <BODY> <%‐‐ Método para sumar dos números enteros ‐‐%> <%! public int sumar(int param1, int param2) { return param1 + param2; } %> <% if(request.getParameter("switch") == null) { %> <FORM method="POST" action="/EjemplosWeb/calculadora.jsp" > <INPUT type="hidden" name="switch" value="true"> <TABLE border="0"> <TR> <TD>Primer número:</TD> <TD><INPUT name="param1"></TD> </TR> <TR> <TD>Segundo número:</TD> <TD><INPUT name="param2"></TD> </TR> <TR> <TD><INPUT type="submit" value="Sumar"></TD> </TR> </TABLE> </FORM> <% } else { try { int param1 = Integer.parseInt(request.getParameter("param1")); int param2 = Integer.parseInt(request.getParameter("param2")); int result = param1 + param2; %> El resultado de la suma es: <%= sumar(param1, param2) %><BR><BR> <% } catch(NumberFormatException ex) { %> 123
Alguno de los números no contenía dígitos válidos...<BR><BR> <% } %> <%= Calendar.getInstance().getTime() %><BR><BR> <A href="/EjemplosWeb/calculadora.jsp">Volver atrás...</A> <% } %> </BODY> </HTML> Si analizamos detenidamente el ejemplo, podemos observar el uso de los distintos tipos de
etiquetado:
 Directivas para definir algunos aspectos técnicos de la JavaServer Page, así como
añadir imports necesarios para la correcta compilación.
 Comentarios para documentar el objetivo del método sumar.
 Declaraciones para definir el método sumar.
 Scriptlets para implementar la lógica de control.
 Expresiones para devolver los valores calculados.
Evidentemente se trata de un ejemplo, donde hemos intentado utilizar el 100% de los
conceptos expuestos. No quiere decir que la mejor solución implique utilizarlos todos.
Por cierto, algún lector se habrá dado cuenta de la utilización de un objeto “request” sin
haberlo mencionado ni definido en ningún sitio. Las JavaServer Pages cuentan con una serie
de objetos implícitos accesibles desde cualquier punto de la página. Los comentaremos en
la siguiente sección.
Adicionalmente, y simplemente a modo ilustrativo, adjuntamos el código fuente del Java
Servlet que el Servidor de Aplicaciones Java EE habría generado para la JavaServer Page de
ejemplo. Como decimos, es puramente a modo ilustrativo, por si puede ayudar a entender
los conceptos explicados. Recordar que la generación y compilación de este Java Servlet es
algo automático e intrínseco del Servidor de Aplicaciones Java EE:
/* * Generated by the Jasper component of Apache Tomcat * Version: Apache Tomcat/7.0.22 * Generated at: 2012‐02‐17 12:25:10 UTC * Note: The last modified time of this file was set to * the last modified time of the source file after * generation to assist with modification tracking. */ package org.apache.jsp; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import java.util.Calendar; 124
MÓDULO B – Unidad 5: JavaServer Pages
public final class calculadora_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent { public int sumar(int param1, int param2) { return param1 + param2; } private static final javax.servlet.jsp.JspFactory _jspxFactory = javax.servlet.jsp.JspFactory.getDefaultFactory(); private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants; private javax.el.ExpressionFactory _el_expressionfactory; private org.apache.tomcat.InstanceManager _jsp_instancemanager; public java.util.Map<java.lang.String,java.lang.Long> getDependants() { return _jspx_dependants; } public void _jspInit() { _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletCon
text()).getExpressionFactory(); _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(ge
tServletConfig()); } public void _jspDestroy() { } public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException { final javax.servlet.jsp.PageContext pageContext; javax.servlet.http.HttpSession session = null; final javax.servlet.ServletContext application; final javax.servlet.ServletConfig config; javax.servlet.jsp.JspWriter out = null; final java.lang.Object page = this; javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null; try { response.setContentType("text/html; charset=ISO‐8859‐1"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write("\r\n"); out.write("\r\n"); 125
out.write("<!DOCTYPE html PUBLIC \"‐//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n"); out.write("<HTML>\r\n"); out.write(" <HEAD>\r\n"); out.write(" <META http‐equiv=\"Content‐Type\" content=\"text/html; charset=ISO‐8859‐1\">\r\n"); out.write(" <TITLE>Calculadora</TITLE>\r\n"); out.write(" </HEAD>\r\n"); out.write(" <BODY>\r\n"); out.write(" "); out.write("\r\n"); out.write(" "); out.write("\r\n"); out.write(" \t"); if(request.getParameter("switch") == null) { out.write("\r\n"); out.write("\t<FORM method=\"POST\" action=\"/EjemplosWeb/calculadora.jsp\" >\r\n"); out.write("\t\t<INPUT type=\"hidden\" name=\"switch\" value=\"true\">\r\n"); out.write("\t\t<TABLE border=\"0\">\r\n"); out.write("\t\t\t<TR>\r\n"); out.write("\t\t\t\t<TD>Primer número:</TD>\r\n"); out.write("\t\t\t\t<TD><INPUT name=\"param1\"></TD>\r\n"); out.write("\t\t\t</TR>\r\n"); out.write("\t\t\t<TR>\r\n"); out.write("\t\t\t\t<TD>Segundo número:</TD>\r\n"); out.write("\t\t\t\t<TD><INPUT name=\"param2\"></TD>\r\n"); out.write("\t\t\t</TR>\r\n"); out.write("\t\t\t<TR>\r\n"); out.write("\t\t\t\t<TD><INPUT type=\"submit\" value=\"Sumar\"></TD>\r\n"); out.write("\t\t\t</TR>\r\n"); out.write("\t\t</TABLE>\r\n"); out.write("\t</FORM>\r\n"); out.write("\t"); } else { try { int param1 = Integer.parseInt(request.getParameter("param1")); int param2 = Integer.parseInt(request.getParameter("param2")); out.write("\r\n"); out.write("\tEl resultado de la suma es: "); out.print( sumar(param1, param2) ); out.write("<BR><BR>\r\n"); out.write("\t"); } catch(NumberFormatException ex) { out.write("\r\n"); out.write("\tAlguno de los números no contenía dígitos válidos...<BR><BR>\r\n"); out.write("\t"); } out.write('\r'); out.write('\n'); 126
MÓDULO B – Unidad 5: JavaServer Pages
out.write(' '); out.print( Calendar.getInstance().getTime() ); out.write("<BR><BR>\r\n"); out.write("\t<A href=\"/EjemplosWeb/calculadora.jsp\">Volver atrás...</A>\r\n"); out.write("\t"); } out.write("\r\n"); out.write(" </BODY>\r\n"); out.write("</HTML>"); } catch (java.lang.Throwable t) { if (!(t instanceof javax.servlet.jsp.SkipPageException)){ out = _jspx_out; if (out != null && out.getBufferSize() != 0) try { out.clearBuffer(); } catch (java.io.IOException e) {} if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); } } finally { _jspxFactory.releasePageContext(_jspx_page_context); } } } Aunque hay muchas líneas de código que no son fáciles de interpretar a estas alturas del
curso, si que de un simple vistazo el alumno debería ser capaz de identificar los métodos
_jspInit(), _jspService() y _jspDestroy() que son invocados por los métodos del ciclo de vida
de los Java Servlets estudiados en la unidad anterior. Y si nos centramos en concreto en el
método _jspService(), se debería poder identificar fácilmente la lógica de control de nuestro
JavaServer Page, así como las impresiones del código estático HTML a la respuesta.
También se puede identificar al inicio, la declaración del método sumar() como parte del
Java Servlet generado.
5.4
Otros conceptos
En este apartado trataremos algunos otros conceptos relacionados con los JavaServer Pages
que ya hemos mencionado pero no hemos tratado con el suficiente detalle.
5.4.1 El ciclo de vida de un JavaServer Page
Al igual que ocurría con los Java Servlets, los JavaServer Pages también siguen un ciclo de
vida definido por el API de la especificación Java EE. En concreto el interface:
javax.servlet.jsp.HttpJspBase
Dicho ciclo de vida es el mismo que el de los Java Servlets ya que como hemos indicado en
varias ocasiones ya, los JavaServer Pages terminan siendo transformados por el Servidor de
Aplicaciones Java EE en un Java Servlet. La única diferencia radica en los nombres.
Los métodos del ciclo de vida de un JavaServer Page son:
127
 public void _jspInit();
 public _jspService(HttpServletRequest request, HttpServletResponse response);
 public void _jspDestroy();
Si quisiéramos sobrescribir el comportamiento de inicialización o finalización de un
JavaServer Page, deberíamos hacerlo redefiniendo el método en cuestión mediante las
etiquetas de declaración. Pero es raro tener que hacerlo.
El método _jspService por el contrario, no se sobrescribe nunca, porque ya hemos visto que
cualquier cosa que añadamos al JavaServer Page forma parte de él. Es decir, crear un
JavaServer Page implica siempre sobreescribir el método _jspService.
5.4.2 Objetos implícitos de un JavaServer Page
El contenedor Web de un Servidor de Aplicaciones Java EE, pone a disposición de los
desarrolladores de JavaServer Pages una serie de objetos implícitos sin necesidad de que
estos tengan que crearlos o buscarlos.
En el último ejemplo que vimos, utilizamos el objeto request que representa a la petición
HTTP recibida por el JavaServer Page sin necesidad de crearlo, o pedirlo. Directamente
existe y es utilizable.
Los objetos implícitos son:
 request: representa la petición HTTP y normalmente la utilizaremos para acceder a los
parámetros enviados desde el cliente.
 response: representa la respuesta HTTP.
 session: representa la sesión HTTP del usuario. Este tema lo veremos con mayor
profundidad en siguientes unidades.
 application: representa el contexto de la aplicación. Este tema lo veremos con mayor
profundidad en siguientes unidades.
 config: representa la configuración inicial que se ha hecho para este JavaServer Page.
Este tema lo veremos con mayor profundidad en siguientes unidades.
 page: representa la propia página. Sería lo mismo que usar la keyword de Java: this.
 exception: representa la excepción que se ha producido y que ha motivado que el
Servidor de Aplicaciones Java EE redirigiese la ejecución a esta página. Debe utilizar la
directiva “isErrorPage”. Si no se es una página definida como página de error, este
objeto no estará accesible.
 out: representa el writer de escritura de la respuesta HTTP. No suele ser habitual su
uso desde una JavaServer Page..
128
MÓDULO B – Unidad 5: JavaServer Pages
5.4.3 Empaquetado y despliegue
Como comentábamos en la primera unidad de este curso de introducción al Java EE, una
aplicación Java EE está formada por un empaquetamiento de una o varias unidades
conocidas con el nombre de módulos. Este empaquetamiento final era un EAR (Enterprise
ARchive).
Uno de esos módulos son los Web, que contienen normalmente Java Servlets, JavaServer
Pages (JSP), JavaServer Faces (JSF), contenidos estáticos como imágenes, HTMLs, CSSs…
Su extensión del fichero empaquetado es WAR (Web ARchive).
En este curso, nos vamos a centrar exclusivamente de este tipo de módulos, ya que
intentamos cubrir solo la parte web de la programación Java EE y no el resto de aspectos
que darían lugar a un curso demasiado extenso o a un segundo curso.
A pesar de que las aplicaciones Java EE se empaquetan en un EAR, los Servidores de
Aplicación que solo cubren parte de la especificación Java EE como ocurre con Apache
Tomcat, permiten desplegar simplemente módulos Web aislados. Este será nuestro caso
durante este curso.
Gráficamente, la estructura de un módulo Web empaquetado sería la siguiente:
Como podemos observar, tiene bastante parecido a la estructura del proyecto web dentro
de Eclipse IDE for Java EE Developers aunque no es igual. En principio, el raíz del fichero
WAR correspondería al directorio /WebContent y el directorio /classes del fichero WAR
correspondería al directorio /build/classes.
129
Ahora bien, normalmente no nos preocuparemos mucho de la generación de un módulo
Web u otro tipo de módulo, porque son los IDEs los que nos van a ayudar a generarlo. Por
ejemplo, en nuestro caso, con Eclipse IDE for Java EE Developers basta con seleccionar el
proyecto, pulsar el botón derecho del ratón y seleccionar las opciones “Export” -> “WAR
file”:
130
MÓDULO B – Unidad 5: JavaServer Pages
En la siguiente ventana, nos aseguramos que el proyecto seleccionado es el correcto, y
decidimos donde y con que nombre se va a generar el fichero WAR, por ejemplo,
“C:\EjemplosWeb.war”. Pulsar el botón “Finish”:
Si vamos a una sesión de DOS, mediante el comando de la JDK jar.exe (jar tvf
nombreFichero.war), podemos ver su contenido y confirmar que la estructura generada es
exactamente la de la especificación Java EE:
131
Este fichero WAR, sería el que un administrador de Servidores de Aplicación Java EE
desplegaría y configuraría para que la aplicación estuviese disponible y dando servicio. Pero
en nuestro caso, simplemente añadiremos o quitaremos aplicaciones en el Apache Tomcat
de Eclipse IDE for Java EE Developers mediante el interfaz de usuario: botón derecho del
ratón y la opción “Add and Remove…”, o directamente sobre el componente y “Run As” ->
“Run on Server”.
Nos queda no obstante hablar un poco sobre el descriptor de despliegue. Como ya
adelantábamos en la primera unidad, se trata de un fichero XML donde se describe un poco
el contenido y posible comportamiento del contenido del módulo.
En el caso concreto de los módulos Web, su descriptor de despliegue es el fichero web.xml
A lo largo de esta unidad, nunca hemos hecho mención de él, ya que a diferencia de los
Java Servlets, los JavaServer Pages pueden ser invocados directamente mediante el
nombre del fichero sin necesidad de registrarlos en el descriptor de despliegue.
No obstante, es posible registrarlos con otro alias para evitar que sean invocados mediante
el nombre del fichero. Esto se consigue de forma parecida a como hacíamos con los Java
Servlets pero con la etiqueta ”jsp-file” en vez de “servlet-class”.
Veamos un ejemplo:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>CalculadoraJSP</servlet‐name> <jsp‐file>/calculadora.jsp</jsp‐file> </servlet> <servlet‐mapping> <servlet‐name>CalculadoraJSP</servlet‐name> <url‐pattern>/CalculadoraJSP</url‐pattern> </servlet‐mapping> </web‐app> Si utilizamos este descriptor de despliegue en nuestro ejemplo, en vez de usar esta URL
para invocar nuestra JavaServer Page:
http://localhost:8080/EjemplosWeb/calculadora.jsp
podríamos utilizar esta otra:
http://localhost:8080/EjemplosWeb/CalculadoraJSP
Existen muchas mas etiquetas a utilizar en un descriptor de despliegue de un módulo Web,
pero las iremos viendo a lo largo del curso según las vayamos necesitando. De momento
nos quedamos con la general “web-app” y las necesarias para registrar un alias a un
JavaServer Page.
132
MÓDULO B – Unidad 5: JavaServer Pages
Es una buena práctica utilizar siempre el alias y ocultar de esta manera el nombre del fichero
al llamante de la JavaServer Page (JSP).
133
PARA RECORDAR
 Los JavaServer Pages, son un tipo de componente Java EE que se empaquen en
un módulo web (WAR) y se despliegan y ejecutan en el contenedor web de un
Servidor de Aplicaciones Java EE.
 Dentro del patrón de diseño MVC ocupan el espacio de la Vista, como encargado
de mostrar el resultado de la petición al usuario final. Están enfocadas a la
presentación.
 Un JavaServer Page, es un fichero de extensión *.jsp que utiliza principalmente
lenguajes de etiquetado como el HTML en el que se pueden embeber mediante
unas etiquetas especiales, código Java.
 Contienen distintos tipos de etiquetas, como son las:
 Comentario: <%-- … --%>
 Directiva:
o page: añade información técnica a la página
o include: se utiliza para incluir el resultado de la ejecución de otra JSP
o taglib: se utiliza para definir una librería de etiquetas (tags) que se va a utilizar
en la JavaServer Page
 Declaración: <%! … %> utilizada para definir atributos y método que serán
accesibles desde toda la JavaServer Page.

Scriptles: <% … %> para incluir código Java embebido en la JavaServer Page.

Expresión: <%= … %> devuelve el valor de una variable o un método para
insertarlo como parte de la respuesta.
 El ciclo de vida de una JavaServer Page es similar a los Java Servlets, solo que
cambian los nombres, jspInit, jspService y jspDestroy
134
 Las JavaServer Pages, tienen una serie de objetos a su disposición de forma
implícita, para utilizarlos en caso de necesitarlos:
 request: representa la petición HTTP
 response: representa la respuesta HTTP.
 session: representa la sesión HTTP del usuario.
 application: representa el contexto de la aplicación.
 config: representa la configuración inicial que se ha hecho para este JavaServer
Page.
 page: representa la propia página.
 exception: representa la excepción que se ha
 out: representa el writer de escritura de la respuesta HTTP
135
136
Unidad de Aprendizaje 6
DISEÑO DE APLICACIONES
JAVA EE
ÍNDICE
6.1
Introducción ................................................................. 139
6.1.1 El Controlador ...............................................................140
6.1.2 La Vista...........................................................................140
6.1.3 El Modelo .......................................................................141
6.2
Conectando Java Servlets con JavaServer Pages . 142
6.2.1 RequestDispatcher .......................................................142
6.2.2 Un ejemplo completo ...................................................143
6.3
Otros patrones de diseño........................................... 147
PARA RECORDAR.................................................................. 150
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
6.1
Introducción
Llegados a este punto, el alumno ya conoce lo básico de las tecnologías Java Servlet y
JavaServer Page (JSP), sus pros y contras, puntos fuertes y puntos flojos.
En más de una ocasión durante las últimas unidades, hemos comentado que estábamos
haciendo un mal diseño de las aplicaciones pero que desde un punto de vista didáctico nos
parecía conveniente hacerlo así, para comprender mejor esta unidad dedicada al diseño de
Aplicaciones Java EE.
Existen multitud de patrones de diseño relacionados con las Aplicaciones Java EE, pero hay
uno ya mencionado durante el curso que tiene en cuenta a la aplicación en su conjunto y no a
una parte solo.
Estamos hablando del patrón MVC (Modelo-Vista- Controlador o Model-View-Controller en
inglés).
Este patrón de diseño divide la aplicación en tres roles, cada uno de ellos con unas
responsabilidades muy concretas.

El Modelo (Model): Representa los datos y cualquier lógica de negocio relacionada con
ellos.

La Vista (View): renderiza el contenido de los modelos dependiendo de la tipología de
cliente (navegador web, teléfono móvil, etc…).

El Controlador (Controller): define el comportamiento general de la aplicación
coordinando a las otras dos partes (Modelo y Vista).
Veamos el patrón de diseño en un diagrama:
139
Pues bien, los dos tipos de componentes Java EE que hemos estudiado ya, encajan
perfectamente en este diseño:
 Controlador: Java Servlets.
 Vista: JavaServer Pages (JSP).
6.1.1 El Controlador
De la experiencia que hemos cogido con las actividades relacionadas con la unidad de los
Java Servlets, hemos visto que son muy potentes para contener código Java, analizar los
parámetros de las peticiones, validarlos, manipularlos, etc… pero sin embargo son
realmente tediosos para manejar la presentación. Para un diseñador gráfico de páginas
HTML, es realmente complicado crear y mantener dichas páginas a través de líneas
out.println(….) que dificultan ver el resultado final en su conjunto.
6.1.2 La Vista
Por el contrario, los JavaServer Pages (JSP) han demostrado ser muy valiosos para realizar
el diseño gráfico de la presentación, insertando pequeños scriptlets Java, pero muy tediosos
cuando el número de líneas de código Java se incrementa y entonces la mezcla de lógica y
presentación se hace muy complicada.
140
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
6.1.3 El Modelo
Con lo visto hasta ahora, no parece que ninguna de las dos tecnologías sea la más
adecuada para implementar la lógica de negocio, es decir, encapsular e implementar la
razón de nuestra Aplicación Java EE.
Las especificaciones Java EE contemplan un tipo de componente cuyo objetivo es cubrir
este hueco: los Enterprise JavaBeans (EJBs). Pero como no son objetivo de este curso,
utilizaremos directamente POJOs (Plain Old Java Object, o lo que es lo mismo, clases Java
sin más).
Por tanto, todo en su conjunto quedaría visualmente así:
Y el flujo habitual de una aplicación Java EE a partir de ahora quedará de la siguiente
manera:
1. El cliente, por ejemplo un navegador, solicitará una funcionalidad desde el interface
visual (Vista).
2. Dicha petición entrará a través de un Java Servlet (Controlador).
3. Dicho Java Servlet, analizará qué se está pidiendo, qué información adicional aporta y
decidirá que JavaBean (Modelo) cubre dicha petición (implementado mediante un
POJO).
4. Lo invocará, y tras recibir un resultado, decidirá qué JavaServer Page muestra dicho
resultado al cliente (Vista).
5. El resultado será devuelto y mostrado.
Para profundizar en el patrón de diseño Model-View-Controller, conectarse al Catálogo OnLine de patrones Java EE:
http://www.oracle.com/technetwork/java/catalog-137601.html
141
6.2
Conectando Java Servlets con JavaServer Pages
Quedan claras entonces las interrelaciones que existirán entre los distintos componentes
estudiados. ¿Pero técnicamente cómo hacemos dichos enlaces?
La invocación desde un Java Servlet a un JavaBean (o POJO) es muy sencilla. Simplemente
instanciará la clase en cuestión e invocará algún método de la misma. Pero, ¿y la invocación
desde un Java Servlet a un JavaServer Page (JSP)?
Dicha invocación se realiza mediante el interface javax.servlet.RequestDispatcher.
6.2.1 RequestDispatcher
Una instancia del tipo RequestDispatcher, representa la información necesaria para lanzar
una petición a un recurso web. En nuestro caso, podremos lanzar una petición a otro Java
Servlet o un JavaServer Page (JSP).
El acceso a dicha instancia se puede realizar mediante el método:
RequestDispatcher getRequestDispatcher(java.lang.String path);
de la HttpServletRequest, donde el parámetro que necesita, indica el recurso al que
queremos acceder.
RequestDispatcher tiene dos métodos:
 void forward(ServletRequest request, ServletResponse response) throws….
Este primer método, nos permite redirigir la petición a otro componente y delegar en él
la respuesta. Es decir, el control de lo que se responde al cliente por parte del Servidor
Java EE queda delegado.
 void include(ServletRequest request, ServletResponse response) throws….
Este segundo método nos permite incluir como parte de nuestra respuesta, la
respuesta de otro componente. Es decir, dicho componente colabora con la
respuesta, pero el control lo seguimos teniendo nosotros. Es el mismo resultado que la
directiva JSP “include” que estudiamos en la unidad anterior.
Los parámetros de ambos métodos son la petición y respuesta HTTP. Normalmente serán
los mismos que hemos recibido.
Por tanto, ya sabemos cómo redirigir la ejecución desde un Java Servlet a un JavaServer
Page (JSP). Pero nos quedaría un tema pendiente. ¿Cómo le pasamos información de la
lógica de negocio al siguiente?
Existen varias maneras de hacerlo:
 A través de la HttpServletRequest. Podemos utilizar los métodos setParameter(…) o
setAttribute(…) de la petición para añadir información que será utilizada por el
siguiente componente de la aplicación mediante los correspondientes métodos
getParameter(…) o getAttribute(…).
 A través de la HttpSession. Todavía no hemos estudiado este concepto. Lo trataremos
en la siguiente unidad.
142
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
 A través del ServletContext. Todavía no hemos estudiado este concepto. Lo
trataremos en la siguiente unidad.
6.2.2 Un ejemplo completo
Veamos un ejemplo completo de una aplicación web que resta dos números y que
implementa todos los roles del patrón de diseño Java EE MVC, cada uno de ellos en su sitio
adecuado.
Nota: Aunque un ejemplo tan sencillo se podría pensar en implementar en un solo
componente como hemos hecho en las actividades anteriores, debemos ser capaces de
extrapolar el ejemplo a una aplicación mucho más compleja y entenderemos las grandes
ventajas de este diseño que ya utilizaremos siempre a partir de ahora en el curso.
Página JSP de cabecera a ser reutilizada (Vista) cabecera.jsp:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <TABLE border="0" width="100%"> <TR> <TD align="left"> <IMG src="/EjemplosWeb/images/banner.gif"> </TD> <TD align="center"> <H1>Ejemplo de MVC</H1> </TD> <TD align="right"> <IMG src="/EjemplosWeb/images/banner.gif"> </TD> </TR> </TABLE> <HR><BR> Página JSP inicial (Vista):
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Calculadora</TITLE> </HEAD> <BODY> <%@ include file="/cabecera.jsp" %> <FORM method="POST" action="/EjemplosWeb/RestadorServlet" > <TABLE border="0"> <TR> <TD>Primer número:</TD> <TD><INPUT name="param1"></TD> </TR> 143
<TR> <TD>Segundo número:</TD> <TD><INPUT name="param2"></TD> </TR> <TR> <TD><INPUT type="submit" value="Restar"></TD> </TR> </TABLE> </FORM> </BODY> </HTML>
JavaBean o POJO (Modelo) RestadorBean.java:
package es.aulamentor; public class RestadorBean { public int restar(int param1, int param2) { return param1 + param2; } } Java Servlet (Controlador) index.jsp:
package es.aulamentor; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="RestadorServlet", urlPatterns={"/RestadorServlet"}) public class RestadorServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.procesarPeticion(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.procesarPeticion(request, response); } private void procesarPeticion(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { int param1 = Integer.parseInt(request.getParameter("param1")); 144
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
} int param2 = Integer.parseInt(request.getParameter("param2")); RestadorBean restadorBean = new RestadorBean(); int result = restadorBean.restar(param1, param2); request.setAttribute("result", result); request.getRequestDispatcher("/result.jsp").forward(reques
t, response); } catch(NumberFormatException ex) { request.setAttribute("error", "Alguno de los números no contenía dígitos válidos..."); request.getRequestDispatcher("/error.jsp").forward(request
, response); } } Página JSP de resultado (Vista) result.jsp:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Calculadora</TITLE> </HEAD> <BODY> <%@ include file="/cabecera.jsp" %> El resultado de la suma es: <%= request.getAttribute("result") %> <BR><BR> <A href="/EjemplosWeb/index.jsp">Volver atrás...</A> </BODY> </HTML> Página JSP de error (Vista) error.jsp:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Calculadora</TITLE> </HEAD> <BODY> <%@ include file="/cabecera.jsp" %> Se ha producido el siguiente error:<BR><BR> <%= request.getAttribute("error") %> <BR><BR> 145
<A href="/EjemplosWeb/index.jsp">Volver atrás...</A> </BODY> </HTML> No es necesario utilizar un descriptor de despliegue, ya que en el Java Servlet hicimos uso
de las Anotaciones Java.
Si el alumno implementa este ejemplo, debería ver algo así…
Página de inicio:
Página de resultado:
146
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
Página de error:
6.3
Otros patrones de diseño
A lo largo de la vida de las especificaciones Java EE, se han ido definiendo distintos patrones
de diseño (buenas prácticas) que han demostrado ser muy útiles por distintos motivos tanto en
el desarrollo como en el mantenimiento de las aplicaciones web.
Existe mucha literatura sobre el tema, aunque la guía básica es la denominada Java EE
BluePrints:
http://java.sun.com/blueprints/patterns/
Este curso no pretende entrar a estudiar en profundidad los distintos patrones, pero si que
comentaremos y utilizaremos alguno adicional que resultan interesantes
A continuación, listamos alguno sencillo de entender y de mucha utilidad:

Business Delegate (o Delegación de Negocio): permite reducir el acoplamiento entre la
capa web y la capa de negocio. Se trata de una capa intermedia que abstrae a la capa
de presentación de la tecnología empleada en la capa de negocio, es decir,
conseguiríamos que la capa de presentación no supiera si la lógica de negocio se
implementa mediante entidades Java Persistence API (JPA), Enterprise JavaBeans
(EJBs), POJOs, etc…y un cambio de tecnología, no afectaría para nada a la capa de
presentación, solo a los Business Delegates.
Más información en:
http://www.oracle.com/technetwork/java/businessdelegate-142190.html
147

Data Access Object, también llamado DAO (u Objeto de Acceso a Datos): permite
abstraer a la lógica de negocio del sistema de persistencia de los datos. Seguramente
a muchos os sonará de cuando estudiasteis el acceso a Bases de Datos con Java:
JDBC (Java DataBase Access). Es decir, la lógica de la aplicación es agnóstica de si
estamos usando Bases de Datos, ficheros, o cualquier otra fórmula de persistencia y
acceso a los datos. Nuevamente, un cambio en la forma de hacerlo, solo afectaría al
Data Access Object pero no a la lógica de negocio.
Tendremos oportunidad de utilizarlo en los ejemplos y actividades de las siguientes
unidades.
Más información en:
http://www.oracle.com/technetwork/java/dao-138818.html

Front Controller (o Controlador Frontal): se trata de una pieza controladora que
centraliza todas las peticiones y va eligiendo qué lógica de negocio y presentación son
necesarias para dicha petición. Sin saberlo, así es como hemos trabajado en esta
unidad. Siempre hemos manejado un único Java Servlet controlador que ha
gestionado las peticiones.
Evidentemente nuestros ejemplos eran muy sencillos y quizás no se vea la utilidad
pero imaginemos por un momento una aplicación web típica de altas, bajas y
modificaciones. Una primera aproximación podría ser contar con un Java Servlet para
cada petición, pero este patrón de diseño recomienda tener uno solo que sepa
gestionar de manera centralizada los tres tipos de petición.
Tendremos oportunidad de utilizarlo en los ejemplos y actividades de las siguientes
unidades.
Más información:
http://www.oracle.com/technetwork/java/frontcontroller-141071.html

Intercepting Filter (o Filtro Interceptor): permite implementar una lógica que se ejecute
siempre previamente a recibir una petición y posteriormente a enviar la respuesta.
Imaginemos por ejemplo que queremos incluir en nuestra aplicación un sistema de
logging, o de autenticación, etc…
Técnicamente se implementa mediante unos Java Servlets especiales denominados
filtros que estudiaremos en la siguiente unidad.
Más información en:
http://www.oracle.com/technetwork/java/interceptingfilter-136585.html

Service Locator (o Localizador de Servicios): permite simplificar el acceso a servicios
de la aplicación (por ejemplo Enterprise JavaBeans) o del Servidor de Aplicaciones
Java EE (por ejemplo Pool de Conexiones a Bases de Datos o Conectores a Sistemas
Empresariales) encapsulando dicha búsqueda y permitiendo su reutilización.
148
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
Hablaremos de nuevo de este patrón en la siguiente unidad, cuando tratemos el
acceso a Bases de Datos y los Pool de Conexiones (conocidos también con el nombre
de Data Sources).
Más información en:
http://www.oracle.com/technetwork/java/servicelocator-138528.html

Transfer Object (u Objeto de Transferencia): permite encapsular la información que
viaja entre las distintas capas de la aplicación. Tiene mucho sentido cuando ambas
capas están separadas físicamente y por tanto implica una comunicación por red en
cada petición. Suele ser mejor desde un punto de vista de rendimiento, pedir una vez y
recibir mucha información, que pedir más de una vez.
Se utiliza frecuentemente en las invocaciones desde la capa de presentación y la capa
de lógica de negocio cuando esta es distribuida, por ejemplo utilizando Enterprise
JavaBeans (EJBs).
En nuestro caso que utilizamos JavaBeans locales, no tiene un impacto tan grande.
Más información:
http://www.oracle.com/technetwork/java/transferobject-139870.html
149
PARA RECORDAR
 En esta unidad hemos visto detalladamente que componentes son los adecuados a
utilizar siguiendo el patrón de diseño MVC:
 El Modelo: Representa los datos y cualquier lógica de negocio relacionada con
ellos. Implementado mediante POJOS (también EJBs).
 La Vista: Renderiza el contenido de los modelos dependiendo de la tipología de
cliente (navegador web, teléfono móvil, etc…). Implementado mediante
JavaServer Pages (JSP).
 El Controlador: Define el comportamiento general de la aplicación coordinando
a las otras dos partes (Modelo y Vista). Implementado mediante Java Servlets.
 La conexión entre un Java Servlet y un POJO se realiza mediante las llamadas a los
métodos de dicho componente.
 La conexión entre un Java Servlet y un JavaServer Page (JSP) se realiza mediante
los métodos forward o include (dependiendo de las necesidades) de la clase
RequestDispatcher.
 Para pasarle los datos necesarios del Java Servlet y un JavaServer Page (JSP) se
pueden utilizar los siguiente mecanismos:
 HttpServletRequest. Podemos
setAttribute(…) de la petición
utilizar
los
métodos
setParameter(…)
o
 HttpSession.
 ServletContext.
 Otros patrones de diseño Java EE son:
 Business Delegate: permite reducir el acoplamiento entre la capa web y la capa de
negocio.
 Data Access Object: permite abstraer a la lógica de negocio del sistema de
150
 Front Controller: se trata de una pieza controladora que centraliza todas las
peticiones y va eligiendo qué lógica de negocio y presentación son necesarias para
dicha petición.
 Intercepting Filter: permite implementar una lógica que se ejecute siempre
previamente a recibir una petición y posteriormente a enviar la respuesta.
 Service Locator: permite simplificar el acceso a servicios de la aplicación o del
Servidor de Aplicaciones Java encapsulando dicha búsqueda y permitiendo su
reutilización.
 Transfer Object: permite encapsular la información que viaja entre las distintas
capas de la aplicación
151
152
Unidad de Aprendizaje 7
JAVA SERVLETS AVANZADO
ÍNDICE
7.1
Introducción ................................................................. 155
7.2
Configuración de un Java Servlet ............................. 155
7.2.1 Mediante descriptor de despliegue ...........................155
7.2.2 Mediante anotaciones..................................................156
7.3
Concurrencia en un Java Servlet .............................. 158
7.4
Acceso a Bases de Datos........................................... 160
7.4.1 Acceso directo desde el código.................................160
7.4.2 Acceso a través de un Pool de Conexiones.............166
7.5
Filtros............................................................................. 175
7.6
Mantenimiento del estado del cliente ...................... 179
7.6.1 Cookies ..........................................................................179
7.6.2 Sesión HTTP..................................................................188
7.7
Gestión de eventos...................................................... 193
PARA RECORDAR.................................................................. 201
MÓDULO C – Unidad 7: Java Servlets Avanzado
7.1
Introducción
A estas alturas del curso, ya hemos aprendido las tecnologías básicas sobre las que se apoya
el desarrollo de aplicaciones web Java EE y cuándo usar unas u otras. Incluso ya hemos
desarrollado algunas aplicaciones sencillas.
El objetivo de las siguientes unidades, es profundizar en estas tecnologías para poderle sacar
más provecho y llegar a desarrollar aplicaciones Java EE reales.
7.2
Configuración de un Java Servlet
Como bien recordarás de las unidades anteriores, el ciclo de vida de un Java Servlet tenía un
método de inicialización:
public void init(ServletConfig config);
que se ejecutaba una sola vez al inicio de la vida del Java Servlet y que se solía utilizar para
llevar a cabo todas las labores de inicialización y configuración que necesitáramos para su
posterior ejecución.
Como
se
puede
observar,
javax.servlet.ServletConfig,
que
recibe
como
representa
parámetro
la
una
información
de
instancia
de
configuración
la
clase
que
el
administrador del Servidor de Aplicaciones Java EE haya podido añadir.
Dicha clase tiene distintos métodos para facilitar el acceso a su información:

java.lang.String getInitParameter(java.lang.String name)
Devuelve el parámetro de configuración que coincide con el nombre que se envía.

java.util.Enumeration<java.lang.String> getInitParameterNames()
Devuelve una colección con los nombres de todos los parámetros de configuración
que tiene.
¿Y cómo añadimos información de configuración a un Java Servlet? Pues bien, el
desarrollador tiene dos modos de añadir dicha información:

Mediante el descriptor de despliegue.

Mediante anotaciones en el código (a partir de Java EE 6.0).
7.2.1 Mediante descriptor de despliegue
Consiste en añadir un bloque “init-param” por cada parámetro, con parejas de bloques
“param-name” y “param-value”, dentro del bloque “servlet” que ya conocemos y hemos
utilizado anteriormente.
Veamos un ejemplo de un Java Servlet que recibe dos parámetros de configuración
mediante el descriptor de despliegue:
155
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>ConfigServlet</servlet‐name> <servlet‐class>es.aulamentor.ConfigServlet</servlet‐class> <init‐param> <param‐name>param1</param‐name> <param‐value>Hola</param‐value> </init‐param> <init‐param> <param‐name>param2</param‐name> <param‐value>Mundo</param‐value> </init‐param> </servlet> <servlet‐mapping> <servlet‐name>ConfigServlet</servlet‐name> <url‐pattern>/ConfigServlet</url‐pattern> </servlet‐mapping> </web‐app> 7.2.2 Mediante anotaciones
Se realiza añadiendo el atributo “initParams” a la anotación @WebServlet que ya hemos
utilizado anteriormente. Dicho atributo, contiene a su vez, anotaciones @WebInitParam por
cada parámetro, la cual nuevamente, contiene parejas de atributos “name” y “value”.
Se entiende mucho más fácil con un ejemplo:
package es.aulamentor; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="ConfigServlet",urlPatterns={"/ConfigServlet"}, initParams={@WebInitParam(name="param1", value="Hola"), @WebInitParam(name="param2", value="Mundo")}) public class ConfigServlet extends HttpServlet { public void init(ServletConfig config) throws ServletException { Enumeration<String> parameters = config.getInitParameterNames(); while(parameters.hasMoreElements()) { String name = parameters.nextElement(); 156
MÓDULO C – Unidad 7: Java Servlets Avanzado
System.out.println("Nombre: " + name + " Valor: " + config.getInitParameter(name)); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } Este código de ejemplo en ejecución dentro del entorno de desarrollo mostraría algo así:
Ambos dos métodos no son excluyentes, aunque no tiene mucho sentido utilizar ambos para
un mismo Java Servlet. No obstante, si así fuera y en el hipotético caso de que en ambos dos
sitios existiera un parámetro con el mismo nombre, tendría prioridad el del descriptor de
despliegue.
157
7.3
Concurrencia en un Java Servlet
Nota: En esta sección se asume que el alumno tiene conceptos de programación avanzada en
Java, en concreto, en la programación concurrente con Java Threads.
Se dice que una aplicación soporta concurrencia cuando permite ejecuciones en paralelo de
su código. Es decir, en el caso de las aplicaciones Java EE que estamos estudiando,
significaría que varios usuarios puedan conectarse y ejecutar la aplicación a la vez.
Las aplicaciones Java EE son concurrentes por naturaleza. El Servidor de Aplicaciones Java
EE se encarga de controlar y permitir la concurrencia de la aplicación permitiendo al
desarrollador prácticamente despreocuparse de esta casuística.
Teniendo en cuenta que solamente hay una instancia de un Java Servlet por cada JVM, no
debemos olvidarnos nunca del tema y tenerlo siempre presente en nuestros desarrollos para
evitar problemas y comportamientos no deseados. Por ejemplo, imaginemos lo que puede
ocurrir si utilizamos variables de instancia en el Java Servlet para manejar una información
temporal durante la ejecución de un método, en el que hemos sustituido un posible código
que tarda cierto tiempo en ejecutar por un Thread.sleep(5000);
package es.aulamentor; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/ConcurrenciaServlet") public class ConcurrenciaServlet extends HttpServlet { private int val = 0; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { val = Integer.parseInt(request.getParameter("param")); System.out.println("Thread: " + Thread.currentThread().getName() + " usa el valor: " + val); try { //Simulamos que el servlet está con alguna operativa antes de //volver a utilizar el valor de la variable val. Thread.sleep(5000); } catch(InterruptedException ex) { } System.out.println("Thread: " + Thread.currentThread().getName() + " usa el valor: " + val); } } E invocamos desde el navegador a este Java Servlet dos veces consecutivas (en menos de 5
segundos) primero con el parámetro 5 y luego con el parámetro 2:
158
MÓDULO C – Unidad 7: Java Servlets Avanzado
http://localhost:8080/EjemplosWeb/ConcurrenciaServlet?param=5 http://localhost:8080/EjemplosWeb/ConcurrenciaServlet?param=2
Observemos en la salida por consola lo que ocurre:
La primera petición la sirve un thread controlado por el Servidor de Aplicaciones Java EE que
se llama “http-bio-8080-exec3” y el inicio de la ejecución del Java Servlet muestra que el
parámetro con el que tiene que trabajar vale 5. Entonces, se duerme durante 5 segundos (ha
sido la forma de simular una tarea costosa) y cuando vuelve a por el parámetro, resulta que
vale 2.
¿Qué ha pasado? Lo que ha pasado es que antes de que el primer Java Servlet terminara de
ejecutarse, el Servidor de Aplicaciones Java EE recibió una segunda petición al mismo Java
Servlet con un valor del parámetro distinto. Como ambos dos threads, en este caso “http-bio8080-exec-4”, ejecutan el mismo código, el segundo ha machacado el valor al primero.
Se trata de un ejemplo muy sencillo, pero el problema que demuestra puede ser muy
complicado de detectar.
Existen distintas soluciones:
159

Evitar en la medida de lo posible utilizar variables de instancia cuando su valor es de
escritura/lectura.

Implementar el interface javax.servlet.SingleThreadModel que le indica al Servidor de
Aplicaciones Java EE, que no puede paralelizar las ejecuciones de este Java Servlet.
Esta solución no es recomendable porque por regla general implica un tiempo de
respuesta pésimo a los usuarios. Imaginad cien usuarios pidiendo este servicio a la
vez y teniendo que esperar en cola a ser respondidos.

7.4
Utilizar técnicas de sincronización del lenguaje Java (synchronized).
Acceso a Bases de Datos
Nota: En esta sección se asume que el alumno tiene conceptos de programación avanzada en
Java, en concreto, en la programación de acceso a Bases de Datos con JDBC.
Existen distintas alternativas para el acceso a Bases de Datos desde aplicaciones web. Vamos
a comentar dos de ellas: mediante el acceso directo a la Base de Datos desde el código y
mediante un servicio que nos proveen los Servidores de Aplicaciones Java EE denominado
Pool de Conexiones (o Data Source).
La primera alternativa tiene bastantes problemas (uno de ellos es que tiene peor rendimiento
que las otras alternativas) y no es para nada recomendada. Pero, no obstante, la veremos
brevemente para entender mejor la naturaleza de una aplicación web, el por qué esta es una
mala alternativa y cómo la segunda es una opción mucho mejor.
7.4.1 Acceso directo desde el código
Este método supone ejecutar todos los pasos típicos del API JDBC en el código de nuestra
aplicación:
 Cargar el Driver JDBC en la JVM.
 Crear una conexión a la Base de Datos.
 Crear una sentencia (de cualquiera de los tipos) y ejecutarla.
 Analizar el resultado de la sentencia.
 Cerrar y liberar los recursos.
Con lo que conocemos ya del desarrollo de Java Servlets, podríamos pensar en colocar los
distintos pasos en distintos lugares del código.
Por ejemplo, una opción sería realizar la carga del Driver JDBC, la creación de la conexión a
la Base de Datos y de la sentencia a ejecutar en el método de inicialización de Java Servlet
(init). En los métodos de proceso de HTTP GET o HTTP POST (doGet o doPost) la ejecución
160
MÓDULO C – Unidad 7: Java Servlets Avanzado
de la sentencia y análisis del resultado. Y por último, en el método de finalización del Java
Servlet (destroy) incluiríamos el código de limpieza, cerrando y liberando los recursos.
Ahora bien, esta opción tiene un inconveniente, y es que la sentencia será una variable de
instancia (o atributo), y como ya hemos tratado en la sección anterior, debido a que las
aplicaciones web son multiusuario (multithread) por naturaleza, tendríamos que tener en
cuenta el acceso sincronizado a la variable.
Podríamos pensar entonces en otra opción, y sería pasar todos los pasos a los métodos de
proceso de HTTP GET y HTTP POST (doGet y doPost) dejando únicamente la carga del
Driver JDBC en el método de inicialización (init). En este caso es cierto que no tendremos
que estar pendientes de sincronizar el acceso a ninguna variable de instancia (o atributo),
pero penalizamos enormemente el rendimiento (tiempo de respuesta) de la aplicación al
estar conectando y desconectando constantemente con la Base de Datos.
Vamos a ver un ejemplo de código para que se visualice mejor esta primera alternativa de
acceso a Bases de Datos aunque como ya dijimos no es la recomendada.
El ejemplo consiste en una aplicación web de consulta de títulos de libros mediante el
código ISBN:
Página HTML de inicio:
<!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Acceso a Bases de Datos</TITLE> </HEAD> <BODY> <FORM method="POST" action="/EjemplosWeb/BaseDatosServlet"> <TABLE border="0"> <TR> <TD>Introduzca el ISBN:</TD> <TD><INPUT name="isbn"></TD> </TR> <TR> <TD><INPUT type="submit" value="Buscar"></TD> </TR> </TABLE> </FORM> </BODY> </HTML> Java Servlet con la lógica:
package es.aulamentor; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; 161
import java.sql.SQLException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/BaseDatosServlet") public class BaseDatosServlet extends HttpServlet { public void init(ServletConfig config) throws ServletException { try { Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); } catch(ClassNotFoundException ex) { System.out.println("Driver JDBC no encontrado..."); ex.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; String isbn = request.getParameter("isbn"); try { con = DriverManager.getConnection("jdbc:derby:D:/biblioteca", "derbyuser","derbyuser"); pstmt = con.prepareStatement("SELECT * FROM PRESTAMOS WHERE ISBN = ?"); pstmt.setString(1,isbn); rs = pstmt.executeQuery(); if(rs.next()) { request.setAttribute("titulo", rs.getString(3)); } request.getRequestDispatcher("/resultDB.jsp").forward(request, response); } catch(SQLException ex) { System.out.println("Problemas en el acceso a la BD..."); ex.printStackTrace(); } finally { try { if(rs != null) rs.close(); } catch(SQLException ex) 162
MÓDULO C – Unidad 7: Java Servlets Avanzado
{ ex.printStackTrace(); } try { if(pstmt != null) pstmt.close(); } catch(SQLException ex) { ex.printStackTrace(); } try { if(con != null) con.close(); } catch(SQLException ex) { ex.printStackTrace(); } } } } Página JSP de resultado:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Acceso a Bases de Datos</TITLE> </HEAD> <BODY> <% if(request.getAttribute("titulo") != null) { %> El título del libro es: <%= request.getAttribute("titulo") %> <% } else { %> Código ISBN no encontrado. <% } %> <BR><BR> <A href="/EjemplosWeb/indexDB.html">Volver atrás...</A> </BODY> </HTML> 163
En esta ocasión, nuestra aplicación está haciendo uso de los Drivers JDBC de una Base de
Datos (en concreto de Apache Derby) por lo que tendremos que tener en cuenta añadir el
fichero JAR que contiene dichas clases Java en nuestra aplicación.
La estructura de un módulo Web según las especificaciones Java EE dictaba que este tipo
de ficheros debían ubicarse en el directorio /WEB-INF/lib, que en un proyecto web de
Eclipse IDE for Java EE Developers corresponde a /WebContent/WEB-INF/lib:
Otra opción sería añadir el fichero a la instalación del Servidor de Aplicaciones Java EE en
vez de añadirlo a cada módulo web que acceda a la Base de Datos.
La configuración de esta opción es dependiente del servidor, es decir, dependiendo del
servidor que estemos utilizando se hará de una manera u otra. En nuestro caso, que
estamos utilizando Apache Tomcat 7.0.x, el fichero JAR se debe copiar en el directorio /lib
de la instalación:
164
MÓDULO C – Unidad 7: Java Servlets Avanzado
Independientemente de la opción de configuración elegida, la ejecución del ejemplo debería
mostrar algo así…
Página de inicio:
Página de resultado:
165
No obstante, como ya hemos comentado, esta forma de acceder a Bases de Datos tiene
graves problemas de rendimiento en el caso de tener muchos usuarios y además, si
decidimos compartir la conexión y la sentencia a través de una variable de instancia (o
atributo) para mejorar algo el rendimiento, tenemos que introducir en la programación
técnicas de sincronización que no son triviales.
Por este motivo, las especificaciones Java EE definieron el concepto de Pool de Conexiones
(Data Source) que todo Servidor de Aplicaciones Java EE debe implementar y que
estudiaremos a continuación.
7.4.2 Acceso a través de un Pool de Conexiones
Todo Servidor de Aplicaciones Java EE, debe implementar un servicio de Pool de
Conexiones a Bases de Datos que implemente el siguiente interface:
javax.sql.DataSource
Dicho interface tiene solo dos métodos que permiten el acceso a una conexión:
 Connection getConnection() throws SQLException;
Devuelve una conexión a Base de Datos disponible del pool.
 Connection getConnection(String username, String password) throws SQLException;
Devuelve una conexión a Base de Datos disponible del pool pero usando un usuario y
contraseña específico (no necesariamente el que use por defecto el Data Source).
Al tratarse de un servicio del Servidor de Aplicaciones Java EE, tendremos que crearlo y
configurarlo en el servidor para que sea accesible desde nuestra aplicación web. Y
evidentemente, esto no se hace en el código sino en el propio servidor.
Cada Servidor de Aplicaciones Java EE tiene su propio mecanismo de administración, es
decir, las especificaciones Java EE dictan qué servicios e interfaces deben implementar,
166
MÓDULO C – Unidad 7: Java Servlets Avanzado
pero indican en cómo lo tienen que hacer. Por tanto, la forma de configurar el servidor
dependerá del que estemos usando.
A continuación, comentaremos cómo se configura un Pool de Conexiones en Apache
Tomcat 7.0.x que es el Servidor de Aplicaciones Java EE que estamos utilizando a lo largo
de este curso.
Apache Tomcat 7.0.x basa toda su administración y configuración en ficheros XML que
residen en el directorio /conf. Pero como en nuestro caso lo estamos usando integrado en
Eclipse IDE for Java EE Developers, existe un proyecto especial adicional a los dedicados a
nuestros desarrollos que se llama “Servers”. Ahí es donde residen los ficheros XML de
configuración del Apache Tomcat 7.0.x que estamos utilizando.
En concreto, para configurar un Pool de Conexiones nuevo, debemos editar el fichero de
configuración context.xml, y a la sección ya existente <Context> </Context> añadirle el
siguiente bloque “Resource”:
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="derbyuser" password="derbyuser" 167
driverClassName="org.apache.derby.jdbc.EmbeddedDriver" url="jdbc:derby:D:/biblioteca" />
Este bloque “Resource” define y configura un Pool de Conexiones a la Base de Datos
Apache Derby que estamos usando en nuestro ejemplo.
Repasemos el significado de algunas de las propiedades de la configuración:
 name: identificador JNDI (Java Naming and Directory Interface) que utilizaremos para
acceder al pool.
 type:
tipo
de
interface
que
implementa
el
recurso
(en
nuestro
caso
javax.sql.DataSource).
 username: identificador de usuario en el caso de que el Gestor de Base de Datos que
estamos utilizando tenga la seguridad activada.
 password: contraseña de usuario en el caso de que el Gestor de Base de Datos que
estamos utilizando tenga la seguridad activada.
 driverClassName: nombre del Driver JDBC de acceso al Gestor de Base de Datos
que estamos utilizando.
 url: URL JDBC.
El resto de propiedades suelen estar relacionadas con las características más funcionales
del Pool de Conexiones, temas como el número máximo de conexiones que puede tener, el
tiempo máximo que una conexión puede estar asignada sin ser devuelta al pool, etc…
Con esto, el Servidor de Aplicaciones Java EE ya va a crear y gestionar un Pool de
Conexiones con nuestra Base de Datos. Ahora, nos queda indicar que nuestra aplicación
web está interesada en el acceso a dicho pool y lo haremos mediante el descriptor de
despliegue del módulo web (web.xml).
Para ello, añadiremos el siguiente bloque “resource-ref”:
<resource‐ref> <description>Conexion BD</description> <res‐ref‐name>jdbc/TestDB</res‐ref‐name> <res‐type>javax.sql.DataSource</res‐type> <res‐auth>Container</res‐auth> </resource‐ref>
Simplemente hacemos referencia al recurso creado y configurado en el servidor,
identificando básicamente el nombre (res-ref-name) y tipo (res-type). De esta manera, al
desplegar la aplicación web, el Servidor de Aplicaciones Java EE nos dará acceso al
recurso.
Ya solo nos queda modificar el código fuente de nuestra aplicación para que ahora haga uso
del Data Source en vez de crear las conexiones a la Base de Datos directamente.
168
MÓDULO C – Unidad 7: Java Servlets Avanzado
Para buscar y acceder a un recurso definido en el Servidor de Aplicaciones Java EE se utiliza
el API JNDI (Java Naming and Directory Interface). Es el API a través del cual podemos
conectarnos al directorio de recursos del servidor y acceder a ellos. Dicho API se encuentra
en el paquete Java: javax.naming;
Su uso es muy sencillo y normalmente consta de dos pasos:
 Creación del Contexto de búsqueda: dirección IP, puerto del servicio, y punto de
entrada en el directorio.
 Realización de la búsqueda del recurso y downcasting a su tipo concreto.
Veamos un ejemplo típico:
try { Context initialContext = new InitialContext(); DataSource datasource = (DataSource)initialContext.lookup("java:comp/env/jdbc/TestDB"); } catch(NamingException ex) { System.out.println("Problemas en el acceso al recurso..."); ex.printStackTrace(); } En el ejemplo creamos un Contexto con los valores por defecto, es decir, acceso al servicio
del propio Servidor de Aplicaciones Java EE en el que la aplicación se está ejecutando
desde la raíz del directorio. Si hubiéramos querido conectar con un servicio JNDI de otro
Servidor de Aplicaciones Java EE remoto, tendríamos que haber creado el Contexto con los
parámetros adecuados.
Y a continuación, realizamos la búsqueda del recurso con el nombre “jdbc/TestDB”, que nos
es devuelto como un java.lang.Object y de ahí que debamos hacer el downcasting a
javax.sql.DataSource.
Si no se encontrase el recurso por el motivo que fuese (el nombre está mal, no está bien
configurado
en
el
servidor,
etc…)
se
producirá
una
excepción
javax.naming.NamingException que deberemos tratar según la lógica de nuestra aplicación.
El lugar dentro del servicio JNDI donde se ubican siempre todos los recursos accesibles a
las aplicaciones web es: java:comp/env, de ahí que la búsqueda no haya sido solo de
“jdbc/TestDB” sino que ha sido de “java:comp/env/jdbc/TestDB”.
Por último, ya solo quedaría pedirle al Data Source una conexión disponible a la Base de
Datos a través de uno de los métodos comentados al inicio de este apartado. En este punto
se encuentra la clave de esta alternativa de programación de acceso a Bases de Datos. En
este caso, al contrario que ocurría cuando la conexión se la pedíamos al DriverManager, la
conexión ya está establecida con el Gestor de Base de Datos con lo que el tiempo de
respuesta es mucho mayor. Además, varias ejecuciones paralelas de nuestra aplicación
169
pueden estar accediendo a la Base de Datos en paralelo, no como antes que el acceso era
sincronizado (y por tanto serializado) a una única conexión.
No obstante, al igual que cuando accedíamos directamente a la Base de Datos desde el
código, es importante liberar los recursos cuando se han dejado de utilizar. En este caso, la
diferencia es que la llamada al método “close” de la conexión, en vez de cerrarla lo que hace
es devolverla al Pool de Conexiones como disponible para poder ser utilizada por otra
petición.
Veamos la aplicación de ejemplo de antes, pero esta vez utilizando un Pool de Conexiones.
Descriptor de despliegue:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>DataSourceServlet</servlet‐name> <servlet‐class>es.aulamentor.DataSourceServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>DataSourceServlet</servlet‐name> <url‐pattern>/DataSourceServlet</url‐pattern> </servlet‐mapping> <resource‐ref> <description>Conexion BD</description> <res‐ref‐name>jdbc/TestDB</res‐ref‐name> <res‐type>javax.sql.DataSource</res‐type> <res‐auth>Container</res‐auth> </resource‐ref> </web‐app>
Página HTML de inicio:
<!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Acceso a Bases de Datos</TITLE> </HEAD> <BODY> <FORM method="POST" action="/EjemplosWeb/DataSourceServlet"> <TABLE border="0"> <TR> <TD>Introduzca el ISBN:</TD> <TD><INPUT name="isbn"></TD> </TR> <TR> <TD><INPUT type="submit" value="Buscar"></TD> </TR> </TABLE> </FORM> 170
MÓDULO C – Unidad 7: Java Servlets Avanzado
</BODY> </HTML>
Java Servlet:
package es.aulamentor; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; public class DataSourceServlet extends HttpServlet { DataSource datasource = null; public void init(ServletConfig config) throws ServletException { try { Context initialContext = new InitialContext(); datasource = (DataSource)initialContext.lookup("java:comp/env/jdbc/TestDB"); } catch(NamingException ex) { System.out.println("Problemas en el acceso a la Base de Datos..."); ex.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; String isbn = request.getParameter("isbn"); try { con = datasource.getConnection(); pstmt = con.prepareStatement("SELECT * FROM PRESTAMOS WHERE ISBN = ?"); pstmt.setString(1,isbn); rs = pstmt.executeQuery(); if(rs.next()) { request.setAttribute("titulo", rs.getString(3)); 171
} request.getRequestDispatcher("/resultDS.jsp").forward(request, response); } catch(SQLException ex) { System.out.println("Problemas en el acceso a la Base de Datos..."); ex.printStackTrace(); } finally { try { if(rs != null) rs.close(); } catch(SQLException ex) { ex.printStackTrace(); } try { if(pstmt != null) pstmt.close(); } catch(SQLException ex) { ex.printStackTrace(); } try { if(con != null) con.close(); } catch(SQLException ex) { ex.printStackTrace(); } } } } Página JSP de resultado:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Acceso a Bases de Datos</TITLE> </HEAD> <BODY> <% if(request.getAttribute("titulo") != null) { %> El título del libro es: <%= request.getAttribute("titulo") %> 172
MÓDULO C – Unidad 7: Java Servlets Avanzado
<% } else { %> Código ISBN no encontrado. <% } %> <BR><BR> <A href="/EjemplosWeb/indexDS.html">Volver atrás...</A> </BODY> </HTML>
La ejecución del ejemplo debería mostrar exactamente los mismos resultados que antes. Es
decir, el cómo accedamos a la Base de Datos no afecta en nada a la presentación de la
aplicación aunque seguramente si se notará mejor rendimiento (la búsqueda se hará más
rápida).
Página de inicio:
Página de resultado:
173
Ahora bien, como ya hemos comentado en otras ocasiones, a partir de Java EE 6.0 existe
otra alternativa al descriptor de despliegue y código Java. Son las anotaciones Java.
Veamos cómo quedaría el mismo ejemplo usando la anotación @Resource. En vez de
escribir las líneas de código necesarias para realizar la búsqueda:
public class DataSourceServlet extends HttpServlet { DataSource datasource = null; public void init(ServletConfig config) throws ServletException { try { Context initialContext = new InitialContext(); datasource = (DataSource)initialContext.lookup("java:comp/env/jdbc/TestDB"); } catch(NamingException ex) { System.out.println("Problemas en el acceso a la BD..."); ex.printStackTrace(); } }
podríamos simplemente usar esta anotación:
public class DataSourceServlet extends HttpServlet { @Resource(name="java:comp/env/jdbc/TestDB") DataSource datasource; teniendo en cuenta importar el paquete: javax.annotation;
Cualquiera de las dos opciones es válida.
Adicionalmente, existe otra anotación muy útil sobre todo para los entornos de desarrollo
locales que permite realizar la definición de los DataSources sin necesidad de tocar los
ficheros de configuración de los Servidores de Aplicación Java EE. Es mediante la anotación
@DataSourceDefinition que requiere importar el paquete: javax.annotation.sql;
Nota: esta opción no está disponible en el servidor Apache Tomcat 7.0.x que utilizamos en
este curso (que como recordaremos, no implementaba el 100% de las especificaciones Java
EE, sola las relacionadas con la capa web), pero no obstante la comentamos:
@DataSourceDefinition(name = "java:comp/env/jdbc/TestDB", className = "org.apache.derby.jdbc.EmbeddedDriver", url = "jdbc:derby:D:/biblioteca") public class DataSourceServlet extends HttpServlet { @Resource(name=" java:comp/env/jdbc/TestDB ") DataSource datasource; 174
MÓDULO C – Unidad 7: Java Servlets Avanzado
En este ultimo ejemplo, vemos como en el propio código realizamos la definición del
DataSource. Los Servidores de Aplicación Java EE, al encontrar este código, dinámicamente
crean el DataSource sin necesidad de haberlo definido en la configuración del servidor.
Esta manera de definirlos está recomendada únicamente en los entornos locales de los
desarrolladores, para facilitar y agilizar las pruebas. Pero no es la manera recomendada de
configurarlos en los entornos reales de ejecución donde deberán ser los administradores los
que decidan cómo configurarlos.
El uso de Pool de Conexiones, siempre lleva relacionado temas de “tunning” (ajustes de la
configuración para mejorar el rendimiento), pero este es un tema que trasciende el ámbito de
este curso y que además es muy dependiente del Servidor de Aplicaciones Java EE que se
esté utilizando. Pero si es interesante que recuerdes que es importante que los
administradores del servidor realicen pruebas de carga y analicen cómo afecta al
rendimiento de la aplicación el número máximo de conexiones disponible en el pool entre
otros parámetros, decidiendo el valor óptimo en cada caso.
7.5
Filtros
Un filtro es un componente web más, que a diferencia de los que hemos visto hasta ahora no
son invocados directamente. Son unos componentes que se despliegan como parte de la
aplicación Web, y cuya misión es interceptar las peticiones y respuesta de un componente
concreto para por ejemplo, realizar algún tipo de validación, algún tipo de auditoria, algún tipo
de transformación, etc…
Es decir, sin que el usuario lo sepa, antes y después de la ejecución de un componente web
se ejecuta este nuevo componente.
Un filtro de implementar el interface: javax.servlet.Filter que incluye tres métodos:

void init(FilterConfig filterConfig) throws ServletException;
Se invoca una única vez en la vida del filtro y se utiliza para realizar las labores de
inicialización. El parámetro del tipo javax.servlet.FilterConfig da acceso a cualquier
atributo de configuración del filtro que se haya especificado en el descriptor de
despliegue o en las anotaciones.

void doFilter(ServletRequest request, ServletResponse response, FilterChain
chain) throws java.io.IOException, ServletException;
Es el método que realiza la lógica específica del filtro: auditoria, transformaciones,
etc… A través del último parámetro del tipo javax.servlet.FilterChain podremos renviar
la petición al siguiente filtro en la cadena si lo hubiera, o al componente web destino
que estábamos filtrando.

void destroy();
175
Nuevamente, se invoca una única vez en la vida del filtro y se utiliza para realizar las
labores de limpieza y liberación de recursos si fuese necesario.
Como vemos, es muy parecido a un Java Servlet con la diferencia de que no son invocados
expresamente por la presentación, sino que se ejecutan cuando el componente web al que
filtran es invocado.
Desde la aparición de Java EE 6.0 existen dos maneras de declarar los filtros y asociarlos a
unos componentes web determinados: el descriptor de despliegue y las anotaciones Java.
Veamos primero cómo se definen y configuran en el descriptor de despliegue, el fichero
web.xml
Definimos el filtro a través del bloque “filter” con sus bloques “filter-name” y “filter-class”. Y
configuramos qué componentes web filtra mediante el bloque “filter-mapping” con sus
bloques “filter-name” y “url-pattern”.
Por ejemplo:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet‐name>DataSourceServlet</servlet‐name> <servlet‐class>es.aulamentor.DataSourceServlet</servlet‐class> </servlet> <servlet‐mapping> <servlet‐name>DataSourceServlet</servlet‐name> <url‐pattern>/DataSourceServlet</url‐pattern> </servlet‐mapping> <filter> <filter‐name>AuditoriaFilter</filter‐name> <filter‐class>es.aulamentor.AuditoriaFilter</filter‐class> </filter> <filter‐mapping> <filter‐name>AuditoriaFilter</filter‐name> <url‐pattern>/*</url‐pattern> </filter‐mapping> </web‐app> En este ejemplo, además de un Java Servlet de un ejemplo anterior, tenemos un Filtro que se
llama AuditoriaFilter implementado mediante la clase es.aulamentor.AuditoriaFilter que filtra (es
decir, intercepta las peticiones) cualquier componente web de la aplicación.
A través del patrón de URL, podríamos afinar un poco más el filtrado. Por ejemplo, si
queremos que solo filtre los ficheros HTML, podríamos poner *.html en vez de /*, o
/RequestServlet si lo que queremos es filtrar a ese Java Servlet o JavaServer Page concreta.
Hay muchas posibilidades.
176
MÓDULO C – Unidad 7: Java Servlets Avanzado
A continuación, vamos a ver el código fuente del filtro de este ejemplo, que se limita a escribir
en consola la dirección IP que realiza la petición y a qué hora, y la hora en la que se envía la
respuesta:
package es.aulamentor; import java.io.IOException; import java.util.Calendar; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class AuditoriaFilter implements Filter { public void init(FilterConfig fConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Calendar time = Calendar.getInstance(); System.out.println("Acceso desde IP: " + request.getRemoteAddr() + " a las " + time.get(Calendar.HOUR) + ":" + + time.get(Calendar.MINUTE)); chain.doFilter(request, response); System.out.println("Contestado a las " + time.get(Calendar.HOUR) + ":" + + time.get(Calendar.MINUTE)); } public void destroy() { } } Es muy importante siempre realizar la llamada al siguiente miembro de la cadena (que puede
ser otro filtro o el componente web final) mediante el método doFilter() del parámetro
FilterChain. Aunque también existe la posibilidad de desviar la ejecución, invocando a otro
componente web (por ejemplo de error) a través del RequestDispatcher como ya sabemos
hacer. Es decir, que un filtro puede decidir en un momento dado interrumpir la ejecución
normal de la petición y desviarla por el motivo que sea a otro componente.
La ejecución en el entorno de desarrollo debería mostrar algo así:
177
Como mencionamos, desde Java EE 6.0 también existe la opción de obviar el descriptor de
despliegue y utilizar anotaciones Java para las definiciones y configuraciones. En este caso,
usaremos la anotación @WebFilter con sus atributos “filterName” y “urlPatterns”:
package es.aulamentor; import java.io.IOException; import java.util.Calendar; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; @WebFilter(filterName="AuditoriaFilter", urlPatterns={"/*"}) public class AuditoriaFilter implements Filter { public void init(FilterConfig fConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse 178
MÓDULO C – Unidad 7: Java Servlets Avanzado
response, FilterChain chain) throws IOException, ServletException { Calendar time = Calendar.getInstance(); System.out.println("Acceso desde IP: " + request.getRemoteAddr() + " a las " + time.get(Calendar.HOUR) + ":" + + time.get(Calendar.MINUTE)); chain.doFilter(request, response); System.out.println("Contestado a las " + time.get(Calendar.HOUR) + ":" + + time.get(Calendar.MINUTE)); } public void destroy() { } } El resultado debería ser el mismo.
En casos de que existiese más de un filtro, y que además filtrasen al mismo componente web,
su ejecución se realizaría en el orden en el que fueron definidos.
7.6
Mantenimiento del estado del cliente
El protocolo HTTP es un protocolo sin estado, es decir, cada petición que se recibe en el
servidor de un mismo cliente se recibe como si fuese la primera petición que hace. Es decir,
no hay constancia de que ya se hubiese conectado antes y hubiera solicitado una acción.
Este es un inconveniente importante. Supone por ejemplo, que aunque un cliente ya se
hubiera autenticado con el sistema, como la próxima petición parece una petición nueva
pediría autenticarse de nuevo. O que un cliente que mediante una petición anterior movió un
producto al carrito de la compra en una aplicación de comercio electrónico, en la siguiente
petición el carrito aparece vacío.
Por suerte, el protocolo HTTP contempla la posibilidad de almacenar en el lado cliente
información del servidor, de manera que dicha información viaje a partir de entonces en cada
nueva petición, y tanto la aplicación Web como el Servidor de Aplicaciones Java EE puedan
usarla para recordar al cliente.
Esta información que se puede almacenar en el lado cliente recibe el nombre de Cookie.
7.6.1 Cookies
Básicamente, una Cookie es una pareja formada por una clave y un valor que contiene
información textual. Es decir, tiene un nombre que identifica la Cookie y un valor asociado,
junto con alguna información relacionada adicional que ahora comentaremos sobre cuándo
caduca, quién la creó, quién la puede ver, etc…
179
El hecho de que se puedan crear desde el servidor, es decir, desde una aplicación web, las
hace muy útiles para poder “recordar” los clientes y evitar interacciones redundantes,
pérdidas de información y similares.
Normalmente (a no ser que tengamos el navegador configurado para evitarlas) en nuestro
navegador tendremos decenas de Cookies guardadas sin que fuéramos conscientes de ello.
Por ejemplo, si utilizas Mozilla Firefox ves a la opción de menú “Firefox” -> “Options” ->
“Options”:
En la opción “Privacy”, selecciona “Use custom settings for history” en la sección “history”,
y entonces pulsa el botón “Show Cookies…”:
180
MÓDULO C – Unidad 7: Java Servlets Avanzado
Te sorprenderá ver todas las que tienes (incluyendo Cookies de Aula Mentor):
181
En el caso de Internet Explorer, es un poco más complicado. Ir a la opción de menú “tools” > “Internet Options”:
Pulsar el botón “Settings” de la sección “Browsing history”:
182
MÓDULO C – Unidad 7: Java Servlets Avanzado
Y en la nueva ventana, pulsar el botón “View files”:
183
Se abrirá el explorador de archivos, y tendremos que buscar todos aquellos que empiezan
por Cookie:
184
MÓDULO C – Unidad 7: Java Servlets Avanzado
Bien, veamos qué información guarda una Cookie antes de meternos con el API Java para
crearlas y acceder a ellas desde nuestras aplicaciones:

Nombre: Identificador de la Cookie para poder ser accedida.

Contenido: La información en modo texto que guarda.

Servidor (o Host): Servidor que creo la Cookie.

Ruta (o Path): Dentro de ese Servidor, a qué rango de URLs les mandará el
navegador la Cookie (un / significa que a todas).

Segura: Indica si debe ser enviada exclusivamente a través de conexiones
seguras (HTTPS).

Caducidad: Indica la fecha en la que caduca y por tanto es borrada. Se puede
indicar en vez de una fecha, que se borre cuando se cierre el navegador.
185
Las Cookies están implementadas en Java por la clase:
javax.servlet.http.Cookie;
Las
Cookies
ya
existentes
son
accesibles
a
través
de
la
petición
(javax.servlet.http.HttpServletRequest) mediante el método:
Cookie[] getCookies();
Y
las
nuevas,
una
vez
creadas
se
deben
incluir
en
la
respuesta
(javax.servlet.http.HttpServletResponse) mediante el método:
void addCookie(Cookie cookie);
Para crear una Cookie nueva utilizaremos su constructor, pasándole la información que ya
hemos comentado:
public Cookie(java.lang.String name, java.lang.String value);
A su vez, la clase Cookie tiene una serie de métodos para acceder o establecer los distintos
valores que hemos comentado. Lo más sencillo es verlo en un ejemplo. Vamos a desarrollar
una aplicación web, que implementa un contador de visitas por parte de un mismo cliente
independientemente de que cerremos el navegador mediante el uso de una Cookie:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Contador</TITLE> </HEAD> <BODY> <% Cookie cookie = null; Cookie[] cookies = request.getCookies(); if(cookies != null) { for(int i=0; i<cookies.length; i++) { if(cookies[i].getName().equals("CONTADOR")) { cookie = cookies[i]; break; } } } if(cookie == null) { cookie = new Cookie("CONTADOR","0"); } int cont = Integer.parseInt(cookie.getValue()); cookie.setValue(Integer.toString(cont+1)); cookie.setMaxAge(604800); // Una semana en segundos. 186
MÓDULO C – Unidad 7: Java Servlets Avanzado
response.addCookie(cookie); %> Número de veces visitada esta página: <%= cookie.getValue() %> </BODY> </HTML> Al ejecutar la aplicación desde un navegador y recargar (o refrescar) la página varias veces,
veremos que el contador sigue contando donde se quedó. Es mas, si paramos el servidor y
cerramos el navegador y volvemos a rearrancar todo, el contador debería seguir por donde
iba también. Sin embargo, si utilizamos otro navegador distinto o el mismo pero desde otra
máquina de nuestra red, veremos que el contador comienza en cero porque ese navegador
no tiene la Cookie guardada.
Y si le pedimos al navegador que nos muestre todas las Cookies que tiene (filtramos por
CONTADOR) veremos todos los datos de nuestra Cookie.
187
Hay varios puntos importantes que tener presentes de este ejemplo:
 Por defecto, el tiempo de expiración de la Cookie es el de la vida del navegador (tiene
el mismo efecto asignarle un valor negativo), es decir, cuando este se cierra se borra.
Asignarle un valor de cero borraría inmediatamente la Cookie. Y asignarle cualquier
otro valor positivo. es la nueva vida de la Cookie en segundos. En nuestro ejemplo,
hemos establecido que sea una semana tras cada uso.
 Cada vez que se modifica algo de la Cookie, hay que añadirla de nuevo a la respuesta.
Si no se añade, la Cookie sigue con los valores antiguos porque la respuesta contiene
una copia de la Cookie recibida y no una referencia.
 Por defecto, la ruta (o path) del servidor al que el navegador mandará la Cookie es el
de la aplicación que creo la Cookie. En nuestro caso, /EjemplosWeb/. Si el navegador
conecta con otra aplicación en otra ruta o en otro servidor, la Cookie no se enviará.
Aunque el ejemplo que hemos utilizado para presentar las Cookies es muy simple, la
potencia de esta tecnología es inmensa cuando pensamos en empresas de comercio
electrónico, de marketing, etc… Todas ellas llenan nuestro navegador de Cookies con
identificadores que les permiten a nuestro regreso recordar nuestros gustos, lo último que
hicimos en su aplicación, etc…
7.6.2 Sesión HTTP
Las Cookies por tanto, son un mecanismo muy potente para poder recordar al usuario y
actuar en consecuencia. Pero tiene algunos inconvenientes técnicos como el hecho de solo
188
MÓDULO C – Unidad 7: Java Servlets Avanzado
poder albergar 4Kb de información y que dicha información solo puede ser textual no muy
estructurada (recordemos que el valor en una Cookie es una simple cadena de caracteres).
Adicionalmente, no son muy seguras. Los usuarios pueden ver el contenido, pueden
borrarlas e incluso pueden modificarlas con mínimos conocimientos de informática.
Por este motivo, aunque basándose en la existencia de las Cookies, las especificaciones
Java EE definieron un mecanismo de persistencia en el servidor denominado Sesión HTTP (o
HTTP Session). Todos los Servidores de Aplicación Java EE implementan este servicio.
La sesión HTTP es una zona de almacenaje en el servidor exclusiva de cada cliente, donde
las aplicaciones pueden dejar información para ser utilizada en sucesivas peticiones del
mismo cliente.
Cada vez que se recibe una petición, el servidor analiza las cabeceras HTTP del mensaje en
busca de una Cookie que incluya un identificador de sesión para ponerla a disposición de la
aplicación.
Normalmente
dicha
Cookie
se
llama
JSESSIONID
y
es
gestionada
automáticamente por el servidor. Las aplicaciones manejarán la Sesión HTTP desde un
punto de vista funcional, los detalles técnicos de su mantenimiento quedan cubiertos por el
servicio ofrecido por el servidor.
La Sesión HTTP implementa el interface:
javax.servlet.http.HttpSession;
Es accesible desde la petición HTTP mediante el método:
HttpSession getSession();
que nos devolverá una referencia a la sesión de este cliente si ya existiese o a una nueva
creada en este instante y asignada a este cliente.
Existe otra opción, que es el método:
HttpSession getSession(boolean create);
La diferencia con el anterior, es que este recibe un boolean como parámetro. Si le
mandamos “true”, en caso de no existir sesión para este cliente nos devuelve la referencia a
una nueva. Si le mandamos “false”, nuevamente en caso de no existir, esta vez no la crea y
devuelve null.
Técnicamente la implementación de la Sesión HTTP es una especia de colección al estilo de
las Hashtables y HashMaps. Es decir, es una colección en la que se guardan parejas de
clave y valor, teniendo que ser ambas del tipo java.lang.Object (es decir, tipos complejos).
Tiene distintos métodos, pero los más usados son:
 java.lang.Object getAttribute(java.lang.String name);
Devuelve el valor de un atributo concreto.
 java.util.Enumeration<java.lang.String> getAttributeNames();
189
Devuelve una colección con el nombre de todos los atributos que contiene.
 void setAttribute(java.lang.String name, java.lang.Object value);
Guarda un atributo con su valor.
 void removeAttribute(java.lang.String name);
Elimina un atributo.
 void invalidate();
Elimina la sesión del servidor. Recordemos que su creación no se realiza a través de
un constructor sino simplemente pidiéndosela a la petición HTTP.
Los Servidores de Aplicación Java EE, implementan un sistema de expiración de sesiones
inactivas. El motivo es que la sesión consume recursos y no se puede garantizar ni que la
aplicación web implemente un sistema de limpieza (invocando el método invalidate() cuando
un usuario termine de trabajar con la aplicación), ni que el usuario de las aplicación web
siempre termine de manera ordenada la aplicación invocando la petición de limpieza (por
ejemplo, un logout) en vez de cerrar el navegador directamente. Sin este sistema de
expiración, podríamos terminar con “infinitas” sesiones huérfanas en el servidor.
Este tiempo de expiración, es un parámetro de configuración propio de cada servidor. En el
caso de Apache Tomcat 7.0.x se realiza en el fichero de configuración /conf/web.xml que
por defecto viene con media hora de tiempo:
<session‐config> <session‐timeout>30</session‐timeout> </session‐config> Todos los objetos que se guarden en la sesión, deben ser serializables (es decir,
implementar java.io.Serializable). El motivo es que los Servidores de Aplicación Java EE,
normalmente implementan mecanismos de persistencia de las sesiones para facilitar
mecanismos de balanceo de carga y tolerancia a fallos, para liberar recursos de memoria,
etc.. y si el contenido no es serializable no lo puede guardar.
Como buena práctica, la información guardada en la Sesión HTTP debe de ser lo más
pequeña posible.
Veamos un ejemplo similar al que mostramos con las Cookies, pero en esta ocasión añade
un botón para invalidar la sesión y comprobar como se pierde la información del contador y
comienza de nuevo en uno.
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Contador</TITLE> 190
MÓDULO C – Unidad 7: Java Servlets Avanzado
</HEAD> <BODY> <% HttpSession sesion = request.getSession(true); int cont = 1; boolean isInvalidate = false; if(request.getParameter("invalidate") != null && request.getParameter("invalidate").equals("true")) { sesion.invalidate(); isInvalidate = true; } else { if(sesion.getAttribute("CONTADOR") != null) { cont = ((Integer)sesion.getAttribute("CONTADOR")).intValue(); } sesion.setAttribute("CONTADOR", new Integer(cont+1)); } %> <FORM method="POST" action="/EjemplosWeb/sesion.jsp" > <TABLE border="0"> <% if(!isInvalidate) { %> <TR> <TD>Número de veces visitada esta página: <%= cont %></TD> </TR> <% } %> <TR> <TD>Invalidar sesión: <INPUT type="checkbox" name="invalidate" value="true"></TD> </TR> <TR> <TD><INPUT type="submit" value="Refrescar"></TD> </TR> </TABLE> </FORM> </BODY> </HTML> Al ejecutar el ejemplo desde un navegador externo, deberíamos ver algo así:
191
Y si le pedimos al navegador que nos muestre todas las Cookies que tiene (filtramos por
localhost) veremos la Cookie JSESSIONID que el Servidor de Aplicaciones Java EE ha
creado para gestionar la Sesión HTTP.
Si invalidamos la sesión mediante la checkbox, además de comprobar que el contador se
resetea porque su valor se pierde al destruirse la sesión, podremos comprobar como la
192
MÓDULO C – Unidad 7: Java Servlets Avanzado
Cookie JSESSIONID desaparece. De igual modo, si seguimos ejecutando el ejemplo
creando una nueva sesión, el valor de la Cookie (el identificador de la sesión en el servidor)
cambiará.
Otro tema importante a tener en cuenta, es que la Cookie con el identificador de la Sesión
HTTP caduca con la vida del navegador, es decir, si cerramos el navegador, al abrirlo de
nuevo y solicitar la aplicación, se crea una sesión nueva. Da igual que no la hubiéramos
invalidado antes de cerrar. Posiblemente cuando entremos de nuevo en el servidor, siga
existiendo la anterior que todavía no habrá caducado por el tiempo máximo de inactividad
pero ya no está relacionada con ningún cliente (está huérfana).
Esta es una desventaja importante frente a las Cookies, ya que en las Cookies controladas
por nuestra aplicación, la expiración era controlable.
Por eso, normalmente un carrito de la compra, se implementa mediante la Sesión HTTP
porque no tiene sentido que permanezca tras haber realizado una compra. Mientras que los
gustos o preferencias de un cliente se controlan con una Cookie para que perdure entre
compras (normalmente se mantiene un identificador de algún registro en Base de Datos
donde se han ido almacenando todas la navegaciones del cliente por la tienda).
Indicar que en ambos dos casos, las Cookies son utilizadas. En el primer caso la Cookie
guarda toda la información del estado del cliente que queremos mantener, mientras que en
la segunda guarda solamente el identificador de la Sesión HTTP del servidor que guarda la
información que queremos mantener de cada cliente.
7.7
Gestión de eventos
Las especificaciones Java EE definen una serie de notificación de eventos a los que las
aplicaciones web se pueden suscribir para ser notificadas de cuándo dichos eventos ocurren.
El funcionamiento de la gestión de eventos en las aplicaciones web funciona igual que en las
aplicaciones visuales de escritorio (AWT/Swing). Es decir, siguen más o menos el siguiente
diagrama:
193
Básicamente, contamos con dos piezas fundamentales. Un notificador (Notifier), que es quién
generará los eventos, y un escuchador (Listener) que es quien está interesado en dichos
eventos para reaccionar y actuar en consecuencia.
Para que un escuchador, pueda escuchar los eventos de un notificador, ha de subscribirse a
estos. En caso de estar subscrito, el notificador, cuando ocurra el evento, se lo notificará al
escuchador. En Java, esto significa enviar un mensaje concreto al escuchador (ejecutar un
método concreto).
El mecanismo que tenemos en Java de poder garantizar que el escuchador implementa dichos
métodos, es forzándole a implementar un interfaz. Y esto lo consigue mediante el API del
método de subscripción, que solo permite recibir parámetros de un tipo concreto. Luego el
escuchador interesado ha de ser de dicho tipo para poder subscribirse.
Un escuchador, igual que se subscribe, puede finalizar la subscripción.
Los notificadores pasan la información a los escuchadores invocando un método concreto
como ya hemos comentado, pasándole como parámetro un evento que encapsula toda la
información necesaria para conocer lo que ha ocurrido.
Los eventos contienen información sobre lo que ha ocurrido, accesible a través de distintos
métodos.
Ahora bien, existe una diferencia muy importante de operativa con las aplicaciones Java SE
(visuales de escritorio), y es que en Java EE no hay que invocar un método para suscribirse
una familia de eventos (addXXXListener), sino que basta con:
194

O informar de quién es el escuchador en el descriptor de despliegue.

O utilizar una anotación Java en el código del escuchador.
MÓDULO C – Unidad 7: Java Servlets Avanzado
Adicionalmente, no hay forma de finalizar la subscripción (removeXXXListener) como ocurre
con las aplicaciones visuales. Pero por lo demás, el mecanismo de funcionamiento es el
mismo.
Antes de ver código, vamos a revisar las familias de eventos que existen con sus métodos. En
concreto, existen tres familias de eventos:
 Relacionadas con el Contexto del Java Servlet: por ejemplo, cuándo se arranca o se
para la aplicación.
 Relacionadas con la petición: por ejemplo, cuándo se comienza a procesar una
petición.
 Relacionadas con la Sesión HTTP: por ejemplo, cuándo se invalida una sesión.
Los tipos de eventos que existen son los siguientes:
javax.servlet.ServletContextEvent
Cuando se arranca o para una aplicación web.
javax.servlet.ServletContextAttributeEvent
Cuando se crea, modifica o elimina un atributo
del contexto del Java Servlet.
javax.servlet.http.HttpSessionEvent
Cuando se crea o se destruye una sesión.
También cuando se persiste y elimina de la
memoria, y cuando se restaura de nuevo en
memoria.
javax.servlet.http.HttpSessionBindingEvent
Cuando se añade, modifica o eliminan atributos
de la sesión. También cuando un objeto ha sido
añadido o eliminado de la sesión.
javax.servlet.ServletRequestEvent
Cuando se inicializa o destruye una petición.
javax.servlet.ServletRequestAttributeEvent
Cuando se añade, modifica o elimina un atributo
de la petición.
A continuación añadiremos una tabla con un listado de todos los interfaces que hay para cada
una de las familias de eventos que hemos visto, y sus métodos:
javax.servlet.ServletContextListener
contextDestroyed
contextInitialized
attributeAdded
javax.servlet.ServletContextAttribute
attributeRemoved
attributeReplaced
javax.servlet.http.HttpSessionActivationListener
javax.servlet.http.HttpSessionBindingListener
sessionDidActivate
sessionWillPassivate
valueBound
valueUnbound
195
attributeAdded
javax.servlet.http.HttpSessionAttributeListener
attributeRemoved
attributeReplaced
javax.servlet.ServletRequestListener
requestDestroyed
requestInitialized
attributeAdded
javax.servlet.ServletRequestAttributeListener
attributeRemoved
attributeReplaced
No nos detendremos en explicar uno a uno cada método. El API Java EE esta disponible en la
web, así que no lo reproduciremos por completo aquí.
Veamos eso si, cómo se suscribe una clase a un notificador mediante el descriptor de
despliegue y mediante anotaciones Java:

Mediante descriptor de despliegue. Utilizaremos el bloque “listener” con su bloque
“listener-class”:
<listener> <listener‐class> es.aulamentor.EjemploListener </listener‐class> </listener> Y la clase es.aulamentor.EjemploListener ya implementará los interfaces necesarios
para las acciones que quiera escuchar.

Mediante anotaciones Java (recordemos que esta opción solo está disponible desde
Java EE 6.0). Utilizaremos la anotación @Weblistener
import javax.servlet.annotation.WebListener; @WebListener public class EjemploListener implements Y la clase es.aulamentor.EjemploListener ya implementará los interfaces necesarios
para las acciones que quiera escuchar.
Veamos un ejemplo que escucha todos los eventos posibles, y muestra por consola una línea
por cada evento que ha ocurrido. Lo ejecutaremos junto con la aplicación que demostraba el
uso de la Sesión HTTP para ver qué eventos se van lanzando:
package es.aulamentor; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestEvent; 196
MÓDULO C – Unidad 7: Java Servlets Avanzado
import javax.servlet.ServletRequestListener; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; @WebListener public class EjemploListener implements ServletContextListener, ServletContextAttributeListener, HttpSessionListener, HttpSessionAttributeListener, HttpSessionActivationListener, HttpSessionBindingListener, ServletRequestListener, ServletRequestAttributeListener { public void requestDestroyed(ServletRequestEvent ev) { System.out.println("Se ha invocado requestDestroyed..."); } public void attributeAdded(HttpSessionBindingEvent ev) { System.out.println("Se ha invocado attributeAdded..."); } public void contextInitialized(ServletContextEvent ev) { System.out.println("Se ha invocado contextInitialized..."); } public void sessionDidActivate(HttpSessionEvent ev) { System.out.println("Se ha invocado sessionDidActivate..."); } public void valueBound(HttpSessionBindingEvent ev) { System.out.println("Se ha invocado valueBound..."); } public void attributeAdded(ServletContextAttributeEvent ev) { System.out.println("Se ha invocado attributeAdded..."); } public void attributeRemoved(ServletContextAttributeEvent ev) { System.out.println("Se ha invocado attributeRemoved..."); } public void sessionDestroyed(HttpSessionEvent ev) { System.out.println("Se ha invocado sessionDestroyed..."); } public void attributeRemoved(HttpSessionBindingEvent ev) { System.out.println("Se ha invocado attributeRemoved..."); } 197
public void attributeAdded(ServletRequestAttributeEvent ev) { System.out.println("Se ha invocado attributeAdded..."); } public void valueUnbound(HttpSessionBindingEvent ev) { System.out.println("Se ha invocado valueUnbound..."); } public void sessionWillPassivate(HttpSessionEvent ev) { System.out.println("Se ha invocado sessionWillPassivate..."); } public void sessionCreated(HttpSessionEvent ev) { System.out.println("Se ha invocado sessionCreated..."); } public void attributeReplaced(HttpSessionBindingEvent ev) { System.out.println("Se ha invocado attributeReplaced..."); } public void attributeReplaced(ServletContextAttributeEvent ev) { System.out.println("Se ha invocado attributeReplaced..."); } public void attributeRemoved(ServletRequestAttributeEvent ev) { System.out.println("Se ha invocado attributeRemoved..."); } public void contextDestroyed(ServletContextEvent ev) { System.out.println("Se ha invocado contextDestroyed..."); } public void attributeReplaced(ServletRequestAttributeEvent ev) { System.out.println("Se ha invocado attributeReplaced..."); } public void requestInitialized(ServletRequestEvent ev) { System.out.println("Se ha invocado requestInitialized..."); } } La ejecución en el entorno de desarrollo debería mostrar algo así:
198
MÓDULO C – Unidad 7: Java Servlets Avanzado
199
200
PARA RECORDAR
 La información de configuración de un Java Servlet que es recogida mediante el
método getInitParameter del parámetro javax.servlet.ServletConfig, que es
pasado al método init del Java Servlet. Para pasar dicha información, el
administrador puede hacerlo en el despliegue de la aplicación o el desarrollador
puede hacerlo en el descriptor de despliegue o mediante anotaciones.
 Aunque el servidor de aplicaciones Java EE permite y posibilita la concurrencia en
las llamadas a un Java Servlet, hay que tener cuidado con la definición de
atributos o código que no se quiera que sea multithread.
 Hemos visto dos alternativas de acceso a Bases de datos:
 Acceso directo desde el código. Su principal problema es su pobre rendimiento.
 Acceso a través de un Pool de conexión, siendo esta la recomendada para las
aplicaciones
Java
EE.
El
método
utilizado
es
el
getConnection
de
javax.sql.DataSource
 Los filtros son unos componentes que se despliegan como parte de la aplicación
Web, y cuya misión es interceptar las peticiones y respuesta de un componente
concreto para por ejemplo, realizar algún tipo de validación, algún tipo de auditoria,
algún tipo de transformación, etc…
 Un filtro de implementar el interface: javax.servlet.Filter que incluye tres métodos:

init: Se invoca una única vez en la vida del filtro y se utiliza para realizar las
labores de inicialización.

doFilter: Es el método que realiza la lógica específica del filtro: auditoria,
transformaciones, etc…

destroy: Se invoca una única vez en la vida del filtro y se utiliza para realizar las
labores de limpieza y liberación de recursos si fuese necesario.
201
 Para el mantenimiento del estado del cliente en el servidor, se pueden utilizar:
 Cookies: es información formada por una clave y un valor que contiene
información textual. Esta cookie es creada en el servidor de aplicaciones y
almacenada en el navegador cliente utilizado en las llamadas a la aplicación
web.
 Sesión HTTP: Es una zona de almacenaje en el servidor exclusiva de cada
cliente, donde las aplicaciones pueden dejar información para ser utilizada en
sucesivas peticiones del mismo cliente.
 Las especificaciones Java EE definen una serie de notificación de eventos a los que
las aplicaciones web se pueden suscribir para ser notificadas de cuándo dichos
eventos ocurren. Contamos con dos piezas fundamentales:
 Un notificador (Notifier), que es quién generará los eventos
 Un escuchador (Listener) que es quien está interesado en dichos eventos para
reaccionar y actuar en consecuencia.
 En concreto, existen tres familias de eventos:
 Relacionadas con el Contexto del Java Servlet
 Relacionadas con la petición
 Relacionadas con la Sesión HTTP
202
Unidad de Aprendizaje 8
JAVASERVER PAGES
AVANZADO
ÍNDICE
8.1
Introducción ................................................................. 205
8.2
Etiquetas JSP estándar .............................................. 205
8.3
Lenguaje de Expresiones JSP (EL) ........................... 208
8.4
Librerías de etiquetas JSP estándar......................... 211
8.4.1 Core ................................................................................214
8.4.2 XML.................................................................................215
8.4.3 I18N.................................................................................215
8.4.4 Database ........................................................................216
8.4.5 Functions........................................................................217
8.5
Librerías de etiquetas JSP personalizadas.............. 218
PARA RECORDAR.................................................................. 224
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
8.1
Introducción
A menudo, en el desarrollo de aplicaciones web de una cierta envergadura, existen equipos de
desarrollo con roles y skills diferentes. Así, nos encontraremos con desarrolladores expertos
en Java que se encargarán normalmente del modelo y controlador, mientras que tendremos
otro grupo de desarrolladores expertos en diseño que se encargarán de la presentación.
Estos expertos en diseño, no suelen conocer ni manejar el lenguaje Java, centrando sus skills
más en diseño gráfico, tratamiento de imágenes, etc… por lo que al desarrollar la presentación
emplearán herramientas más orientadas a etiquetas que a programar con el lenguaje Java.
Por este motivo, la especificación de JavaServer Pages (JSP) define una serie de mecanismos
para seguir permitiendo el desarrollo de la presentación sin necesidad de escribir líneas de
lenguaje Java.
Estos mecanismos son:

Las acciones JSP estándar.

Las librerías de etiquetas JSP
Esta unidad se centra en el estudio de ambos mecanismos.
8.2
Etiquetas JSP estándar
Las etiquetas JSP estándar, son etiquetas del estilo de las empleadas en las páginas HTML o
en los descriptores de despliegue (XML) que permiten realizar acciones en el momento de
ejecución de la página.
Cualquier etiqueta JSP podría ser sustituida sin ningún problema por código Java equivalente
como ya hicimos en unidades anteriores.
La sintaxis de una etiqueta JSP consiste en el prefijo “jsp:” seguido del identificador de la
acción y opcionalmente atributos (parejas de nombre y valor).
Las especificaciones definen múltiples etiquetas JSP estándar, a saber:

<jsp:forward>: redirige la petición a otra página JSP, HTML o Java Servlet.

<jsp:include>: incluye el resultado de otra página JSP, Java Servlet u otro componente
web estático.

<jsp:param>: se utiliza dentro de un bloque de <jsp:forward> o <jsp:include> para
indicar los parámetros que opcionalmente se pueden enviar.

<jsp:useBean>: referencia o instancia una clase Java y la asocia un nombre y un
ámbito concreto.

<jsp:setProperty>: inserta un valor a un atributo del bean (o clase Java).

<jsp:getProperty>: recoge el valor de un atributo del bean (o clase Java) y lo incluye en
la respuesta
205

<jsp:text>: inserta texto en la respuesta.

<jsp:element>: inserta un elemento XML en la respuesta.

<jsp:plugin>: inserta un Applet Java en la respuesta.

<jsp:output>: inserta la etiqueta XML DOCTYPE de toda JSP en la respuesta.

<jsp:body>: identifica el comienzo del cuerpo del documento HTML (viene a sustituir a
<BODY>). Se ha de utilizar siempre que en la página se utilice la acción
<jsp:attribute>.

Otras: <jsp:root>, <jsp:invoke>, <jsp:doBody>, <jsp:attribute>, …
Son muchas las etiquetas pero trataremos solo algunas de ellas porque en general, a
excepción de unas pocas, su uso es muy raro.
La etiqueta <jsp:include> produce un efecto exactamente igual que el de la directiva <%@
include file=”xxx” %> que ya hemos visto y practicado en alguna actividad durante el curso.
La diferencia es que el atributo que necesita se llama “page”.
Algunos ejemplos:
<jsp:include page="copyright.html" /> <jsp:include page="/index.html" /> <jsp:include page="/login.jsp"> <jsp:param name="usuario" value="pepe" /> </jsp:include>
Y la etiqueta <jsp:forward> es parecida a <jsp:include> con la diferencia de que no incluye el
resultado, sino que delega en ese nuevo recurso la respuesta.
Algunos ejemplos:
<jsp:forward page="/servlet/login" /> <jsp:forward page="/servlet/login"> <jsp:param name="usuario" value="pepe" /> </jsp:forward>
Otra etiqueta típica es la de referenciar o instanciar una clase Java para trabajar con ella.
Como vimos en la enumeración de etiquetas existentes, la etiqueta a emplear es
<jsp:useBean>. Esta etiqueta busca un objeto con el identificador dado en el ámbito
seleccionado y de no encontrarlo, lo crea con dicho identificador en dicho ámbito.
Utiliza por tanto estos tres atributos:
206

id: identificador del objeto.

scope: ámbito donde buscar o crearlo. Existen cuatro valores posibles:
o
request: la petición.
o
page: la página:
o
session: la sesión HTTP.
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
o

application: la aplicación.
class: la clase Java (el tipo).
Por ejemplo:
<jsp:useBean id="cesta" scope="session" class="edu.aulamentor.Cesta"/> Esta etiqueta busca en la sesión HTTP un objeto de la clase edu.aulamentor.Cesta que se
llama cesta. Si no existiera lo crea.
¿Y esto para qué? Pues normalmente va a acompañado de las etiquetas <jsp:setProperty> y
<jsp:getProperty> para utilizar el objeto en cuestión.
<jsp:setProperty> nos permite establecer el valor de alguno de los atributos del objeto. Para
ello utiliza tres atributos:

name: identificador del objeto.

attribute: atributo del objeto.

value: valor del atributo del objeto.
Por ejemplo:
<jsp:useBean id="cesta" scope="session" class="edu.aulamentor.Cesta"/> <jsp:setProperty name="cesta" property="total" value="0.0" />
De igual forma, podemos acceder al valor de un atributo del objeto mediante la acción
<jsp:getAttribute>. Para ello utiliza dos atributos:

name: identificador del objeto.

attribute: atributo del objeto.
Por ejemplo:
Total de la cesta es: <jsp:getProperty name="cesta" property="total"/> Para que estas etiquetas funcionen bien, la clase Java debe seguir las especificaciones
JavaBean. Esto significa que, entre otras cosas, la clase debe tener un constructor por defecto
(constructor sin parámetros) y un getter/setter por cada atributo (siguiendo la norma de utilizar
get y set seguido del nombre del atributo con la primera letra en mayúsculas). Es decir, en
nuestro ejemplo:
package es.aulamentor; public class Cesta { private double total; public Cesta() { } 207
public double getTotal() { return this.total; } public void setTotal(double param) { this.total = param; } } Simplemente por comparar, este mismo ejemplo pero con código Java habría sido algo así:
<% es.aulamentor.Cesta cesta = (es.aulamentor.Cesta)session.getAttribute(“cesta”); cesta.setTotal(0.0); %> Total de la cesta es: <%= cesta.getTotal() %>
Pero la etiqueta <jsp:setProperty> puede tener un uso más potente todavía, y es el de
transferir el valor de los parámetros de un formulario que se reciba en una petición a los
atributos de un objeto Java sin necesidad de ir uno a uno. Basta con eliminar el atributo value:
<jsp:useBean id="cesta" scope="session" class="es.aulamentor.Cesta" /> <jsp:setProperty name="cesta" property="*" /> En este caso, el servidor va a buscar todos (porque hemos usado el carácter * en vez de un
nombre concreto) aquellos parámetros que vengan en la petición que se llamen igual que
algún atributo de la clase Cesta y ponerle su valor.
8.3
Lenguaje de Expresiones JSP (EL)
Conocido con el acrónimo EL (Expression Language).
EL es un pseudolenguaje para identificar y acceder de una manera muy sencilla a las variables.
Veamos primero un ejemplo con el que se verá rápidamente la idea. Mediante código Java,
para acceder por ejemplo al atributo nombre, de un objeto de tipo Perro guardado en un
atributo llamado perro en un objeto de tipo Persona que está guardado en la Sesión HTTP con
el identificador de persona escribiríamos algo así:
Se llama: <%= ((es.aulamentor.Persona)session.getAttribute(“persona”)).getPerro().getN
ombre() %> Sin embargo, utilizando EL sería algo así:
Se llama: ${persona.perro.nombre} Sencillo, ¿verdad?
208
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
La sintaxis y opciones de EL son realmente sencillas. Ahora, es muy importante no pensar en
Java cuando usemos EL y viceversa, porque aunque se parecen son distintos y nos llevarán a
equivocaciones.
Las expresiones EL siempre van entre llaves ({ }) precedidas del símbolo del dólar ($):
${ } El contenido de las llaves siempre será uno o varios identificadores separados por puntos.
El primer identificador puede ser dos cosas:

Una referencia a un objeto implícito: que existe en el contenedor web y es accesible
directamente.

Un atributo existente en uno de los distintos ámbitos: página, petición, sesión o
aplicación. Es importante tener en cuenta que se busca en ese orden, por si existiese
más de un atributo con el mismo nombre en ámbitos diferentes.
Todos los objetos implícitos son una colección del tipo Map, es decir, contiene parejas de
clave y valor. Estos son los que hay:

pageScope: ámbito de la página.

requestScope: ámbito de la petición.

sessionScope: ámbito de la sesión.

applicationScope: ámbito de la aplicación.

param: parámetros de la petición.

paramValues: parámetros de la petición en caso de que el parámetro sea a su vez una
colección.

header: cabeceras de la petición.

headerValues: cabeceras de la petición en caso de que la cabecera sea a su vez una
colección.

cookie: cookies de la petición.

initParam: parámetros del contexto.

pageContext: es el único que no es un Map. Directamente es una referencia a una
instancia de la clase javax.servlet.jsp.PageContext
Por tanto, si queremos referenciar al atributo persona que está en la Sesión HTTP tenemos
dos opciones:
${persona} o para evitar colisiones en el caso de que existiese otro atributo con el mismo nombre en
ámbitos con mayor precedencia:
209
${sessionScope.persona} Ahora, si queremos seguir profundizando en el atributo, accediendo a otros atributos más
internos en su estructura (como el ejemplo anterior donde accedimos al nombre del perro de la
persona), es cuando utilizaremos una secuencia de nombres de atributos separados por
puntos:
${sessionScope.persona.perro.nombre} Ahora bien, llegados a este punto es importante volver a recordar, que esto solo funciona si las
clases Java accedidas siguen las especificaciones JavaBean, que entre otras cosas obligan a
que:

La clase tenga un constructor por defecto (sin parámetros).

La clase tenga un método getter por cada atributo siguiendo la regla de que se llamara
get seguido del nombre del atributo con la primera letra en mayúscula.

La clase tenga un método setter por cada atributo siguiendo la regla de que se llamara
set seguido del nombre del atributo con la primera letra en mayúscula.
Por tanto, para que funcione el ejemplo:
${sessionScope.persona.perro.nombre} significa que la clase Persona tiene un método que se llama getPerro() y que la clase Perro
tiene un método que se llama getNombre(). Si esto no fuese así, la compilación de la página
JSP fallaría.
Veamos otro ejemplo de cómo sería el acceso al valor de una Cookie. Usando Java sería algo
así:
<% Cookie[] cookies = request.getCookies(); for(int i=0; i<cookies.lenght; i++) { if((cookies[i].getName()).equals(“nombreUsuario”)) { %> <%= cookies[i].getValue() %> <% } } %>
Con EL sería simplemente esta línea:
${cookie.nombreUsuario.value} Las expresiones EL también admiten el uso de corchetes ([]). Su uso vale para dos cosas:
210
MÓDULO C – Unidad 8: JavaServer Pages Avanzado

Lo
mismo
que
el
punto,
es
decir,
${perro.nombre}
es
equivalente
a
${perro[“nombre”]} usando las comillas dobles para especificar el nombre del
atributo.

Para profundizar en atributos que son de algún tipo de colección (array, Map o List),
por ejemplo: ${perros[3].nombre}
Las expresiones EL también permiten implementar una mínima lógica, aunque no está
recomendado su uso para ello. Soporta los operadores aritméticos (+, -, *, / y %), los
operadores lógicos (&&, || y !) y los operadores relacionales (==, ¡=, <, >, <= y >=).
Otro dato a tener muy en cuenta es que las expresiones EL pueden ser usadas como valores
de los atributos de las etiquetas JSP que ya hemos comentado en la sección anterior y en las
que comentaremos a continuación.
8.4
Librerías de etiquetas JSP estándar
Al igual que existen las etiquetas JSP estándar definidas en las especificaciones JSP, con el
tiempo surgió otra especificación denominada JSTL (JavaServer Page Standard Tag Library o
Librería de etiquetas JSP estándar) que aglutina una serie de librerías de etiquetas o acciones
adicionales que persiguen el mismo objetivo que las anteriores: facilitar la programación de la
presentación de las aplicaciones web a diseñadores gráficos sin conocimientos del lenguaje
Java mediante herramientas visuales orientadas al manejo de etiquetas.
En este curso no pretendemos cubrir todas y cada una de las etiquetas, pero si comentar
cómo se especifica el uso de una librería, qué librerías hay, y algún ejemplo.
La guía de referencia completa de JSTL está disponible en:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
Actualmente existen cinco librerías de etiquetas presentes en cualquier servidor de
aplicaciones Java EE completo:

Core (en castellano principal): Su prefijo es c y su URI http://java.sun.com/jsp/jstl/core.
Cubre funcionalidades básicas como el manejo de variables, el control del flujo, la
gestión de URLs y otras acciones.

XML: Su prefijo es x y su URI http://java.sun.com/jsp/jstl/xml. Cubre funcionalidades
de gestión de ficheros XML.

I18N
(en
castellano
internacionalización):
Su
prefijo
es
fmt
y
su
URI
http://java.sun.com/jsp/jstl/fmt. Cubre funcionalidades de formateo de mensajes,
números, fechas, horas, etc… teniendo en cuenta la localización de cada cliente.

Database
(en
castellano,
Base
de
Datos):
Su
prefijo
es
sql
y
su
URI
http://java.sun.com/jsp/jstl/sql. Cubre funcionalidades de acceso a Bases de Datos.
211

Functions
(en
castellano
funciones):
Su
prefijo
es
fn
y
su
URI
http://java.sun.com/jsp/jstl/functions. Cubre funcionalidades relacionadas con el
manejo de cadenas de caracteres.
Antes de entrar más en detalle en cada librería, vamos a ver cómo se indica en una página JSP
el uso de una librería. Para ello se utiliza una directiva que ya mencionamos en una unidad
anterior pero que no explicamos en detalle “taglib”:
<%@ taglib uri=”xxx” prefix=”xxx” %> Recibe dos atributos:
 URI: identificador del espacio de nombres (viene a significar algo parecido a los
paquetes Java para evitar colisiones de dos etiquetas de mismo nombre).
 prefix: identificador de la librería a utilizar.
Por tanto, si en nuestra página JSP queremos utilizar por ejemplo las librerías Core y Database
deberíamos añadir estas dos líneas al inicio de la página:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> El uso de una acción concreta de una de estas librerías, sigue la sintaxis de las acciones JSP
estándar: pero cambiando “jsp” por el prefijo de la librería, seguido de los dos puntos,
seguidos de la acción en cuestión, seguida de sus atributos.
Por ejemplo, el uso de la acción “set” de la librería Core sería algo así:
<c:set var="titulo" value="Don Quijote"/> Pero ¿qué pasa cuando añadimos una de estas directivas en Eclipse IDE for Java EE
Developers? Salen errores.
El motivo, es que Apache Tomcat no cumple el 100% de las especificaciones Java EE, y en
concreto JSTL 1.2 no lo cumple. Pero es muy sencillo añadir la implementación de referencia
de la especificación a nuestra aplicación web, añadiendo a /WebContent/WEB-INF/lib estos
dos ficheros JAR:

http://search.maven.org/remotecontent?filepath=javax/servlet/jsp/jstl/javax.servlet.jsp.j
stl-api/1.2.1/javax.servlet.jsp.jstl-api-1.2.1.jar

http://search.maven.org/remotecontent?filepath=org/glassfish/web/javax.servlet.jsp.jst
l/1.2.1/javax.servlet.jsp.jstl-1.2.1.jar
212
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
Una vez hemos copiado ambos dos ficheros en el directorio /WebContent/WEB-INF/lib del
proyecto, si no se fuese el error forzamos una recompilación mediante la opción de menú:
“Project” -> “Clean…”:
Revisemos a continuación brevemente las etiquetas de cada una de las librerías estándar.
Como ya comentamos, no va a ser una explicación exhaustiva. Simplemente pretendemos
que se conozcan qué posibilidades hay y dónde poder consultar en caso de llegar a
necesitarse alguna.
213
8.4.1 Core
Implementa acciones básicas para el tratamiento de variables, control de flujo, gestión de
URLs, y otras:
 Gestión de variables:
o set: estable el valor de una variable EL o del atributo de una variable EL en uno
de los ámbitos posibles. Si dicha variable no existiese la crea.
<c:set var="titulo" scope="session" value="${param.titulo}"/> o remove: elimina una variable EL.
<c:remove var="cart" scope="session"/>  Control de flujo:
o choose junto con when y otherwise: viene a ser una especie de estructura
switch, case, default de Java. Evalúa las condiciones EL de cada etiqueta
when y entra por la que sea true. Si ninguna fuese true, ejecuta la otherwise.
<c:choose> <c:when test="${cont == 0}" > No se ha encontrado ningún elemento. </c:when> <c:otherwise> Se han encontrado ${cont} elementos. </c:otherwise> </c:choose> o forEach: permite iterar por una colección de elementos.
<c:forEach var="libro" items="${sessionScope.cesta.libros}"> <TR> <TD align="right" bgcolor="#ffffff"> ${libro.titulo} </TD> </TR> </c:forEach> o forTokens: permite iterar por una colección de tokens separados por un
delimitador.
o if: evalúa una condición EL y si es true sigue ejecutando el contenido del
bloque.
<c:if test="${param.nombre == ‘Pepe’}"> <H1>El nombre es Pepe.</H1> </c:if>  Gestión de URLs:
o import: importa el contenido de un recurso de Internet en una variable EL.
Puede utilizar param para especificar parámetros.
<c:import url="/introduccion.txt" var="texto" /> o redirect: envía al cliente un código HTTP de redirección. Puede utilizar param
para especificar parámetros.
214
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
o url: guarda URLs en una variable EL. Puede utilizar param para especificar
parámetros.
 Otras:
o catch: captura una excepción. La excepción no se propaga y por tanto no se
invocará la página JSP de error si la hubiera.
o out: evalúa una expresión EL y devuelve su valor.
Más detalles y ejemplos:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
8.4.2 XML
Implementa acciones básicas para el parseo de documentos XML, control de flujo
recorriendo estructuras XML y transformaciones:
 Parseo:
o out: evalúa una expresión XPath y su resultado lo devuelve como parte de la
respuesta.
o parse: parsea un documento XMl y guarda el contenido en una variable
identificada mediante EL.
o set: evalúa una expresión XPath y su resultado lo guarda en una variable
identificada mediante EL.
 Control de flujo:
o choose junto con when y otherwise: similar a la librería Core pero itera sobre el
resultado de evaluar una expresión XPath sobre un documento XML.
o forEach: similar a la librería Core pero itera sobre el resultado de evaluar una
expresión XPath sobre un documento XML.
o if: similar a la librería Core pero itera sobre el resultado de evaluar una
expresión XPath sobre un documento XML.
 Transformación:
o transform: aplica una transformación a un documento XML especificado en el
atributo doc definida en una plantilla XSLT especificada en el atributo xslt.
Más detalles y ejemplos:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
8.4.3 I18N
Implementa acciones básicas para la gestión de la localización, seleccionar los mensajes a
mostrar en base a dicha localización y el formateo de números y fechas:
 Localización:
o setLocale: fuerza una localización concreta independientemente de la que
enviara el cliente web.
o requestEncoding: especifica la codificación a utilizar para interpretar los
parámetros de una petición.
 Mensajes:
215
o bundle: especifica el conjunto de recursos “localizados” a utilizar.
o setBundle: similar a bundle pero para un contexto específico.
o message: sirve para añadir a la respuesta un texto “localizado” especificando
en el atributo key la clave de dicho texto dentro del bundle.
 Formateo:
o formatNumber: formatea un número teniendo en cuenta la localización.
o formatDate: formatea una fecha teniendo en cuenta la localización.
o parseNumber: convierte una cadena de texto en un número teniendo en
cuenta la localización.
o parseDate: convierte una cadena de texto en una fecha teniendo en cuenta la
localización.
o setTimeZone: especifica la zona horaria.
Más detalles y ejemplos:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
8.4.4 Database
Implementa acciones básicas para el acceso a las Bases de Datos:
 Configuración:
o setDataSource: sirve para especificar el identificador JNDI del Data Source a
utilizar.
<sql:setDataSource dataSource="jdbc/TestDB" />  SQL:
o query: ejecuta una query que devuelve un resultado que guarda en el atributo
var. Dicho resultado es un Java Bean con los siguientes atributos (a tener en
cuenta para poder explotar la información resultante mediante EL):
 public String[] columnNames
 public int rowCount
 public Map[] rows()
 public Object[][] rowsByIndex
 public boolean limitedByMaxRows
Un ejemplo imaginando que tenemos una tabla LIBROS con columnas como
AUTOR, TITULO y PAGINAS:
<sql:query var="libros" sql="select * from LIBROS where AUTOR = ?" > <sql:param value="${autor}" /> </sql:query> <c:forEach var="libro" begin="0" items="${libros.rows}"> <H2>${libro.titulo}</H2><BR> Núm. De Páginas: ${libro.paginas}<BR><BR> </c:forEach> 216
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
o update: ejecuta una actualización en la Base de Datos.
o transaction: sirve para aglutinar varias queries y/o updates en una unidad
transaccional.
Más detalles y ejemplos:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
8.4.5 Functions
Implementa acciones básicas de manejo de cadenas de caracteres pero al contrario que
todas las librerías anteriores, estás no son etiquetas como tal sino funciones a emplear en
una EL:

length: devuelve la longitud de una colección.
<c:if test="${fn:length(parametro.nombre) > 0}" > Longitud del nombre mayor de cero. Correcto! </c:if> 
toUpperCase: devuelve la cadena en mayúsculas.

toLowerCase: devuelve la cadena en minúsculas.

substring: devuelve una parte de una cadena.

substringAfter: devuelve una parte de una cadena a partir de un carácter
especificado.

substringBefore: devuelve una parte de una cadena antes de un carácter
especificado.

trim: devuelve la cadena sin espacios en blanco por delante ni por detrás.

replace: devuelve una cadena con un carácter/cadena remplazado por otro.

indexOf: devuelve la posición de un carácter/cadena especificado.

startsWith: chequea si una cadena comienza con un carácter/cadena especificado.

endsWith: chequea si una cadena termina con un carácter/cadena especificado.

contains: chequea si una cadena contiene un carácter/cadena especificado.

containsIgnoreCase: chequea si una cadena contiene un carácter/cadena
especificado ignorando las mayúsculas y minúsculas.

split: divide una cadena devolviendo un array de cadenas.

join: devuelve la unión de varias cadenas en una sola cadena.

escapeXml: devuelve la cadena habiendo cambiado los caracteres especiales por
sus valores codificados para poder ser usados en una URL.
Más detalles y ejemplos:
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
217
8.5
Librerías de etiquetas JSP personalizadas
Al igual que existen las librerías de etiquetas JSP estándar estudiadas en la sección anterior,
las especificaciones Java EE contemplan la posibilidad de que podamos definir e implementar
nuestra propia librería de etiquetas. De esta forma, en caso de haber decidido minimizar el
código Java que aparecerá en las páginas JSP podemos implementar etiquetas que cubran
necesidades particulares de nuestra aplicación.
De igual forma, encontraremos en Internet cantidad de librerías adicionales de etiquetas
desarrolladas por terceras personas.
El API necesario para la implementación de etiquetas personalizadas se encuentra en el
paquete: javax.servlet.jsp.tagext;
La implementación de una etiqueta personalizada siempre ha de implementar el interface:
javax.servlet.jsp.tagext.Tag
o extender la clase:
javax.servlet.jsp.tagext.TagSupport
que es una clase que contiene implementaciones por defecto de los métodos del interface
Tag.
El interface Tag tiene varios métodos, pero aquí solo comentaremos:

int doStartTag() throws JspException
Este método es invocado cuando el contenedor web detecta el inicio de la etiqueta. Lo
normal, es usar este método para implementar la lógica asociada a la etiqueta. Debe
devolver un número entero que corresponde a una de estas constantes definidas en el
interface Tag:
o
SKIP_BODY: significa que la etiqueta ya ha procesado el resto de etiquetas o
contenido incluido dentro de su bloque (si lo hubiera) así que el contenedor
web puede proceder con el final de la etiqueta.
o
EVAL_BODY_INCLUDE: significa que la etiqueta no ha procesado el resto de
etiquetas o contenido incluido dentro de su bloque (si lo hubiera) así que el
contendor web debe procesar ese contenido antes de proceder con el final de
la etiqueta.

int doEndTag() throws JspException
Este método es invocado cuando el contenedor web detecta el final de la etiqueta.
Debe devolver un número entero que corresponde a una de estas constantes definidas
en el interface Tag:
o
EVAL_PAGE: indica al contendor web que continúe con el proceso de
ejecución normal de la página JSP.
218
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
o
SKIP_PAGE: indica al contendor web que interrumpa el proceso de ejecución
normal de la página JSP.
Si la nueva etiqueta va a soportar atributos, entonces la implementación Java debe incluir un
atributo con un método setter con idéntico nombre por cada uno. El método setter debe seguir
las especificaciones JavaBean, es decir, debe llamarse set seguido del nombre del atributo
con la primera letra en mayúsculas.
El contenedor web, al encontrarse con la nueva etiqueta, instanciará la implementación y
especificará los valores de todos los atributos basado en los valores que se encuentran en la
etiqueta en la página JSP.
Al extender la clase TagSupport, tenemos acceso a una variable con nombre pageContext de
tipo:
javax.servlet.jsp.PageContext
que nos permite acceder al writer (java.io.Writer) de la respuesta, para poder escribir el
resultado de la ejecución de la etiqueta mediante el método:
public JspWriter getOut()
Veamos un ejemplo. Vamos a definir e implementar una etiqueta que añada por delante y por
detrás del contenido de su cuerpo (el bloque definido por la etiqueta) un carácter un número
concreto de veces. Para ello, tendrá dos atributos donde especifiquemos el carácter y el
número de veces llamados “caracter” y “veces”.
Esta sería la implementación:
package es.aulamentor; import java.io.IOException; import java.io.Writer; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; public class RepiteTag extends TagSupport { private char caracter; private int veces; public void setCaracter(char carcater) { this.caracter = carcater; } public void setVeces(int veces) { this.veces = veces; } public int doStartTag() throws JspException { 219
Writer out = pageContext.getOut(); for(int i=0; i<veces; i++) { try { out.write(caracter); } catch(IOException ex) { ex.printStackTrace(); } } return Tag.EVAL_BODY_INCLUDE; } public int doEndTag() throws JspException { Writer out = pageContext.getOut(); for(int i=0; i<veces; i++) { try { out.write(caracter); } catch(IOException ex) { ex.printStackTrace(); } } return Tag.EVAL_PAGE; } } A continuación, necesitamos crear un fichero de configuración XML donde se le indica al
Servidor Java EE la existencia de una librería personalizada y los detalles. Este fichero de
extensión *.tld debe formar parte de la aplicación web y su ubicación es un directorio tlds en
/WEB-INF
En nuestro caso lo llamamos AulaMentorTagLib.tld:
220
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
Este fichero, sigue una sintaxis concreta. Veamos el contenido para nuestro ejemplo y
repasaremos las etiquetas más relevantes:
<?xml version="1.0" encoding="UTF‐8"?> <taglib version="2.1" 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 http://java.sun.com/xml/ns/javaee/web‐jsptaglibrary_2_1.xsd"> <tlib‐version>1.0</tlib‐version> <short‐name>Aula_Mentor_Tag_Library</short‐name> <uri>http://www.aulamentor.es/jsp/jstl/tags</uri> <tag> <name>repite</name> <tag‐class>es.aulamentor.RepiteTag</tag‐class> <body‐content>scriptless</body‐content> <attribute> <name>caracter</name> <required>true</required> </attribute> <attribute> <name>veces</name> <required>false</required> </attribute> </tag> </taglib>
La primera línea indica que se trata de un archivo XML.
La segunda indica que se trata de la definición de una librería de etiquetas.
Como bloques o etiquetas relevantes tenemos:

uri: a la que luego haremos referencia desde la página JSP para indicar que usamos
esta librería.
221

tag: incluye la definición de una etiqueta personalizada.

name: el identificador de la etiqueta cuando la usemos en una página JSP.

tag-class: la clase Java que implementa el comportamiento de la etiqueta.

body-content: indica si la etiqueta puede albergar contenido dentro de su bloque o no
(entre la etiqueta de inicio y la de cerrado). Puede tomar varios valores:
o
empty: no puede tener contenido.
o
scriptless: puede tener contenido pero solo otras etiquetas, no código de
script.
o

tagdependent: puede contener cualquier cosa.
attribute: incluye la definición de un atributo de la etiqueta. Indica su nombre que
usaremos luego en la página JSP y si es obligatorio o no.
Por último, ya solo nos queda utilizar la nueva etiqueta en la aplicación. Para ello vamos a
crear una página JSP muy sencilla:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <%@ taglib uri="http://www.aulamentor.es/jsp/jstl/tags" prefix="am" %> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Prueba de Tag Personalizada</TITLE> </HEAD> <BODY> <am:repite caracter="*" veces="5"> PRUEBA </am:repite> <BODY> </HTML> Primero, fijémonos en cómo decimos que vamos a utilizar etiquetas de la nueva librería:
<%@ taglib uri="http://www.aulamentor.es/jsp/jstl/tags" prefix="am" %> La URI debe coincidir exactamente con la que especificamos en le fichero de configuración de
la librería. Y el prefijo, puede ser cualquiera. En este caso hemos decidido que sea: am.
Ahora, veamos dónde y cómo hemos usado la etiqueta:
<am:repite caracter="*" veces="5"> PRUEBA </am:repite> Identificada con el prefijo y utilizando exactamente el mismo nombre que usamos en el fichero
de configuración. Hemos usado también sus dos atributos (solo carácter era obligatorio).
222
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
El resultado de su ejecución, debería ser la palabra PRUEBA rodeada de cinco asteriscos por
delante y detrás:
El API para la creación de etiquetas personalizadas es más extenso de lo que hemos visto en
esta sección. Aquí hemos repasado las bases para la creación de etiquetas sencillas, pero el
API ofrece más posibilidades que si el alumno está interesado puede profundizar consultando
la guía de referencia en Internet:
http://docs.oracle.com/javaee/6/api/javax/servlet/jsp/tagext/packagesummary.html#package_description
223
PARA RECORDAR
 Las etiquetas JSP estándar, son etiquetas del estilo de las empleadas en las
páginas HTML o en los descriptores de despliegue (XML) que permiten realizar
acciones en el momento de ejecución de la página. Su sintaxis consiste en el prefijo
“jsp:”.
 Las Expression Language (EL) son un pseudolenguaje para identificar y acceder
de una manera muy sencilla a las variables. Su sintaxis es ${…}
 La especificación JSTL (JavaServer Page Standard Tag Library o Librería de
etiquetas JSP estándar) aglutina una serie de librerías de etiquetas o acciones
adicionales. Se especifican mediante la directiva “taglib”.
 Las librerías existentes en un servidor de aplicaciones Java EE son:
 Core: Cubre funcionalidades básicas como el manejo de variables, el control del
flujo, la gestión de URLs y otras acciones.
 XML: Cubre funcionalidades de gestión de ficheros XML.
 I18: Cubre funcionalidades de formateo de mensajes, números, fechas, horas,
etc… teniendo en cuenta la localización de cada cliente.
 Database: Cubre funcionalidades de acceso a Bases de Datos.
 Functions: Cubre funcionalidades relacionadas con el manejo de cadenas de
caracteres.
 Las especificaciones Java EE contemplan la posibilidad de que podamos definir
implementar nuestra propia librería de etiquetas. La implementación de una etiqueta
personalizada siempre ha de implementar el interface, javax.servlet.jsp.tagext.Tag
o extender la clase javax.servlet.jsp.tagext.TagSupport
224
Unidad de Aprendizaje 9
OTROS CONCEPTOS AVANZADO
ÍNDICE
9.1
Introducción ................................................................. 227
9.2
Gestión de errores....................................................... 227
9.3
Gestión de la seguridad.............................................. 232
9.4
Frameworks de desarrollo web................................. 244
9.4.1 JavaServer Faces .........................................................244
9.4.2 Apache Struts................................................................245
9.4.3 Spring Source................................................................245
9.4.4 Apache Wicket ..............................................................246
PARA RECORDAR.................................................................. 247
MÓDULO C – Unidad 9: Otros conceptos
9.1 Introducción Esta es la última unidad del curso. En ella trataremos algunos temas no menos importantes
que no han tenido cabida en las unidades anteriores como son la gestión de errores y la
seguridad en Java EE.
Por último, daremos una breve pincelada de algunos frameworks de desarrollo de aplicaciones
web, que construidos sobre los conceptos que hemos visto en este curso pretenden acelerar y
facilitar el desarrollo de aplicaciones web. La idea es simplemente que el alumno conozca de
su existencia y profundice en alguno de ellos si los encuentra de interés. Cada uno de ellos por
si solo, daría lugar a un curso completo.
9.2
Gestión de errores
Según las especificaciones Java EE, existen dos alternativas no excluyentes para la gestión de
errores:

Programática: Toda la gestión se lleva dentro de la aplicación mediante código
fuente. Es el modo que hemos estado empleando hasta ahora en todos los
ejemplos de las distintas unidades.

Declarativa: La gestión se externaliza en configuraciones en el descriptor de
despliegue.
Evidentemente cada una tiene sus ventajas e inconvenientes. Por un lado, la programática es
la gestión más potente y flexible, sin embargo el código es más complejo y la lógica más
complicada de seguir. Por otro lado, la declarativa es la gestión más sencilla pero por otro
lado tiene más restricciones.
La gestión programática ya la conocemos. Mediante las estructura try & catch o cualquier otro
medio de detección de errores, realizamos mediante código redirecciones a páginas concretas
de tratamiento y muestra del error. Por tanto, en esta unidad nos vamos a ceñir a la gestión
declarativa.
Mediante la gestión declarativa podemos controlar dos aspectos:

Errores HTTP: Qué eran y qué tipos de errores HTTP existían ya lo estudiamos en
la unidad dedicada al protocolo HTTP en este mismo curso. Es el propio Servidor
de Aplicaciones Java EE el que habitualmente gestiona este tipo de errores
mostrando una página de error. Pero las especificaciones Java EE nos permiten
definir en el descriptor de despliegue un componente web (página HTML, página
JSP, Java Servlet, etc…) que se invocará cuando ocurra dicho error en vez de
mostrar la página por defecto del servidor.
Por ejemplo, la página por defecto para un error 404 (recurso no encontrado) de
Apache Tomcat 7.0.x es la siguiente:
227
Sin embargo, mediante los bloques “error-page” y sus bloques “error-code” (para
especificar el código de error) y “location” (para especificar qué componente web
invocar) podemos cambiar este comportamiento por defecto.
Veamos un ejemplo de cómo cambiar la página que se muestra para el error HTTP
404:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <error‐page> <error‐code>404</error‐code> <location>/Error404.jsp</location> </error‐page> </web‐app>
Y esta es la página JSP:
<%@ page language="java" contentType="text/html; charset=ISO‐
8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐8859‐1"> <TITLE>Página no encontrada. Disculpe las molestías...</TITLE> </HEAD> <BODY> Página no encontrada. Disculpe las molestías...<BR/> Si el problemea persiste póngase en contacto con el administrador.<BR/> <%= Calendar.getInstance().getTime() %> </BODY> </HTML> 228
MÓDULO C – Unidad 9: Otros conceptos
Este sería el resultado ahora:
Y así podríamos hacer con todos los tipos de errores HTTP más habituales,
consiguiendo dar una imagen más corporativa y cercana al usuario (evidentemente la
página de nuestro ejemplo no es ninguna de las dos cosas).

Excepciones Java: También se pueden gestionar de manera declarativa las
excepciones Java que se produzcan. Lo más habitual, es hacerlo con aquellas
excepciones
Java
no
esperadas
o
con
difícil
solución.
Por
ejemplo,
java.lang.NullPointerException. Pero podemos gestionar cualquiera que queramos.
Veamos primero cómo contesta por defecto Apache Tomcat 7.0.x a una excepción del
tipo java.lang.NullPointerException no capturada.
229
El mecanismo para declarar qué componente invocar cuando se produzca una
excepción concreta, es similar al visto anteriormente. La única diferencia es que en vez
del bloque “error-code” usaremos “exception-type”.
Otra diferencia, es que el Servidor de Aplicaciones Java EE nos pasará en la petición
dos atributos (ojo, no parámetros):
o
javax.servlet.error.exception: Conteniendo la excepción que se ha
producido (no el nombre, sino la instancia como tal).
o
javax.servlet.error.request_uri: Indicando el componente que produjo el
error.
Veamos un ejemplo de cómo cambiar la página que se muestra para la excepción
java.lang.Exception no capturada y tratada en el código:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <error‐page> <exception-type>java.lang.NullPointerException</exception-type> <location>/NullPointerException.jsp</location> </error‐page> </web‐app>
Y esta es la página JSP:
<%@page import="java.util.Calendar"%> <%@ page language="java" contentType="text/html; charset=ISO‐
8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐8859‐1"> <TITLE>Error no esperado.</TITLE> </HEAD> <BODY> <% Exception ex = (Exception)request.getAttribute ("javax.servlet.error.exception"); StackTraceElement[] stack = ex.getStackTrace(); %> Se produjo un error no esperado. Disculpen las molestias...<BR/> Contacte con el administrador con la siguiente información:<BR/> <UL> <LI>Componente defectuoso: <%= request.getAttribute("javax.servlet.error.request_uri") %> 230
MÓDULO C – Unidad 9: Otros conceptos
</LI> <LI>Error producido: NullPointerException</LI> <LI>Más detalle:<BR/> <% for(int i=0; i<stack.length; i++) { %> <%= stack[i].toString() %><BR/> <% } %> </LI> </UL> <%= Calendar.getInstance().getTime() %> </BODY> </HTML> Este sería el resultado ahora:
Y así podríamos hacer con todos los tipos de excepciones más habituales no
controlados o que se pueden escapar mas fácilmente en el código, consiguiendo dar
una imagen más corporativa y cercana al usuario (evidentemente la página de nuestro
ejemplo no es ninguna de las dos cosas).
231
9.3
Gestión de la seguridad
La seguridad, es un tema que no podemos descuidar cuando hablamos de aplicaciones web.
Y las especificaciones Java EE tampoco la descuidan para nada. Imaginemos lo que podría
pasar con aplicaciones web típicas de hoy en día sin una buena gestión de la seguridad: home
banking, bróker online, tiendas virtuales, etc…
En general, desde un punto de vista teórico, una buena gestión de la seguridad debe cubrir los
siguientes puntos:

Autenticación: Asegurarse que un cliente es quien dice ser.
Por ejemplo, al acceder a una aplicación web se nos puede solicitar identificador y
contraseña para validar que somos quien decimos ser. Existen otras opciones además
del identificador y contraseña, como son los certificados digitales.

Autorización: Asegurarse que un cliente accede solo a los recursos a los que
puede/debe tener acceso y no a otros.
Por ejemplo, si no somos administradores de una aplicación web, al entrar en el
sistema no deberíamos poder acceder a opciones de configuración de la aplicación.

Integridad de datos: Asegurarse que los mensajes llegan sin haber sido alterados
por el camino.
Por ejemplo, evitar que alguien pueda estar “pinchado” a la red y modifique el
contenido de los mensajes que enviamos a un servidor.

Confidencialidad: Asegurarse que solo las personas autorizadas pueden ver y
acceder a información sensible.
Por ejemplo, evitar que alguien pueda estar “pinchado” a la red y lea información
sensible como contraseñas, números de cuenta y similares que fluye entre nuestro
navegador y el servidor.

No repudio: Asegurarse que quedan evidencias que eviten que un cliente pueda
negar haber realizado una transacción contra el servidor.
Por ejemplo, evitar que alguien pueda decir que no hizo algo en nuestro sistema.

Auditoria: Asegurarse que queda registrado todos los eventos relacionados con la
seguridad para posteriores estudios y análisis.
Por ejemplo, registrar todos los intentos de acceso fallidos al sistema.
No trataremos en profundidad todos los puntos pero si nos centraremos en algunos
imprescindibles como son la autenticación y autorización. Otros como la integridad de datos o
la confidencialidad los comentaremos brevemente ya que no dependen tanto de la aplicación
sino de una correcta configuración de la infraestructura.
Las especificaciones Java EE, nos ofrecen dos aproximaciones distintas al tema de la
seguridad:
232
MÓDULO C – Unidad 9: Otros conceptos

Programática: es decir, define una serie de APIs para que la gestión de la
seguridad se realice directamente desde el código. APIs como Java Authentication
and Authorization Service (JAAS) para realizar autenticación y autorización, Java
Cryptography Extension (JCE) para realizar cifrados, Java Security Socket
Extension (JSSE) para realizar comunicaciones seguras, etc…

Declarativa: es decir, la posibilidad de delegar en los contenedores Java EE
(Servidor de Aplicaciones Java EE) algunos de los temas relacionados con la
gestión de la seguridad, permitiendo a los desarrolladores centrarse en la lógica de
negocio de la aplicación y no en estos temas colaterales pero no menos
importantes.
La aproximación declarativa se realiza mediante el uso de los descriptores de
despliegue o las anotaciones Java (a partir de Java EE 6.0).
Ambas dos aproximaciones tienes pros y contras. La aproximación declarativa no cubre el
100% de las áreas ni es tan flexible como la programática, pero es mucho más sencilla, está
sujeta a menos errores y cubre las necesidades habituales de autenticación y autorización.
En este curso vamos a tratar solamente la aproximación declarativa, ya que no tiene sentido
dedicar más unidades a estudiar APIs tan específicas. No obstante, todas están
documentadas en la web:
http://docs.oracle.com/javase/7/docs/technotes/guides/security/
Antes de entrar en los detalles Java EE, vamos a revisar unos conceptos teóricos previos
imprescindibles como son: Realm, Usuario, Grupo y Rol.

Realm: Recibe el nombre en inglés de Realm, el conjunto de usuarios y grupos
identificados como válidos para una aplicación web junto con las políticas de
seguridad asociadas. Podríamos decir que se trata de toda la configuración de
seguridad de una aplicación web concreta.

Usuario: Es el identificador unívoco de una persona o entidad de software que puede
interactuar con la aplicación.

Grupo: Es el identificador de un conjunto de usuarios que tienen algo en común.

Rol: Es el identificador de un concepto abstracto que agrupa a varios usuarios
individuales o grupos. Se utiliza para realizar la autorización de acceso a los recursos.
¿Cómo encajan estos conceptos juntos y cómo se utilizan para securizar una aplicación web?
En el Servidor de Aplicaciones Java EE gestionado por los administradores de sistemas
existen definidos usuarios y grupos. Dependiendo del Servidor de Aplicaciones Java EE y de la
solución corporativa que haya instalada en cada caso, esto usuarios y grupos estarán
definidos directamente en el servidor o están delegados en el Sistema Operativo, o en un
Servidor de Directorio LDAP. Lo importante en nuestro caso es que ambos dos conceptos son
un tema ajeno a la aplicación web y está delegado en la infraestructura.
233
Los roles sin embargo, si que son algo que definimos en la aplicación. Es un concepto
abstracto de quién puede hacer qué. Es decir, en la aplicación diremos que a un recurso
concreto solo puede acceder el rol A y B. Y a otro recurso distinto solo el rol A o por el
contrario el rol C.
El “truco” llega en el momento de la instalación de la aplicación donde el administrador
encargado de dicho proceso mapeará el concepto abstracto de rol, con los conceptos reales
de usuario y/o grupo.
Y el conjunto de esas definiciones para una aplicación concreta, es lo que llamamos un Realm.
Pero vayamos por partes. Ha quedado claro que primero necesitamos contar con una serie de
usuarios y opcionalmente grupos en nuestro sistema.
En el caso de este curso, estamos usando el Servidor de Aplicaciones Java EE Apache
Tomcat 7.0.x que ofrece distintas alternativas de configuración. Optaremos por la más
sencilla, que consiste en el uso de un fichero de configuración de usuarios: /conf/tomcatusers.xml
La primera “dificultad” viene porque Apache Tomcat denomina rol lo que en la teoría de
seguridad hemos llamado grupo. No pasa nada, pero evidentemente crea confusión. Así que
es importante recordarlo a lo largo del resto de esta sección: lo que en la configuración de
Apache Tomcat se denomina rol, realmente corresponde al concepto que hemos comentado
de grupo. No tiene nada que ver con el concepto abstracto de rol que aplica a las aplicaciones
web y que veremos mas adelante.
Vamos a trabajar sobre un ejemplo donde tendremos seis usuarios: usuario1, usuario2,
usuario3, usuario4, usuario5 y usuarios6, y tres grupos: clientes (representa usuarios normales
de nuestra aplicación), operadores (representa usuarios especiales que pertenecen a nuestra
empresa y que tienen más permisos que los usuarios cliente) y administradores (representa
usuarios nuevamente de nuestra empresa que tienen todos los permisos).
Los dos primeros usuarios pertenecen al primer grupo, los dos siguientes al segundo grupo y
los dos últimos al tercero. Las contraseñas de cada usuario son su propio identificador, es
decir, usuario1 tendrá como contraseña usuario1, y así sucesivamente.
Vamos a editar el fichero de configuración en el entorno de desarrollo Eclipse IDE for Java EE
Developers (recordemos que los ficheros de configuración de Apache Tomcat en este caso
estarán en un proyecto denominado Servers):
234
MÓDULO C – Unidad 9: Otros conceptos
El contenido del fichero debería ser algo así para nuestro ejemplo:
<?xml version="1.0" encoding="UTF‐8"?> <tomcat‐users> <role rolename="clientes"/> <role rolename="operadores"/> <role rolename="administradores"/> <user username="usuario1" password="usuario1" roles="clientes"/> <user username="usuario2" password="usuario2" roles="clientes"/> <user username="usuario3" password="usuario3" roles="operadores"/> <user username="usuario4" password="usuario4" roles="operadores"/> <user username="usuario5" password="usuario5" roles="administradores"/> <user username="usuario6" password="usuario6" roles="administradores"/> </tomcat‐users> De esta manera, nuestro sistema ya cuenta con los usuarios y grupos definidos. Nota: Un
usuario puede pertenecer a más de un grupo. En ese caso, simplemente se añadiría un grupo
separado por coma a la definición del usuario.
A continuación, vamos a desarrollar nuestra aplicación de ejemplo antes de seguir avanzando
en la configuración de la seguridad. La aplicación va a ser muy sencilla, va a consistir en una
página HTML de entrada con tres botones: clientes, operadores y administradores. Esta
página es pública, es decir, será accesible por todo el mundo esté dado de alta en los
sistemas como usuario o no.
Cada uno de los tres botones, invocará a una JavaServer Page (JSP) distinta accesible por
cada uno de los tres grupos. Y aquí vendrá el grueso del ejemplo porque los clientes solo
podrán acceder a la página de clientes, los operadores podrán acceder tanto a la de clientes
235
como a la de operadores y los administradores a todas. Para ello, el navegador nos pedirá un
usuario y una contraseña, para saber quién somos y si nos puede autorizar o no. Pero la
configuración para que esto ocurra la veremos después de escribir el código.
Página HTML (publica.html):
<!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Ejemplo de Seguridad</TITLE> </HEAD> <BODY> Esta página es pública y accesible por todo el mundo. <FORM method="POST" action="/EjemplosWeb/clientes.jsp"> <INPUT type="submit" value="Clientes"> </FORM> <FORM method="POST" action="/EjemplosWeb/operadores.jsp"> <INPUT type="submit" value="Operadores"> </FORM> <FORM method="POST" action="/EjemplosWeb/administradores.jsp"> <INPUT type="submit" value="Adminitradores"> </FORM> </BODY> </HTML> Página JSP (clientes.jsp):
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Ejemplo de Seguridad</TITLE> </HEAD> <BODY> Página de Clientes accesible por usuarios: <UL> <LI>Usuario1</LI> <LI>Usuario2</LI> <LI>Usuario3</LI> <LI>Usuario4</LI> <LI>Usuario5</LI> <LI>Usuario6</LI> </UL> </BODY> </HTML> Página JSP (operadores.jsp):
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 236
MÓDULO C – Unidad 9: Otros conceptos
<HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Ejemplo de Seguridad</TITLE> </HEAD> <BODY> Página de Clientes accesible por usuarios: <UL> <LI>Usuario3</LI> <LI>Usuario4</LI> <LI>Usuario5</LI> <LI>Usuario6</LI> </UL> </BODY> </HTML> Página JSP (administradores.jsp):
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> <!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Ejemplo de Seguridad</TITLE> </HEAD> <BODY> Página de Clientes accesible por usuarios: <UL> <LI>Usuario5</LI> <LI>Usuario6</LI> </UL> </BODY> </HTML> La clave viene ahora con el descriptor de despliegue, donde definiremos los roles que existen
en nuestra aplicación, las restricciones de seguridad de los componentes de la aplicación, y el
modo de autenticación al acceder a la aplicación.
Los roles existentes en una aplicación web, se definen mediante los bloques “security-role” y
“role-name”. En nuestro ejemplo:
<security‐role> <role‐name>clientes</role‐name> </security‐role> <security‐role> <role‐name>operadores</role‐name> </security‐role> <security‐role> <role‐name>administradores</role‐name> </security‐role> Como ya comentamos en los conceptos teóricos, Grupo y Rol no tienen por qué ser lo mismo.
Los roles son un concepto abstracto independiente de los sistemas de usuarios/grupos que
237
haya definidos en una empresa De esta manera se consigue una independencia entre la
aplicación y los sistemas donde se vaya a desplegar.
Es a la hora de instalar la aplicación, donde se hace un mapeo de roles con usuarios/grupos.
Pero cómo se hace este mapeo es dependiente de cada Servidor de Aplicaciones Java EE.
Cada uno lo realiza en un fichero de configuración distinto y con una sintaxis distinta. Pero es
más, en el caso de Apache Tomcat 7.0.x dicho mapeo no existe y nos obliga a que los roles
correspondan con nombres de grupos idénticos lo cual es una restricción importante.
Las restricciones de acceso a los componentes de la aplicación web se definen mediante el
bloque “security-constraint”, el cual a su vez contiene múltiples bloques. Veamos un ejemplo:
<security‐constraint> <web‐resource‐collection> <web‐resource‐name>Area de Operadores</web‐resource‐name> <url‐pattern>/operadores.jsp</url‐pattern> <http‐method>GET</http‐method> <http‐method>POST</http‐method> </web‐resource‐collection> <auth‐constraint> <role‐name>administradores</role‐name> <role‐name>operadores</role‐name> </auth‐constraint> <user‐data‐constraint> <transport‐guarantee>NONE</transport‐guarantee> </user‐data‐constraint> </security‐constraint> Como se puede observar, primero se define el recurso o conjunto de recursos a proteger,
identificados por una URL que podría usar comodines tipo: /*, o /*.jsp, etc… especificando
además los protocolos HTTP de acceso a tener en consideración.
Después de especifican los roles que tienen autorización a acceder a los recursos definidos
anteriormente.
Y por último, especifica si las comunicaciones deben ser seguras o no (utilizando HTTPS). Este
bloque puede tomar tres valores:

NONE: no existe requerimiento de comunicaciones seguras para acceder a los
recursos definidos, es decir, HTTP.

CONFIDENTIAL: las comunicaciones deben no ser legibles, por tanto se debe usar
HTTPS para acceder a los recursos definidos.

INTEGRAL: las comunicaciones deben asegurar su integridad, es decir, que nadie
pueda haber cambiado el contenido por en medio entre el cliente y el servidor. A
efectos prácticos implica lo mismo que CONFIDENTIAL, se debe usar HTTPS para
acceder a los recursos definidos.
De esta manera, definiríamos todas las posibles autorizaciones de acceso a los componentes
de la aplicación web.
238
MÓDULO C – Unidad 9: Otros conceptos
El modo de autenticación se define mediante los bloques “login-config” y “auth-method”. Por
ejemplo, para que sea el navegador el que nos muestre una ventana de autenticación de
usuario y contraseña:
<login‐config> <auth‐method>BASIC</auth‐method> </login‐config> Existen múltiples métodos de autenticación. Brevemente son:

BASIC: el servidor pedirá al cliente que solicite el usuario y contraseña. Estas viajaran
codificadas en Base64 en claro (a no ser que las comunicaciones sean seguras).

FORM: la aplicación web implementa la página de solicitud de usuario y contraseña,
en vez de ser una ventana del navegador. La configuración en el descriptor de
despliegue requiere algún parámetro adicional que veremos más tarde.

CLIENT-CERT: requiere que el navegador envíe un certificado digital con la
información del usuario. Este es el mecanismo que se utiliza por ejemplo en
aplicaciones como la declaración de Hacienda en la AEAT.

DIGEST: la información del usuario y la contraseña van cifradas utilizando alguno de
los algoritmos soportados por ambos lados, cliente y servidor.
Con todo esto, veamos cómo sería el descriptor de despliegue de nuestro ejemplo:
<?xml version="1.0" encoding="UTF‐8"?> <web‐app xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web‐app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web‐app_3_0.xsd" id="WebApp_ID" version="3.0"> <security‐role> <role‐name>clientes</role‐name> </security‐role> <security‐role> <role‐name>operadores</role‐name> </security‐role> <security‐role> <role‐name>administradores</role‐name> </security‐role> <security‐constraint> <web‐resource‐collection> <web‐resource‐name>Area de Adminitradores</web‐resource‐name> <url‐pattern>/administradores.jsp</url‐pattern> <http‐method>GET</http‐method> <http‐method>POST</http‐method> </web‐resource‐collection> <auth‐constraint> <role‐name>administradores</role‐name> </auth‐constraint> <user‐data‐constraint> <transport‐guarantee>NONE</transport‐guarantee> </user‐data‐constraint> </security‐constraint> 239
<security‐constraint> <web‐resource‐collection> <web‐resource‐name>Area de Operadores</web‐resource‐name> <url‐pattern>/operadores.jsp</url‐pattern> <http‐method>GET</http‐method> <http‐method>POST</http‐method> </web‐resource‐collection> <auth‐constraint> <role‐name>administradores</role‐name> <role‐name>operadores</role‐name> </auth‐constraint> <user‐data‐constraint> <transport‐guarantee>NONE</transport‐guarantee> </user‐data‐constraint> </security‐constraint> <security‐constraint> <web‐resource‐collection> <web‐resource‐name>Area de Clientes</web‐resource‐name> <url‐pattern>/clientes.jsp</url‐pattern> <http‐method>GET</http‐method> <http‐method>POST</http‐method> </web‐resource‐collection> <auth‐constraint> <role‐name>administradores</role‐name> <role‐name>operadores</role‐name> <role‐name>clientes</role‐name> </auth‐constraint> <user‐data‐constraint> <transport‐guarantee>NONE</transport‐guarantee> </user‐data‐constraint> </security‐constraint> <login‐config> <auth‐method>BASIC</auth‐method> </login‐config> </web‐app> Como se puede ver, definimos tres roles, tres colecciones de recursos con sus definiciones de
acceso y el método de autenticación BASIC.
Si ejecutamos el ejemplo siguiendo la siguiente secuencia lógica:
1. Accedemos a la página HTML principal pública que no está protegida. Deberíamos
poder acceder y ver su contenido sin ningún tipo de problema.
240
MÓDULO C – Unidad 9: Otros conceptos
2. Solicitamos el acceso a la zona de Clientes ya protegida. Y el navegador debería
mostrarnos una ventanita de autenticación. Nos autenticamos con usuario3/usuario3,
es decir, con un miembro del grupo de operadores. Y deberíamos poder ver la zona de
clientes sin problemas.
3. Navegamos hacia atrás y solicitamos el acceso a la zona de Operadores. Deberíamos
poder acceder nuevamente sin problemas ya que el usuario3 pertenece al grupo de
operadores.
241
4. Por último, navegamos hacia atrás y solicitamos el acceso a la zona de
Administradores. En este caso deberíamos recibir un error HTTP 403 porque no
tenemos autorización para acceder a esa zona.
Se trata de un ejemplo muy sencillo pero bastante ilustrativo de la gestión de la seguridad en
Java EE de forma declarativa.
Antes de dar por finalizada esta sección, vamos a mostrar el uso del mecanismo de
autenticación FORM (el del ejemplo anterior ha sido BASIC). Como indicábamos, FORM
implica que la ventana de petición de usuario y contraseña es proporcionada por la aplicación
web y no es una ventanita del navegador.
El primer paso es modificar el descriptor de despliegue. En este caso debería ser algo así:
<login‐config> <auth‐method>FORM</auth‐method> <form‐login‐config> <form‐login‐page>/login.jsp</form‐login‐page> <form‐error‐page>/loginerroneo.jsp</form‐error‐page> </form‐login‐config> </login‐config> Como configuración adicional, especificamos los componentes web que muestran la pantalla
de autenticación, y la pantalla de error en caso de que la autenticación sea errónea.
El formulario de la pantalla de autenticación debe tener en cuenta tres cosas:

Debe invocar mediante HTTP POST un recurso denominado: j_security_check

El usuario lo debe enviar en una variable denominada: j_username

La contraseña debe enviarla en una variable denominada: j_password
Por lo demás, la página puede mostrar la información como quiera. Por ejemplo:
<%@ page language="java" contentType="text/html; charset=ISO‐8859‐1" pageEncoding="ISO‐8859‐1"%> 242
MÓDULO C – Unidad 9: Otros conceptos
<!DOCTYPE html PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML> <HEAD> <META http‐equiv="Content‐Type" content="text/html; charset=ISO‐ 8859‐1"> <TITLE>Ejemplo de Seguridad</TITLE> </HEAD> <BODY> <FORM method="POST" action="j_security_check"> <TABLE> <TR> <TD colspan="2">Página de ejemplo para login:</TD> </TR> <TR> <TD>Usuario:</td> <TD><INPUT type="text" name="j_username"></TD> </TR> <TR> <TD>Contraseña:</td> <TD><INPUT type="password" name="j_password"></TD> </TR> <TR> <TD colspan="2"><INPUT type="submit" value="Login"></TD> </TR> </TABLE> </FORM> </BODY> </HTML> En esta ocasión, cuando el servidor detecte que ha de pedir autenticación al cliente, en vez de
solicitar al navegador que muestre una ventana devolverá nuestra página:
Hemos mencionado en varias ocasiones las comunicaciones seguras basadas en el protocolo
HTTPS (HTTP con SSL). Dado que se trata de un tema puramente de configuración y
administración de los servidores, y que cada servidor lo hace de una manera distinta no vamos
a detenernos en los detalles en este curso.
243
No obstante, la información de cómo se configuran las comunicaciones HTTPS en Apache
Tomcat 7.0.x se encuentra en la siguiente URL:
http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html
9.4
Frameworks de desarrollo web
Uno de los objetivos habituales en el mundo de la informática es el de mejorar constantemente
la productividad de los desarrolladores. Una manera es mejorando día a día las herramientas
de desarrollo disponibles. Y otra, facilitando el desarrollo a través de frameworks que
escondan las complejidades y eviten los trabajos repetitivos a los desarrolladores.
Esta última es la que comentaremos brevemente a continuación. Un framework no es más que
una librería de código junto con una metodología o forma de trabajar. Su objetivo, no es
reinventar la rueda sino basándose en las tecnologías ya existentes intentar facilitar la vida al
desarrollador.
Durante este curso hemos estudiado las tecnologías, especificaciones y APIs en las que se
basa el desarrollo web Java EE. Los frameworks que comentaremos brevemente a
continuación no son algo totalmente distinto, sino que basándose en lo que ya hemos
aprendido intentan mejorar la experiencia del desarrollador facilitando el mantenimiento del
código, mejorando los interfaces visuales, evitando trabajos repetitivos, etc… pero siempre
por debajo, lleva todo lo aprendido en este curso.
Frameworks hay muchos, simplemente comentaremos cuatro de los más extendidos en el
mercado laboral actualmente.
9.4.1 JavaServer Faces
JavaServer Faces es una especificación más de Java EE. Nació
como un framework separado y con el tiempo se adhesionó a las
especificaciones. Siguiendo el estándar Java EE, esta debería ser
la vía de evolución de los programadores web.
¿Y por qué no hemos estudiado esta opción entonces en este
curso?
Dos motivos:
1. Se basa en las especificaciones Java Servlet y JavaServer Page. Sin ese conocimiento
adquirido en este curso, no podríamos entender JavaServer Faces. Sería como
comenzar la casa por el tejado.
2. Adicionalmente, en el mercado siguen existiendo millones de aplicaciones basadas en
Java Servlets y JavaServer Pages. La necesidad de estos conocimientos sigue
estando ahí, es algo que no podemos obviar.
244
MÓDULO C – Unidad 9: Otros conceptos
La idea que persigue JavaServer Faces es definir una serie de conceptos por encima de las
APIs básicas como son: componentes visuales (controles con lógica avanzada reutilizables a
utilizar en las páginas), beans de gestión (mecanismo que facilita la transmisión de
información por el flujo de la aplicación), validadores (un sistema de control de errores en los
valores de los campos), proveer de un controlador que ya implementa el control del flujo de
la aplicación mediante un fichero de configuración, etc…
Para profundizar en este framework:
http://docs.oracle.com/javaee/6/tutorial/doc/bnaph.html
9.4.2 Apache Struts
Fue el primer framework de este estilo que
surgió en la Fundación Apache.
Era muy sencillo de utilizar, y básicamente añadía la posibilidad de definir el flujo de la
aplicación en un fichero de propiedades que un controlador del propio framework se
encargaba de interpretar. Todas las peticiones pasaban por este controlador y él se
encargaba de direccionar a la página que el fichero dijera dependiendo de los valores de
distintos parámetros y/o condiciones.
También añadía validadores para facilitar el control de errores de los formularios.
Con la aparición de JavaServer Faces y otros frameworks como Spring se fue quedando
algo obsoleto y cada vez se usa menos.
Para profundizar en este framework:
http://struts.apache.org/
9.4.3 Spring Source
Junto con JavaServer Faces, es uno de los frameworks
mas extendidos.
Nació como una ayuda mas a la programación web
pero con el tiempo se fue extendiendo a otras muchas
áreas
como
la
programación
transaccional,
la
persistencia de datos, la programación de batch, para móviles, etc…
Para profundizar en este framework:
http://www.springsource.org/documentation
245
9.4.4 Apache Wicket
Este
es
un
nuevo
framework
junto
con
Struts
también
perteneciente a la Fundación Apache.
Su objetivo es conseguir separar lo máximo posible la presentación
de la lógica, y definir un modelo de lógica de negocio basado en
POJOs muy sencillo.
No está muy extendido su uso.
Para profundizar en este framework:
http://wicket.apache.org/
246
PARA RECORDAR
 Existen dos alternativas, según las especificaciones Java EE para la gestión de
errores:

Programática: Toda la gestión se lleva dentro de la aplicación mediante código
fuente (por ejemplo mediante bloques try/catch).

Declarativa: La gestión se externaliza en configuraciones en el descriptor de
despliegue. Permite controlar:
o Errores HTTP
o Excepciones Java
 Una buena gestión de la seguridad debe cubrir los siguientes puntos:

Autenticación: Asegurarse que un cliente es quien dice ser.

Autorización: Asegurarse que un cliente accede solo a los recursos a los que
puede/debe tener acceso y no a otros.

Integridad de datos: Asegurarse que los mensajes llegan sin haber sido
alterados por el camino.

Confidencialidad: Asegurarse que solo las personas autorizadas pueden ver y
acceder a información sensible.

No repudio: Asegurarse que quedan evidencias que eviten que un cliente pueda
negar haber realizado una transacción contra el servidor.

Auditoria: Asegurarse que queda registrado todos los eventos relacionados con
la seguridad para posteriores estudios y análisis.
 Las especificaciones Java EE, nos ofrecen dos aproximaciones distintas al tema de
la seguridad:

Programática: Define una serie de APIs para que la gestión de la seguridad se
realice directamente desde el código.

Declarativa: Delega en los contenedores Java EE (Servidor de Aplicaciones
Java EE) algunos de los temas relacionados con la gestión de la seguridad.
247
 Los métodos de autenticación´ comúnmente más usados son:

BASIC: el servidor pedirá al cliente que solicite el usuario y contraseña

FORM: la aplicación web implementa la página de solicitud de usuario y
contraseña, en vez de ser una ventana del navegador.

CLIENT-CERT: requiere que el navegador envíe un certificado digital con la
información del usuario.

DIGEST: la información del usuario y la contraseña van cifradas utilizando
alguno de los algoritmos soportados por ambos lados, cliente y servidor.
 Los Frameworks más extendidos para el desarrollo de aplicaciones web son:

JavaServer Faces es una especificación más de Java EE basada en Java
Servlets y en JavaServer Pages (JSP).

Apache Struts fue el primer framework de este estilo que surgió en la
Fundación Apache.

Spring Source nació como una ayuda mas a la programación web pero con el
tiempo se fue extendiendo a otras muchas áreas como la programación
transaccional, la persistencia de datos, la programación de batch, para móviles,
etc…

Apache Wicket. Su objetivo es conseguir separar lo máximo posible la
presentación de la lógica, y definir un modelo de lógica de negocio basado en
POJOs muy sencillo.
248