12. Aplicación web MVC [personne] – versión 7
12.1. Introducción
En esta versión, partimos de la base de que puede haber navegadores de los usuarios que hayan desactivado:
- el reenvío de las cookies que envía el servidor
- la ejecución del código JavaScript incrustado en las páginas HTML mostradas
No obstante, queremos que este tipo de navegadores puedan utilizar nuestra aplicación. El punto 2 nos remite a la versión 2 de nuestra aplicación, ya que el JavaScript se empezó a utilizar a partir de la versión 3. La versión 2 hacía funcionar la aplicación sin JavaScript, por lo que el punto 2 queda resuelto.
El punto 1 puede resultar complicado o no de gestionar. La versión 6 de nuestra aplicación funcionaba sin cookies. Al fusionar las versiones 2 y 6, obtenemos el resultado deseado. Vamos a añadir una restricción adicional: la aplicación debe gestionar una sesión. No es una restricción sin sentido. En una aplicación en la que los usuarios deben autenticarse, el servidor debe memorizar el par (identificador/contraseña) del usuario para evitar que tenga que autenticarse en cada página que solicite.
Hasta ahora hemos utilizado tres soluciones para almacenar información a lo largo de las interacciones entre el cliente y el servidor:
- la sesión
- las cookies
- los campos ocultos.
La solución 2 puede descartarse, ya que el navegador del cliente puede haber desactivado el uso de cookies.
La solución 3 es la de la versión 6 que hemos estudiado anteriormente. No se puede utilizar por motivos de seguridad. Si el par (nombre de usuario/contraseña) se incluye en cada página enviada al navegador, esto significa que transita por la red en cada intercambio entre el cliente y el servidor. Esto no es bueno para la seguridad de la aplicación. Por lo tanto, se puede considerar el uso del protocolo HTTPS, que cifra los intercambios entre el cliente y el servidor. Sin embargo, utilizarlo para cada página de la aplicación aumentará la carga del servidor.
Podríamos querer descartar la solución 1 porque también se basa en cookies. Durante el primer intercambio entre el cliente y el servidor, el servidor envía al cliente un token de sesión que este devolverá al servidor en cada nueva solicitud. Gracias a este token, el servidor podrá reconocer a su cliente y asignarle la información que había almacenado durante un intercambio anterior. El servidor envía el token de sesión en una cookie. El navegador que no haya desactivado las cookies puede reenviarle esta cookie en sus siguientes solicitudes. Si las ha desactivado, dispone de otra solución: puede incluir el token de sesión en la URL que solicita. Esto es lo que vemos ahora al retomar el análisis del archivo [index.jsp] de la versión 4:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<c:redirect url="/main"/>
Recordemos que la línea 5 anterior redirige al cliente a la URL [/personne4/main?jsessionid=XX], donde XX es el token de sesión, tal y como muestra la captura de pantalla siguiente, obtenida tras solicitar la URL [http://localhost:8080/personne4]:

Analicemos más detenidamente el funcionamiento de la etiqueta <c:redirect> en lo que respecta al token de sesión. Tomemos como ejemplo un navegador en el que se aceptan las cookies. A continuación, configuramos el navegador Firefox:

En [1], habilitamos las cookies y en [2] eliminamos las que ya existen para partir de una situación conocida. A continuación, solicitamos la URL [http://localhost:8080/personne4]. Obtenemos la siguiente respuesta:

La solicitud inicial del cliente, HTTP, fue la siguiente:
Cabe señalar simplemente que el cliente no envía ninguna cookie de sesión. La respuesta HTTP enviada por el servidor es la siguiente:
- línea 1: el servidor solicita al cliente que se redirija
- línea 3: el servidor envía un token de sesión asociado al atributo [JSESSIONID]
- línea 4: la URL de redirección contiene el token de sesión. La etiqueta <c:redirect> lo ha colocado allí porque el cliente no había enviado ninguna cookie de sesión.
El navegador, al que se le pidió que se redirigiera, realizó a continuación la siguiente solicitud:
- línea 1: solicita la URL de redirección, con el token de sesión incluido. Por eso, en la captura de pantalla, el navegador muestra esta URL.
- línea 10: el navegador devuelve el token de sesión que le envió el servidor en el intercambio anterior. Este es el funcionamiento normal de las cookies cuando están permitidas en el navegador del cliente. Si no es así, las cookies recibidas no se devuelven.
El servidor respondió lo siguiente a esta segunda solicitud:
Ha encontrado la página que se le solicitaba y la envía. Cabe destacar que ya no envía el token de sesión. Este es el funcionamiento normal del token de sesión: el servidor lo envía al navegador una única vez en forma de cookie y, a continuación, el navegador lo reenvía en cada solicitud para que se le reconozca.
Ahora, con el mismo navegador, volvamos a solicitar la URL [http://localhost:8080/personne4] escribiéndola manualmente. Obtendremos entonces la siguiente página:

Observamos que la URL que muestra el navegador ya no contiene el token de sesión. Veamos el primer intercambio entre el cliente y el servidor:
El navegador ha realizado la siguiente solicitud:
Es exactamente la misma solicitud que la anterior, con una diferencia: en la línea 10, el navegador devuelve el token de sesión que había recibido en el primer intercambio. Una vez más, este es el funcionamiento normal si las cookies del navegador están activas.
El servidor envió la siguiente respuesta:
Solicita al cliente que se redirija. Como ha recibido un token de sesión del cliente, continúa con dicha sesión y no envía un nuevo token de sesión. Por la misma razón, la etiqueta <c:redirect> no incluye este token de sesión en la URL de redirección. Por eso, la URL que se muestra en la captura de pantalla anterior no contiene ningún token de sesión.
De todo esto se desprende la siguiente regla: la etiqueta <c:redirect> solo incluye el token de sesión en la URL de redirección si el cliente no ha enviado el encabezado HTTP:
Esta regla también se aplica a la etiqueta <c:url>, con la que nos encontraremos más adelante.
¿Qué ocurre con un navegador en el que se han desactivado las cookies? Probémoslo. En primer lugar, reiniciamos el navegador:

En [1], desactivamos las cookies y en [2] eliminamos las que ya existen para partir de una situación conocida. A continuación, solicitamos la URL [http://localhost:8080/personne4]. Obtenemos la siguiente respuesta:

Obtenemos el mismo resultado que antes. Sin embargo, los intercambios HTTP no son exactamente los mismos:
- líneas 1-9: la solicitud n.º 1 del navegador. No envía ninguna cookie de sesión.
- líneas 11-17: la respuesta del servidor que le pide que se redirija a otra URL. Envía una cookie de sesión en la línea 13: la etiqueta <c:redirect> ha incluido el token en la URL de redirección de la línea 14.
- líneas 19-27: la solicitud n.º 2 del navegador. No devuelve la cookie de sesión que el servidor le acaba de enviar porque tiene desactivadas las cookies.
- líneas 29-33: la respuesta del servidor. Se puede observar que, aunque el navegador no le haya enviado ninguna cookie de sesión, el servidor no inicia una nueva sesión, como cabría esperar. Esto se aprecia en el hecho de que no envía el encabezado HTTP [Set-Cookie] como lo había hecho en la línea 13. Esto significa que continúa con la sesión anterior. Ha podido recuperarla gracias al token de sesión presente en la URL solicitada por el navegador en la línea 19.
Cabe destacar que el servidor realiza el seguimiento de una sesión recuperando el token de sesión enviado por el cliente, de dos formas posibles:
- en el encabezado HTTP [Set-Cookie] enviado por el cliente
- en la URL solicitada por el cliente
Ahora, con el mismo navegador, volvamos a solicitar la URL [http://localhost:8080/personne4] escribiéndola manualmente, tal y como se hacía cuando las cookies estaban permitidas. Entonces obtendremos la siguiente página:

El resultado es diferente al obtenido cuando las cookies estaban permitidas: el token de sesión aparece en la URL que muestra el navegador. Analicemos este resultado sin entrar en detalle en los intercambios HTTP que han tenido lugar:
[cookies autorisés]
- En la segunda solicitud de la URL [http://localhost:8080/personne4], el navegador del cliente había devuelto la cookie de sesión que había recibido del servidor durante la primera solicitud de esa misma URL. Por lo tanto, la etiqueta <c:redirect> no había incluido el token de sesión en la dirección de redirección.
[cookies inhibés]
- En la segunda solicitud de la URL [http://localhost:8080/personne4], el navegador del cliente no envía la cookie de sesión que recibió del servidor durante la primera solicitud de esa misma URL, ya que sus cookies están desactivadas. Por lo tanto, la etiqueta <c:redirect> incluye el token de sesión en la dirección de redirección. Por eso aparece en la captura de pantalla anterior.
Las etiquetas <c:redirect> y <c:url> permiten incluir el token de sesión en las URL. Esta es la solución que se propone aquí.
12.2. El proyecto Eclipse
Para crear el proyecto Eclipse [mvc-personne-07] de la aplicación web [/personne7], se duplicará el proyecto [mvc-personne-06] siguiendo el procedimiento descrito en el apartado 6.2.
![]() | ![]() |
12.3. Configuración de la aplicación web [personne7]
El archivo web.xml de la aplicación /personne7 es el siguiente:
<?xml version="1.0" encoding="UTF-8"?>
...
<display-name>mvc-personne-07</display-name>
...
Este archivo es idéntico al de la versión anterior, salvo en la línea 3, donde el nombre de visualización de la aplicación web ha cambiado a [mvc-personne-07]. La página de inicio [index.jsp] no cambia.
...
<c:redirect url="/do/formulaire"/>
12.4. El código de las vistas
Las vistas [formulaire, réponse, erreurs] vuelven a ser lo que eran en la versión 2, c.a.d, sin JavaScript. Sin embargo, conservan las etiquetas JSTL de las últimas versiones.
12.4.1. La vista [formulaire]

Se han eliminado los botones asociados al código JavaScript.
[formulaire.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne - formulaire</title>
</head>
<body>
<center>
<h2>Personne - formulaire</h2>
<hr>
<form name="frmPersonne" action="<c:url value="validationFormulaire"/>" method="post">
<table>
<tr>
<td>Nom</td>
<td><input name="txtNom" value="${nom}" type="text" size="20"></td>
</tr>
<tr>
<td>Age</td>
<td><input name="txtAge" value="${age}" type="text" size="3"></td>
</tr>
<tr>
</table>
<table>
<tr>
<td><input type="submit" name="bouton" value="Envoyer"></td>
<td><input type="reset" value="Rétablir"></td>
<td><input type="submit" name="bouton" value="Effacer"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
- línea 14: la URL de destino de POST se escribe con la etiqueta <c:url> para que el token de sesión se incluya en ella en caso de que el cliente sea un navegador que no envíe el encabezado HTTP [Cookie].
- El formulario tiene dos botones de tipo [submit]: [Envoyer] (línea 28) y [Effacer] (línea 30). Ambos botones tienen el mismo nombre: bouton. Al pulsar el botón POST, el navegador enviará el parámetro:
- botón=Enviar si la solicitud POST ha sido provocada por el botón [Enviar]
- botón=Borrar si la solicitud POST ha sido provocada por el botón [Borrar]
Este parámetro nos ayudará a definir la acción exacta que hay que realizar, ya que la URL [/do/validationFormulaire] corresponde ahora a dos acciones distintas.
12.4.2. La vista [réponse]

[réponse.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Personne - réponse</h2>
<hr>
<table>
<tr>
<td>Nom</td>
<td>${nom}</td>
</tr>
<tr>
<td>Age</td>
<td>${age}</td>
</tr>
</table>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- línea 24: la URL de destino de HREF se escribe con la etiqueta <c:url> para que el token de sesión se incluya en ella en caso de que el cliente sea un navegador que no envíe el encabezado HTTP [Cookie].
12.4.3. La vista [erreurs]

[erreurs.jsp]:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>
<html>
<head>
<title>Personne</title>
</head>
<body>
<h2>Les erreurs suivantes se sont produites</h2>
<ul>
<c:forEach var="erreur" items="${erreurs}">
<li>${erreur}</li>
</c:forEach>
</ul>
<br>
<a href="<c:url value="retourFormulaire"/>">${lienRetourFormulaire}</a>
</body>
</html>
- línea 18: la URL de destino de HREF se escribe con la etiqueta <c:url> para que el token de sesión se incluya en ella en caso de que el cliente sea un navegador que no envíe el encabezado HTTP [Cookie].
Se invita al lector a probar estas nuevas vistas siguiendo el principio visto en las versiones anteriores.
12.5. El controlador [ServletPersonne]
El controlador [ServletPersonne] de la aplicación web [/personne7] es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
- línea 35: la acción [/retourFormulaire] se realiza mediante un GET y ya no mediante un POST como en la versión anterior.
- líneas 70-87: la acción [/validationFormulaire] se realiza mediante una acción POST, que se activa al hacer clic enuno de los botones [Envoyer] o [Effacer] de la vista [formulaire]. El método [doValidationFormulaire] gestiona estos dos casos mediante dos métodos diferentes.
- líneas 90-103: el método [doEnvoyer] corresponde al método [doValidationFormulaire] de la versión anterior. Los datos introducidos se almacenan en la sesión (líneas 96-98), mientras que en la versión anterior se colocaban en la consulta.
- líneas 58-67: el nuevo método [doEffacer] debe mostrar un formulario vacío. Se podría recurrir al método [doInit], que ya realiza esta tarea. Aprovechamos para borrar también los elementos [nom, age] de la sesión, de modo que esta siga reflejando el último estado del formulario.
- Líneas 50-55: solicitan la visualización de la vista [formulaire] sin una inicialización aparente de la plantilla de dicha vista. Esta plantilla está compuesta, de hecho, por los elementos [nom, age] que ya se encuentran en la sesión. No es necesario hacer nada más.
12.6. Pruebas
Inicie o reinicie Tomcat tras haber integrado en él el proyecto Eclipse [personne-mvc-07] y, a continuación, solicite la URL [http://localhost:8080/personne7] con un navegador en el que se hayan desactivado las cookies y se hayan eliminado las ya existentes. Se obtiene la siguiente respuesta:

El código fuente recibido por el navegador es el siguiente:
En la línea 1, el token de sesión se encuentra en la URL de destino de POST.
Rellenemos el formulario y enviémoslo:

El código fuente que recibe el navegador es el siguiente:
En la línea 3, el token de sesión aparece en la URL de destino del enlace.

