TP 2 : technologies côté serveur (servlets/JSP)

Objectifs pédagogiques du TP

Outils

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.

Description de l'application

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 :

Préambule

Configuration du projet Maven

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>

Configuration pour l'utilisation d'Expression Language en JSP

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">

Description de l'interface et architecture des composants de l'application

Accueil

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 ».

page d'accueil du chat

Initialisation

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 ».

Chat

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 :

page d'accueil du chat

Remarques :

Partie 1  : conception basique de l'application

Pages statiques

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.

Intialisation

Créez ensuite une nouvelle servlet « Init ». Cette servlet répondra aux requêtes en GET ou en POST, et effectuera les traitements suivants :

Interface de gestion des messages

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 :

  1. Réception et mémorisation des messages envoyés par POST : à la réception d'une requête POST, la page récupère le texte du message dans le paramètre de la requête ad hoc, ainsi que le nom de son auteur dans l'attribut de session stocké par Init. Elle crée alors un nouveau message, qu'elle place en queue de liste.
  2. Affichage des messages : à la réception d'une requête (GET ou POST), la page parcourt la liste et affiche tous les messages avec la mise en forme qui vous plaîra. En l'absence d'envoi de données de la part du client, cet affichage s'actualisera toutes les 5 secondes.

Indications :

Ajout de salons

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.

Partie 2 : Refactoring de votre application

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.

JavaBean

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.

Pattern contexte

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é.

Inclusion/transfert de requêtes

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... 

Pattern MVC

À 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 :

Utilisation d'attribut de requête

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.

Pattern chaîne de responsabilité

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.

Partie 3 : amélioration de l'application

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.

Utilisation des en-têtes HTTP

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 :

  1. vérifiez que votre serveur envoie bien au client un en-tête Last-Modified à la génération de la réponse ; sinon, rajoutez-le dans « Affichage.jsp »
  2. vérifiez que votre client vous renvoie bien cette valeur dans un en-tête If-Modified-Since lors de la requête d'actualisation de la page « Messages.jsp »
  3. rajoutez un attribut permettant de stocker la valeur de dernière modification de la liste des messages dans le contexte de l'application etfaites en sorte que « Stockage.jsp » actualise sa valeur à chaque appel
  4. lors de l'appel en GET de « Messages.jsp », comparez la valeur de l'en-tête If-Modified-Since reçu avec celle de l'attribut du contexte applicatif et réagissez en conséquence (génération de la page ou code de statut 304).

Utilisation des cookies

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.

  1. rajoutez / updatez un cookie chez votre client indiquant le numéro du dernier message obtenu lors de l'envoi d'une réponse par « Affichage.jsp »
  2. lors de la réception d'une requête GET par « Messages.jsp », testez l'existence de ce cookie et comparez sa valeur au nombre total de messages mémorisés
  3. réagissez en conséquence (voir plus haut).
Indication :

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.

Licence Creative Commons
Valid XHTML 1.0 Strict