Téléchargements en local : vous trouverez la version 8 de Tomcat dans Ce répertoire. À décompresser dans le répertoire C:\Temp des machines de TP.
Attention : si vous devez installer Tomcat à partir de ce zip, vous devrez également configurer un utilisateur manager (etudiant/etudiant), que votre IDE utilisera pour monitorer le serveur.
Il s'agit d'une application Web de « chat » simple qui fonctionnera derrière un serveur Apache et un moteur de servlets et de JSP (inclus dans Tomcat).
Les tâches à réaliser sont les suivantes :
Dans ce TP, vous allez travailler dans un projet Web Maven. Pour créer votre projet, vous avez plusieurs possibilités :
Attention : Maven ne vous crée pas tout seul le répertoire src/main/java. À vous de le créer car c'est dans ce répertoire que vous allez devoir mettre vos fichiers Java. Si votre IDE indique src/main/resources dans la configuration des fichiers sources de votre projet, supprimez ce répertoire de la configuration.
Bien entendu, dans vos classes Java, n'oubliez pas de déclarer le package dans lequel elles sont situées.
Ensuite, vous devrez ajouter dans votre projet une dépendance sur l'API servlet. Pour cela, rajoutez le code suivant dans votre pom.xml :
<dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency>
Si vous voulez utiliser EL dans vos JSP, il faut que votre web.xml corresponde à l'API Servlet 2.4 ou supérieure. Exemple de code de l'élément racine :
<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_2_5.xsd" version="2.5">
La page d’accueil (« index.html », voir
figure
ci-dessous) contient un formulaire demandant un pseudo à
l’utilisateur. Le pseudo est saisi dans un champ texte, qui est
envoyé par la méthode POST à une
servlet, appelée « Init ».
La servlet « Init » effectue un traitement de la requête (voir plus loin), et redirige l’utilisateur sur une page HTML appelée « interface.html ».
Cette interface est celle qui est affichée pendant le fonctionnement "normal" de l'application (voir figure ci-dessous). Elle est reponsable des fonctionnalités suivantes :
Dans votre projet, commencez par créer les deux pages statiques « index.html » et « interface.html. Pour interface.html, faites en sorte de fixer la hauteur de l'iframe en fonction de la hauteur du formulaire, de façon à laisser un maximum de place pour l'affichage des messages.
Créez ensuite une nouvelle servlet « Init ». Cette servlet répondra aux requêtes en GET ou en POST, et effectuera les traitements suivants :
La page « Messages.jsp » permet de gérer les messages. Pour cela, elle possède une variable globale de type List<Message> (à vous de créer la classe Message). « Messages.jsp » a deux fonctions distinctes :
Indications :
Vous allez maintenant modifier votre application pour qu'elle prenne en charge plusieurs "salons de discussion".
À ce stade, vous avez réalisé une application de chat basique, mais fonctionnelle.
Une fois la session de chat lancée, la totalité de la logique applicative est gérée par « Messages.jsp », ce qui n'est pas très satisfaisant.
Créer une classe « GestionMessages » qui contiendra le modèle de votre application et qui possèdera les caractéristiques suivantes :
Vous utiliserez cette classe en tant que JavaBean dans « Messages.jsp », à l'aide de <jsp:useBean>. À vous de déterminer le scope de ce bean. Testez.
Plutôt que de stocker la map dans une variable globale, utilisez le contexte applicatif pour permettre à votre bean d'accéder à cette map. La JSP lui injectera le contexte à l'aide d'une propriété.
Vous allez maintenant créer deux nouvelles pages JSP :
Dès lors, « Messages.jsp » peut se borner à tester la méthode utilisée et à utiliser les actions <jsp:forward> et <jsp:include>. À vous de déterminer quelle st la JSP incluse et quelle est celle à qui la requête est forwardée...
À la question précédente, vous avez isolé la couche de stockage de celle de composition de l'interface. Mais la majorité de votre application est toujours gérée par des JSP. Refactorez votre application pour que :
Maintenant que vous avez un contrôleur, supprimez l'attribut de session mis en place pour la transmission du nom du salon et faites en sorte que celui-ci apparaisse dans l'URL de la requête et qu'il soit traité au niveau du contrôleur de l'application.
Remplacez la servlet Init par un Filter, qui vérifie, quelle que soit l'URL de la page appelée, que l'utilisateur est connecté (qu'il possède un login), avant de lui permettre d'accéder à l'application. Si ce n'est pas le cas, il sera redirigé vers le formulaire de connexion. Pour cela :
Attention : le filtre ne doit pas bloquer l'accès au formulaire de login. Vous configurerez votre application pour qu'il soit appliqué à toutes les URL sauf celle de ce formulaire.
L'état actuel de votre application est le suivant : toutes les 5 secondes, chaque client interroge le serveur, qui parcourt alors toute la liste de messages et re-génère dynamiquement un nouvel affichage contenant la totalité des messages enregistrés, qui sera renvoyé à chaque client via le réseau. Si le nombre d'utilisateurs est grand et/ou s'il y a de nombreux messages enregistrés dans la base, ce fonctionnement peut vite représenter une charge de travail importante pour le serveur, ainsi qu'une consommation inutile de bande passante réseau.
L'objectif de cette partie est d'améliorer le processus de récupération et d'affichage des messages échangés par les différents utilisateurs. Pour cela, vous allez permettre à votre application de déterminer si elle doit recalculer l'affichage des messages pour un client, ou s'il n'y a pas lieu de le faire. Deux possibilités sont à votre disposition.
La plupart des clients renvoient au serveur un en-tête HTTP If-Modified-Since, indiquant la date de leur dernier chargement d'une page. Si cette date est postérieure à celle du dernier POST reçu, aucun nouveau message n'est disponible. Plutôt que de renvoyer une réponse HTTP contenant une page complète, il suffit de renvoyer juste un en-tête HTTP, avec le code de statut 204 indiquant au client que la page n'a pas été modifiée.
Pour cela :
Si le numéro du dernier message mémorisé (i.e. le nombre total de messages) est égal à celui du dernier message envoyé à un client (i.e. le nombre total de messages au moment où le serveur lui a servi la réponse), cela signifie qu'aucun message n'est arrivé depuis la dernière requête du client. Il est donc inutile de lui renvoyer la page.
Utilisez le getter de « GestionMessages » permettant de récupérer le nombre total de messages.
Vous avez maintenant commencé l'optimisation de votre application en termes de charge serveur et de bande passante réseau. Ce travail sera poursuivi lors des TPs REST et AJAX.