Programación Web en Java MENTOR PDF
Programación Web en Java MENTOR PDF
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.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.
Es por ello que existen distintas plataformas Java, dependiendo del ámbito en el que se vaya a
trabajar.
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
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”.
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: cliente-
servidor, 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
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.
Capa web (Web Tier): responsable del control de la aplicación y en ocasiones también
de la interacción con el usuario.
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.
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.
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:
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.
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.
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.
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 Modelo (Model): Representa los datos y cualquier lógica de negocio relacionada con
ellos.
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:
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).
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.
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.
JavaMail 1.4
Java Authentication Service Provider Interface for Java Authorization Contract for
Containers 1.3
11
J2EE Management 1.1
Dado que la plataforma Java EE extiende la Java SE, existen especificaciones Java SE
incluidas en Java EE:
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
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).
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.
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.
<?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.
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.
Gratuitos o de pago.
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:
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/
URL: http://www-01.ibm.com/software/webservers/appserv/was/
URL: http://geronimo.apache.org
16
MÓDULO A – Unidad 1: Introducción a Java EE
URL: http://www.oracle.com/us/products/middleware/application-server/
URL: http://glassfish.java.net/
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:
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.
19
20
Unidad de Aprendizaje 2
EL ENTORNO DE DESARROLLO
ÍNDICE
2.1 Introducción ................................................................... 23
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:
URL: http://www.oracle.com/technetwork/java/javaee/downloads/index.html
URL: http://www.eclipse.org/
23
URL: http://www.ibm.com/software/awdtools/developer/application/
URL: http://netbeans.org/
URL: http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html
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.
24
MÓDULO A – Unidad 2: El Entorno de Desarrollo
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:
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:
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:
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
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-SR1-
win32-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:
32
MÓDULO A – Unidad 2: El Entorno de Desarrollo
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.
D:\apache-tomcat-7.0.22
34
MÓDULO A – Unidad 2: El Entorno de Desarrollo
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ú:
36
MÓDULO A – Unidad 2: El Entorno de Desarrollo
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:
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
40
Unidad de Aprendizaje 3
PROTOCOLO HTTP Y
LENGUAJE HTML
ÍNDICE
3.1 Introducción ................................................................... 43
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).
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.
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.
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
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).
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.
Protocolo://Servidor:Puerto/Path/Recurso
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
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.
http://74.125.39.103
o si escribiéramos:
http://ww.google.es
Método HTTP: se trata de la acción a realizar. Algunos ejemplos como veremos mas
adelante son GET y POST.
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…
Los métodos HTTP que se pueden utilizar como parte de una petición HTTP son los
siguientes:
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:
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:
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.
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
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:
param1=45¶m2=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
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:
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
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.
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.
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
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):
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/
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
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.
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.
El formato es el siguiente:
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.
<FONT size="3" color="red">
Hola mundo
</FONT>
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.
<!DOCTYPE HTML PUBLIC "‐//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Mi primer HTML</TITLE>
</HEAD>
<BODY>
Mi primer ejercicio
</BODY>
</HTML>
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.
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.
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.
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.
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.
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’.
Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
Disabled: no tiene un valor, sino que su sola presencia significa que el campo está
deshabilitado.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”>
Introduzca su nombre:
<INPUT type=”text” name=”nombre” maxlength=”20”>
</FORM>
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>
3.3.3.2 Áreas de texto
Un área de texto se define mediante la etiqueta TEXTAREA.
Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
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>
3.3.3.3 Checkboxes
Una checkbox se define mediante la etiqueta INPUT y su atributo ‘type’ con el valor
‘checkbox’.
Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
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.
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>
3.3.3.4 Radiobuttons
Un radiobutton se define mediante la etiqueta INPUT y su atributo ‘type’ con el valor ‘radio’.
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.
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.
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>
61
3.3.3.5 Listas y Combos
Tanto las listas como los combos se definen mediante la etiqueta SELECT.
Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
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.
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
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.
Name: el nombre del botón, que puede ser útil cuando se programa con JavaScript en
la página HTML.
Disabled: no tiene un valor, sino que su sola presencia significa que el botón está
deshabilitado.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”>
<INPUT type="submit" value="Enviar">
<INPUT type="reset" value="Borrar">
</FORM>
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’.
Name: el nombre del campo y por tanto, nombre del parámetro que viajará al servidor.
Ejemplo:
<FORM method=”POST” action=“/EjemploWeb/EjemploServlet”>
<INPUT type=”hidden” name=”usuario” value=”1234”>
</FORM>
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…
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).
65
66
PARA RECORDAR
Protocolo://Servidor:Puerto/Path/Recurso
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 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>.
JAVA SERVLETS
ÍNDICE
4.1 Introducción ................................................................... 71
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.
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.
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 /WebContent es donde iremos colocando los recursos web, como por
ejemplo, las páginas HTML, las JavaServer Pages (JSP), imágenes, etc…
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”.
76
MÓDULO B – Unidad 4: Java Servlets
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>");
}
}
<?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
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
83
4.3 Java Servlets
Todas las clases Java relacionadas con los Java Servlets, están en los paquetes:
javax.servet
javax.servlet.http
Los 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
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
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.
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:
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.
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:
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()");
}
}
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().
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>
http://localhost:8080/EjemplosWeb/RequestServlet?param1=valor1¶m2=valor2
En la consola del Servidor de Aplicaciones Java EE deberíamos ver algo como esto (en cada
caso dependerá un poco del entorno utilizado):
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
90
MÓDULO B – Unidad 4: Java Servlets
http://www.iana.org/assignments/media-types/index.html
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>
http://localhost:8080/EjemplosWeb/ResponseServlet
92
MÓDULO B – Unidad 4: Java Servlets
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.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.
<!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>
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.
94
MÓDULO B – Unidad 4: Java Servlets
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¶m2=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
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.
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.
98
MÓDULO B – Unidad 4: Java Servlets
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”.
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>
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.
100
MÓDULO B – Unidad 4: Java Servlets
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
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
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
{
....
}
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).
102
RECORDAR
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.
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.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.
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.
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 /WebContent es donde iremos colocando los recursos web, como por
ejemplo, las páginas HTML, las JavaServer Pages, imágenes, etc…
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
<%@ 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>
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
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.
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
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.
Los comentarios en una JavaServer Page se añaden delimitados por las siguientes dos
etiquetas de inicio y fin:
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>
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.
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 import: fundamental para poder importar las clases Java utilizadas en los
trozos de código java embebido y poder compilar correctamente.
Veamos un ejemplo:
<%@ page contentType="text/html; charset=ISO‐8859‐1"
pageEncoding="ISO‐8859‐1" %>
<%@ page import="java.util.Date, es.aulamentor.*" %>
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.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
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.
<%! … %>
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.
Los scriptles son las porciones de código Java embebidos en la JavaServer Page.
<% … %>
Por ejemplo:
<% String var = “Hola Mundo!”; %>
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.
Este tipo lo que permite es devolver un valor de una variable o un método e insertarlo como
parte de la respuesta.
<%= … %>
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.
122
MÓDULO B – Unidad 5: JavaServer Pages
<%@ 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>
Directivas para definir algunos aspectos técnicos de la JavaServer Page, así como
añadir imports necesarios para la correcta compilación.
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.
/*
* 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.
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.
127
public void _jspInit();
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.
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.
session: representa la sesión HTTP del usuario. 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.
128
MÓDULO B – Unidad 5: JavaServer Pages
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.
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
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”.
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
http://localhost:8080/EjemplosWeb/CalculadoraJSP
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
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.
Directiva:
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.
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:
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.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.
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.
139
Pues bien, los dos tipos de componentes Java EE que hemos estudiado ya, encajan
perfectamente en este diseño:
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.
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).
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?
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).
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.
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?
142
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
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.
<%@ 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>
<%@ 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>
package es.aulamentor;
public class RestadorBean
{
public int restar(int param1, int param2)
{
return param1 + param2;
}
}
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);
}
}
}
<%@ 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>
<%@ 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>
Página de inicio:
Página de resultado:
146
MÓDULO B – Unidad 6: Diseño de Aplicaciones Java EE
Página de error:
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
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.
http://www.oracle.com/technetwork/java/dao-138818.html
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…
http://www.oracle.com/technetwork/java/interceptingfilter-136585.html
http://www.oracle.com/technetwork/java/servicelocator-138528.html
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:
La conexión entre un Java Servlet y un POJO se realiza mediante las llamadas a los
métodos de dicho componente.
Para pasarle los datos necesarios del Java Servlet y un JavaServer Page (JSP) se
pueden utilizar los siguiente mecanismos:
HttpSession.
ServletContext.
Transfer Object: permite encapsular la información que viaja entre las distintas
capas de la aplicación
151
152
Unidad de Aprendizaje 7
ÍNDICE
7.1 Introducción ................................................................. 155
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.
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.
java.util.Enumeration<java.lang.String> getInitParameterNames()
Devuelve una colección con los nombres de todos los parámetros de configuración
que tiene.
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.
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>
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
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-bio-
8080-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.
159
Evitar en la medida de lo posible utilizar variables de instancia cuando su valor es de
escritura/lectura.
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.
Este método supone ejecutar todos los pasos típicos del API JDBC en el código de nuestra
aplicación:
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.
<!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>
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();
}
}
}
}
<%@ 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.
164
MÓDULO C – Unidad 7: Java Servlets Avanzado
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.
javax.sql.DataSource
Dicho interface tiene solo dos métodos que permiten el acceso a una conexión:
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.
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.
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.
<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" />
name: identificador JNDI (Java Naming and Directory Interface) que utilizaremos para
acceder al pool.
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…
<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>
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
Creación del Contexto de búsqueda: dirección IP, puerto del servicio, y punto de
entrada en el directorio.
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.
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>
<!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();
}
}
}
}
<%@ 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.
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();
}
}
public class DataSourceServlet extends HttpServlet
{
@Resource(name="java:comp/env/jdbc/TestDB")
DataSource datasource;
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.
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.
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 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.
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.
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()
{
}
}
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.
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.
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”:
182
MÓDULO C – Unidad 7: Java Servlets Avanzado
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:
Ruta (o Path): Dentro de ese Servidor, a qué rango de URLs les mandará el
navegador la Cookie (un / significa que a todas).
javax.servlet.http.Cookie;
Cookie[] getCookies();
Para crear una Cookie nueva utilizaremos su constructor, pasándole la información que ya
hemos comentado:
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>
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:
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…
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.
javax.servlet.http.HttpSession;
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.
java.util.Enumeration<java.lang.String> getAttributeNames();
189
Devuelve una colección con el nombre de todos los atributos que contiene.
Elimina un atributo.
void invalidate();
<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>
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.
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.
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.
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.
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.
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
MÓDULO C – Unidad 7: Java Servlets Avanzado
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 Sesión HTTP: por ejemplo, cuándo se invalida una sesió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:
contextDestroyed
javax.servlet.ServletContextListener
contextInitialized
attributeAdded
javax.servlet.ServletContextAttribute attributeRemoved
attributeReplaced
sessionDidActivate
javax.servlet.http.HttpSessionActivationListener
sessionWillPassivate
valueBound
javax.servlet.http.HttpSessionBindingListener
valueUnbound
195
attributeAdded
javax.servlet.http.HttpSessionAttributeListener attributeRemoved
attributeReplaced
requestDestroyed
javax.servlet.ServletRequestListener
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:
<listener>
<listener‐class>
es.aulamentor.EjemploListener
</listener‐class>
</listener>
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
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...");
}
}
198
MÓDULO C – Unidad 7: Java Servlets Avanzado
199
200
PARA RECORDAR
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…
init: Se invoca una única vez en la vida del filtro y se utiliza para realizar las
labores de inicialización.
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:
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:
202
Unidad de Aprendizaje 8
JAVASERVER PAGES
AVANZADO
ÍNDICE
8.1 Introducción ................................................................. 205
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.
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).
<jsp:include>: incluye el resultado de otra página JSP, Java Servlet u otro componente
web estático.
<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>.
Son muchas las etiquetas pero trataremos solo algunas de ellas porque en general, a
excepción de unas pocas, su uso es muy raro.
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>
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.
o request: la petición.
o page: la página:
206
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
o application: la aplicación.
Por ejemplo:
<jsp:useBean id="cesta" scope="session" class="edu.aulamentor.Cesta"/>
<jsp:setProperty> nos permite establecer el valor de alguno de los atributos del objeto. Para
ello utiliza tres atributos:
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:
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() %>
<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.
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() %>
Se llama: ${persona.perro.nombre}
Sencillo, ¿verdad?
208
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
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.
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:
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}
${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 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.
${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() %>
<%
}
}
%>
${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
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.
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.
http://docs.oracle.com/javaee/5/jstl/1.1/docs/tlddocs/
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” %>
URI: identificador del espacio de nombres (viene a significar algo parecido a los
paquetes Java para evitar colisiones de dos etiquetas de mismo nombre).
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
<c:set var="titulo" scope="session" value="${param.titulo}"/>
<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>
<c:forEach var="libro" items="${sessionScope.cesta.libros}">
<TR>
<TD align="right" bgcolor="#ffffff">
${libro.titulo}
</TD>
</TR>
</c:forEach>
<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" />
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
8.4.3 I18N
8.4.4 Database
<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):
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 transaction: sirve para aglutinar varias queries y/o updates en una unidad
transaccional.
8.4.5 Functions
<c:if test="${fn:length(parametro.nombre) > 0}" >
Longitud del nombre mayor de cero. Correcto!
</c:if>
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.
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.
218
MÓDULO C – Unidad 8: JavaServer Pages Avanzado
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:
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”.
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;
}
}
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>
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.
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" %>
<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/package-
summary.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:”.
224
Unidad de Aprendizaje 9
ÍNDICE
9.1 Introducción ................................................................. 227
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.
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.
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>
<%@ 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
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).
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”.
<?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>
<%@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>
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:
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.
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.
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.
Las especificaciones Java EE, nos ofrecen dos aproximaciones distintas al tema de la
seguridad:
232
MÓDULO C – Unidad 9: Otros conceptos
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.
¿Cómo encajan estos conceptos juntos y cómo se utilizan para securizar una aplicación web?
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.
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.
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.
<!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>
<%@ 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>
<%@ 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>
<%@ 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.
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.
<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>
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:
CONFIDENTIAL: las comunicaciones deben no ser legibles, por tanto 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
<login‐config>
<auth‐method>BASIC</auth‐method>
</login‐config>
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).
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.
240
MÓDULO C – Unidad 9: Otros conceptos
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.
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.
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:
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
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.
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.
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…
http://docs.oracle.com/javaee/6/tutorial/doc/bnaph.html
Con la aparición de JavaServer Faces y otros frameworks como Spring se fue quedando
algo obsoleto y cada vez se usa menos.
http://struts.apache.org/
http://www.springsource.org/documentation
245
9.4.4 Apache Wicket
http://wicket.apache.org/
246
PARA RECORDAR
o Errores HTTP
o Excepciones Java
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.
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:
247
Los métodos de autenticación´ comúnmente más usados son:
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…
248