TP 5 : Programmation côté client (requêtage asynchrone)
Important : suite à la publication de l'API de correction
- Merci de baser votre client sur l'API de correction et non plus la vôtre.
- Vous ne pouvez l'interroger que depuis l'une des origines suivantes : http:localhost:8080, https://192.168.75.XX ou http://192.168.75.XX:8080.
- Je remettrai régulièrement la liste d'utilisateurs et de groupes à zéro pour "nettoyer" le serveur.
Objectifs pédagogiques du TP
- Se familiariser avec les mécanismes de base des technologies AJAX
- Traiter des données reçues de manière asynchrone côté client
Outils
- Logiciels installés sur les machines de TP : Navigateurs Web, EDI NetBeans / Eclipse / IntelliJ, serveurs Tomcat et Jetty
- Logiciels que vous pouvez installer chez vous : idem.
- Tutoriels : voir partie "Liens utiles" de la page d'accueil du cours
- Bibliothèque de fonctions JavaScript qui réalisent l'envoi de la requête et le traitement de la réponse en asynchrone : disponible ici
Références
Première application AJAX
Cette partie n'est pas à rendre. Elle est destinée à vous "dérouiller" sur l'envoi de requêtes asynchrone.
Vous allez réaliser une application simple en Ajax qui se contente d'afficher l'heure sur le client en interrogeant le serveur de manière asynchrone. Pour cela, un projet pré-configuré est disponible ici : https://forge.univ-lyon1.fr/LIONEL.MEDINI/m1if03-tpclient-ajax. Clonez le repo de ce projet. Quelques infos sur ce projet :
- Commande de démarrage
- mvn jetty:run
- Adresse de la page d'accueil
- http://localhost:8080/index.html
- Cette page télécharge directement la bibliothèque AJAX décrite en cours (cf. rubrique "Outils").
- Rappel : la fonction principale de la bibliothèque AJAX s'appelle loadXMLAsynchroneously et prend les paramètres suivants :
- le nom de la méthode HTTP utilisée ('GET' ou 'POST'),
- l'URL relative de la ressource qui génère le document XML,
- les paramètres éventuels de cette requête ('toto=12&titi=nimportequoi', ou null sinon),
- la valeur de l'attribut id de l'élément de la page qui doit recevoir les données.
- Adresse de la page JSP qui donne l'heure côté serveur
- http://localhost:8080/time.jsp
Dans la page d'accueil :
- ajoutez à l'élément body un attribut onload, pour appeler la fonction loadXMLAsynchroneously, pour qu'elle envoie une requête au serveur Web pour récupérer l'heure dans la page JSP
- écrivez une nouvelle fonction JavaScript qui génère le code HTML correspondant et rajoute ce code dans le contenu de la div timeDiv avec le DOM
- faites en sorte que l'heure se recharge dynamiquement toutes les secondes (cf. rubrique "Références")
Transformation XSLT
- Côté client, modifiez votre fonction de traitement pour qu'elle utilise un moteur XSLT pour réaliser la transformation du XML en un fragment XHTML
- Créez une feuille de style XSLT pour transformer le document reçu en un document SVG affichant une horloge à aiguilles et intégrez ce document SVG dans votre page Web.
Reprise de votre application de blog
Dans cette partie, vous allez consommer l'API de l'application de blog réalisée au TP précédent.
Pour rappel, l'application "v1" du TP3 est capable de tester si le client dispose ou non des derniers billets envoyés et de lui renvoyer la liste complète sinon. Elle possède les faiblesses suivantes :
- l'actualisation provoque un clignotement de la page toutes les 5 secondes
- l'actualisation de la page efface le texte que l'utilisateur peut être en train de taper
- à chaque nouveau billet, le client reçoit l'intégralité de la liste,
alors qu'il n'aurait besoin que des billets postérieurs à ceux qu'il connaît déjà
Vous allez donc concevoir une nouvelle version du client de l'application. Sur le même modèle que dans la question précédente, ce client téléchargera de manière asynchrone uniquement les billets qui lui manqueront (et idem pour les commentaires), et les rajoutera à l'interface sans effacement de la page affichée ni interruption de la tâche de l'utilisateur.
Dans un premier temps, vous réaliserez le squelette de l'application sous forme de Single-Page Application (SPA) et avec jQuery (utilisez un CDN). Ensuite, vous mettrez en place les scripts de communication asynchrones avec le serveur.
Pour éviter les problèmes de violation de la same-origin policy, vous placerez les éléments programmés dans ce TP sur le même serveur que celui de votre API. Pour cela, créez un répertoire client dans webapp, dans lequel vous placerez tout ce que vous aurez produit dans ce TP. La page d'accueil de votre application sur le serveur local devrait donc être accessible à une URL du type : http://localhost:8080/tp4/client.
Remarque : ce n'est pas une solution entièrement satisfaisante, et vous serez amenés à déplacer le client ultérieurement.
Single-Page Application
Vous allez réaliser l'application côté client sous forme de SPA. Le client n'aura qu'une seule page HTML à charger, et la sélection de la vue se fera en fonction du hash (la partie de l'URL après le caractère #) de la page.
L'application côté client sera constituée d'une page HTML statique (pas de génération dynamique côté serveur), contenant l'ensemble des vues nécessaires à son fonctionnement :
- Menu de l'application : permet d'accéder directement aux différentes vues de l'application ; les vues qui nécessitent d'être connecté ne devront pas être accessibles tant que l'utilisateur n'aura pas entré un pseudo
- Accueil de l'application (utilisateur non connecté) : formulaire permettant de se connecter
- Liste des groupes (utilisateur connecté) : affiche la liste des groupes. Permet de créer un groupe (formulaire) et d'accéder à un lien pour se déconnecter
- Groupe (utilisateur connecté) : permet de voir les infos du groupe, d'ajouter / supprimer des membres et d'obtenir des liens vers les billets du groupe
- Billet (utilisateur connecté) : permet d'afficher, de modifier ou de supprimer un billet donné, d'ajouter ou de supprimer des commentaires, et comporte également un lien de retour au groupe
- Liste des utilisateurs (utilisateur connecté) : affiche la liste des utilisateurs connus par le serveur (connectés ou non) et fournit un lien pour se déconnecter
- Déconnexion (utilisateur connecté) : affiche un texte demandant de confirmer, un lien pour revenir à la liste des groupes et un formulaire pour se déconnecter effectivement
Pour vous faire gagner du temps, une version de cette page vous est proposée ici.
À vous d'utiliser jQuery correctement (à l'aide de l'exemple vu en cours) pour :
- déplier / replier le menu quand on clique sur son titre
- mettre en place un mécanisme de routage qui affiche la vue correspondant au hash sélectionné
- permettre l'édition des champs texte affichés dans l'interface
À ce stade, vous devez avoir une SPA non fonctionnelle, mais dont les différentes vues (vides) s'affichent quand on clique sur les menus ou sur les liens.
Templating
Comme vu en cours, vous allez utiliser le moteur de templates Mustache pour remplir les vues.
- Dans un premier temps, créez des "mock objects" qui représentent des données en JSON qui pourraient provenir du serveur. Vous pouvez utiliser les exemples fournis par Swagger dans les réponses aux requêtes GET. Ici, les URIs dans les listes seront remplacés par des sous-objets. Stockez cette hiérarchie d'objets dans une variable globale.
- Rajoutez l'appel à Mustache dans votre page HTML
- Écrivez, dans des éléments <script> de la page HTML, des templates Mustache qui permettront de remplir chacune de vos vues
- Créez une fonction JS qui prend en paramètres :
- l'id d'un script contenant un template
- les données à templater
- l'id de l'élément HTML où placer le résultat
Cette fonction déclenchera le moteur de templating et ajoutera le résultat à la page
- Dans les fonctions de callback du routeur, appelez cette fonction de templating avec les bons paramètres pour qu'elle "remplisse" les vues avec les données mockées
Dans un second temps, optimisez le chargement des templates en les pré-compilant (voir cours).
À ce stade, vous devez avoir une SPA toujours non fonctionnelle, mais avec du contenu dans les vues.
AJAX
Vous allez maintenant utiliser JavaScript et jQuery pour les requêtes asynchrones au serveur. Exploitez l'API pour envoyer les requêtes permettant :
- connexion / déconnexion d'un utilisateur ; faites en sorte que le client navigue automatiquement (window.location en JavaScript) vers la vue représentant la liste des groupes
- Récupération et renvoi du token JWT au serveur
- récupération de la liste des groupes
- création / modification / récupération d'un groupe
- ajout / suppression de l'utilisateur courant aux membres d'un groupe
- création / récupération d'un billet
- faites en sorte que le script de rechargement des commentaires se relance asynchroniquement toutes les 5 secondes (cf. rubrique "Références")
- réutilisez votre travail sur le cache du TP3 pour ne pas recharger les commentaires déjà connus
Remarque : pour l'envoi des fomulaires en asynchrone, utilisez les fonctions de validation JavaScript (cf. rubrique "Références").
Votre SPA doit maintenant être pleinement fonctionnelle.
Fetch API
- Dans la vue d'un billet, remplacez les appels AJAX en jQuery des méthodes GET par des appels à la méthode fetch()
- Traitez les résultats en chaînant les promesses pour que chaque sous-propriété d'une ressource soit aussi obtenue par fetch().
Aide : pour les sous-propriétés, vous pouvez utiliser Promise.all().
Finalisation de votre application
Rajoutez une feuille de style (Bootstrap...).
Déployez-la sur votre VM.
Rendu du TP
Ce TP est à rendre pour le dimanche 8 décembre 2019 à 23h59.
Recommandations / rappels :
- Ne rendez que la dernière partie (votre application de blog et pas la partie horloge)
- Si vous avez fait l'horloge SVG, vous pouvez toutefois l'inclure à la page d'accueil de l'application de chat AJAX pour qu'elle soit prise en compte
- vérifiez que vous avez bien indiqué l'URL de votre projet dans Tomuss (et que vous avez la même URL que votre binôme)
- vérifiez que les liens entre les différents fichiers que vous allez rendre ne font pas référence à votre système de fichier propre ou ne contiennent pas d'URI absolues.
- n'oubliez pas de faire en sorte que vos documents soient en (X)HTML valide, que des feuilles de style CSS leur soient associés et que les scripts soient dans des fichiers séparés.