12. Application web MVC [personne] – version 7
12.1. Introduction
Dans cette version, nous supposons qu'il peut y avoir des navigateurs clients qui ont inhibé :
- le renvoi des cookies qu'envoie le serveur
- l'exécution de code Javascript embarqué dans les pages HTML affichées
On veut néanmoins que ce type de navigateurs puisse utiliser notre application. Le point 2 nous ramène à la version 2 de notre application, le Javascript ayant été utilisé à partir de la version 3. La version 2 faisait fonctionner l'application sans Javascript donc le point 2 est résolu.
Le point 1 peut être délicat ou non à gérer. La version 6 de notre application fonctionnait sans cookies. En fusionnant les versions 2 et 6, nous obtenons le résultat demandé. Nous allons ajouter une contrainte supplémentaire : l'application doit gérer une session. Ce n'est pas une contrainte dénuée de sens. Dans une application où les utilisateurs doivent s'authentifier, le serveur doit mémoriser le couple (identifiant / mot de passe) de l'utilisateur pour lui éviter de s'authentifier à chaque page qu'il demande.
Nous avons utilisé jusqu'à maintenant trois solutions pour mémoriser des informations au fil des échanges client / serveur :
- la session
- les cookies
- les champs cachés.
La solution 2 peut être éliminée puisque le navigateur client peut avoir inhibé l'utilisation des cookies.
La solution 3 est celle de la version 6 précédemment étudiée. Elle ne peut être utilisée pour des raisons de sécurité. Si le couple (login / mot de passe) est encapsulé dans chaque page envoyée au navigateur, cela veut dire qu'il transite sur le réseau à chaque échange client / serveur. Cela n'est pas bon pour la sécurité de l'application. On peut alors envisager d'utiliser le protocole HTTPS qui crypte les échanges client / serveur. Mais l'utiliser pour chaque page de l'application va alourdir la charge du serveur.
On pourrait vouloir éliminer la solution 1 parce qu'elle est également à base de cookies. Lors du premier échange client / serveur, le serveur envoie au client un jeton de session que celui-ci va renvoyer au serveur à chaque nouvelle demande. Grâce à ce jeton, le serveur va pouvoir reconnaître son client et lui affecter des informations qu'il avait mémorisées lors d'un échange précédent. Le jeton de session est envoyé par le serveur dans un cookie. Le navigateur qui n'a pas inhibé ses cookies peut lui renvoyer ce cookie lors de ses demandes suivantes. S'il a inhibé ses cookies, il dispose d'une autre solution : il peut inclure le jeton de session dans l'Url qu'il demande. C'est ce que nous voyons maintenant en reprenant l'étude du fichier [index.jsp] de la version 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"/>
On rappelle que la ligne 5 ci-dessus redirige le client vers l'Url [/personne4/main?jsessionid=XX] où XX est le jeton de session comme le montre la copie d'écran ci-dessous obtenue après avoir demandé l'Url [http://localhost:8080/personne4] :

Examinons de plus près le fonctionnement de la balise <c:redirect> pour ce qui est du jeton de session. Prenons un navigateur où les cookies sont acceptés. Ci-dessous, on configure le navigateur Firefox :

En [1], nous autorisons les cookies et en [2] nous supprimons ceux qui existent déjà afin de partir d'une situation connue. Puis nous demandons l'Url [http://localhost:8080/personne4]. Nous obtenons la réponse suivante :

La demande HTTP initiale du client a été la suivante :
On notera simplement que le client n'envoie pas de cookie de session. La réponse HTTP envoyée par le serveur est la suivante :
- ligne 1 : le serveur demande au client de se rediriger
- ligne 3 : le serveur envoie un jeton de session associé à l'attribut [JSESSIONID]
- ligne 4 : l'Url de redirection contient le jeton de session. La balise <c:redirect> l'y a placé parce que le client n'avait pas envoyé de cookie de session.
Le navigateur, à qui on a demandé de se rediriger, a ensuite fait la demande suivante :
- ligne 1 : il demande l'Url de redirection, jeton de session inclus. C'est pourquoi sur la copie d'écran, le navigateur affiche-t-il cette Url.
- ligne 10 : le navigateur renvoie le jeton de session que lui a envoyé dans l'échange précédent le serveur. C'est le fonctionnement normal des cookies lorsque ceux-ci sont autorisés sur le navigateur client. Si ce n'est pas le cas, les cookies reçus ne sont pas renvoyés.
Le serveur a répondu la chose suivante à cette seconde demande :
Il a trouvé la page qu'on lui demandait et il l'envoie. On notera qu'il n'envoie plus le jeton de session. C'est le fonctionnement normal du jeton de session : il est envoyé au navigateur une unique fois par le serveur sous la forme d'un cookie et le navigateur le renvoie ensuite à chaque demande pour se faire reconnaître.
Maintenant, avec le même navigateur, demandons de nouveau l'Url [http://localhost:8080/personne4] en la tapant à la main. On obtient alors la page suivante :

On constate que l'Url affichée par le navigateur ne contient plus le jeton de session. Regardons le premier échange client / serveur :
Le navigateur a fait la demande suivante :
C'est exactement la même demande que la fois précédente avec cependant une différence : ligne 10, le navigateur renvoie le jeton de session qu'il avait reçu lors du tout premier échange. Encore une fois, c'est le fonctionnement normal si les cookies du navigateur sont actifs.
Le serveur a envoyé la réponse suivante :
Il demande au client de se rediriger. Comme il a reçu un jeton de session du client, il poursuit celle-ci et n'envoie pas de nouveau jeton de session. Pour la même raison, la balise <c:redirect> n'inclut pas ce jeton de session dans l'Url de redirection. C'est pourquoi l'Url affichée par la copie d'écran ci-dessus n'a-t-elle pas de jeton de session.
On retiendra de tout ça la règle suivante : la balise <c:redirect> n'inclut le jeton de session dans l'Url de redirection que si le client n'a pas envoyé l'entête HTTP :
Cette règle est également vraie pour la balise <c:url> que nous aurons l'occasion de rencontrer ultérieurement.
Que se passe-t-il avec un navigateur sur lequel on a inhibé les cookies ? Essayons. Tout d'abord nous réinitialisons le navigateur :

En [1], nous inhibons les cookies et en [2] nous supprimons ceux qui existent déjà afin de partir d'une situation connue. Puis nous demandons l'Url [http://localhost:8080/personne4]. Nous obtenons la réponse suivante :

Nous obtenons le même résultat que précédemment. Les échanges HTTP ne sont pourtant pas exactement les mêmes :
- lignes 1-9 : la demande n° 1 du navigateur. Il n'envoie pas de cookie de session.
- lignes 11-17 : la réponse du serveur qui lui demande de se rediriger vers une autre Url. Il envoie un cookie de session ligne 13 : la balise <c:redirect> a inclus le jeton dans l'Url de redirection ligne 14.
- lignes 19-27 : la demande n° 2 du navigateur. Il ne renvoie pas le cookie de session que vient de lui envoyer le serveur parce que ses cookies sont inhibés.
- lignes 29-33 : la réponse du serveur. On peut constater que bien que le navigateur ne lui ait pas envoyé de cookie de session, il ne redémarre cependant pas une nouvelle session comme on aurait pu s'y attendre. On voit cela au fait qu'il n'envoie l'entête HTTP [Set-Cookie] comme il l'avait fait ligne 13. Cela signifie qu'il continue la session précédente. Il a pu retrouver celle-ci grâce au jeton de session présent dans l'Url demandée par le navigateur ligne 19.
On retiendra que le serveur suit une session en récupérant le jeton de session envoyé par le client, de deux façons possibles :
- dans l'entête HTTP [Set-Cookie] envoyé par le client
- dans l'Url demandée par le client
Maintenant, avec le même navigateur, demandons de nouveau l'Url [http://localhost:8080/personne4] en la tapant à la main, comme il avait été fait lorsque les cookies étaient autorisés. On obtient alors la page suivante :

On a un résultat différent de celui obtenu lorsque les cookies étaient autorisés : le jeton de session est dans l'Url affichée par le navigateur. Exliquons ce résultat sans étudier les échanges HTTP qui ont eu lieu :
[cookies autorisés]
- lors de la seconde demande de l'Url [http://localhost:8080/personne4], le navigateur client avait renvoyé le cookie de session qu'il avait reçu du serveur lors de la première demande de cette même Url. La balise <c:redirect> n'avait donc pas inclus le jeton de session dans l'adresse de redirection.
[cookies inhibés]
- lors de la seconde demande de l'Url [http://localhost:8080/personne4], le navigateur client n'envoie pas le cookie de session qu'il a reçu du serveur lors de la première demande de cette même Url, puisque ses cookies sont inhibés. La balise <c:redirect> inclut donc le jeton de session dans l'adresse de redirection. C'est pourquoi on le trouve sur la copie d'écran ci-dessus.
Les balises <c:redirect> et <c:url> permettent d'inclure le jeton de session dans les Url. C'est la solution qui est proposée ici.
12.2. Le projet Eclipse
Pour créer le projet Eclipse [mvc-personne-07] de l'application web [/personne7], on dupliquera le projet [mvc-personne-06] en suivant la procédure décrite au paragraphe 6.2.
![]() | ![]() |
12.3. Configuration de l'application web [personne7]
Le fichier web.xml de l'application /personne7 est le suivant :
<?xml version="1.0" encoding="UTF-8"?>
...
<display-name>mvc-personne-07</display-name>
...
Ce fichier est identique à celui de la version précédente hormis la ligne 3 où le nom d'affichage de l'application web a changé en [mvc-personne-07]. La page d'accueil [index.jsp] ne change pas.
...
<c:redirect url="/do/formulaire"/>
12.4. Le code des vues
Les vues [formulaire, réponse, erreurs] redeviennent ce qu'elles étaient dans la version 2, c.a.d. sans Javascript. Cependant elles conservent les balises JSTL des dernières versions.
12.4.1. La vue [formulaire]

On a enlevé les boutons associés à du code 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>
- ligne 14 : l'Url cible du POST est écrite avec la balise <c:url> afin que le jeton de session y soit au cas où le client serait un navigateur n'envoyant pas l'entête HTTP [Cookie].
- le formulaire a deux boutons de type [submit] : [Envoyer] (ligne 28) et [Effacer] (ligne 30). Les deux boutons portent le même nom : bouton. Au moment du POST, le navigateur enverra le paramètre :
- bouton=Envoyer si le POST a été provoqué par le bouton [Envoyer]
- bouton=Effacer si le POST a été provoqué par le bouton [Effacer]
C'est ce paramètre qui nous aidera à définir l'action exacte à faire, l'Url [/do/validationFormulaire] correspondant maintenant à deux actions distinctes.
12.4.2. La vue [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>
- ligne 24 : l'Url cible du HREF est écrite avec la balise <c:url> afin que le jeton de session y soit au cas où le client serait un navigateur n'envoyant pas l'entête HTTP [Cookie].
12.4.3. La vue [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>
- ligne 18 : l'Url cible du HREF est écrite avec la balise <c:url> afin que le jeton de session y soit au cas où le client serait un navigateur n'envoyant pas l'entête HTTP [Cookie].
Le lecteur est invité à tester ces nouvelles vues selon le principe vu dans les versions précédentes.
12.5. Le contrôleur [ServletPersonne]
Le contrôleur [ServletPersonne] de l'application web [/personne7] est le suivant :
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 | |
- ligne 35 : l'action [/retourFormulaire] est faite par un GET et non plus par un POST comme dans la version précédente.
- lignes 70-87 : l'action [/validationFormulaire] est faite par un POST provoqué par un clic sur l'un des boutons [Envoyer] ou [Effacer] de la vue [formulaire]. La méthode [doValidationFormulaire] fait traiter ces deux cas par deux méthodes différentes.
- lignes 90-103 : la méthode [doEnvoyer] correspond à la méthode [doValidationFormulaire] de la version précédente. Les données saisies sont mises dans la session (lignes 96-98) alors dans la version précédente elles étaient placées dans la requête.
- lignes 58-67 : la nouvelle méthode [doEffacer] doit afficher un formulaire vide. On pourrait faire appel à la méthode [doInit] qui fait déjà ce travail. Ici, on en profite pour également effacer les éléments [nom, age] de la session afin que celle-ci continue à refléter le dernier état du formulaire.
- lignes 50-55 : demandent l'affichage de la vue [formulaire] sans initialisation apparente du modèle de cette vue. Ce modèle est en fait constitué des éléments [nom, age] déjà dans la session. Il n'y a pas lieu de faire davantage.
12.6. Tests
Lancer ou relancer Tomcat après y avoir intégré le projet Eclipse [personne-mvc-07] puis demander l'url [http://localhost:8080/personne7] avec un navigateur dont on a inhibé les cookies et supprimé ceux existant déjà. On obtient la réponse suivante :

Le code source reçu par le navigateur est le suivant :
Ligne 1, le jeton de session est dans l'Url cible du POST.
Remplissons le formulaire et validons-le :

Le code source reçu par le navigateur est le suivant :
Ligne 3, le jeton de session est dans l'Url cible du lien.

