Chat avec Spring et WebSockets

Chat avec Spring, WebSockets et Jetty

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

L'avènement et la démocratisation du HTML 5 à travers de nouvelles version des navigateurs accélerent des changements dans la communication. Désormais la communication en temps réel peut se faire en écrivant une dizaine des lignes de code qui gérera les WebSockets.

Définition des WebSockets

WebSockets sont arrivés avec HTML 5 en tant qu'une API permettant de développer une application bi-directionnelle permanente entre un client et un serveur. Cette relation peut être employée, par exemple, dans le développement des jeux en ligne multi-utilisateurs ou dans les outils de communication en temps réel (chat).

Le schéma de fonctionnement est le suivant :

Le client (navigateur) envoie une demande de connexion au serveur qui gère les connexions du WebSocket.
(1) ↓

Si l'utilisateur est admis à accéder au WebSocket, le serveur lui ouvre une connexion persistante. La connexion est donc établie pour la relation navigateur - serveur.

Le serveur configure la connexion (timeout) ainsi que la rajoute dans la liste des connexions actives.

Ensuite le serveur envoie un événement au client.

(2) ↓

Le client analyse le message envoyé par le serveur. En fonction de son contenu, il peut afficher soit la connexion, soit la déconnexion au WebSocket.

Une fois la connexion entre les deux établie, le client peut envoyer ses messages au serveur. Supposons qu'il décide de taper "Bonjour" dans notre application de chat.

(3) ↓

Le serveur reçoit le message "Bonjour". Il lance la fonction chargée de traiter cet événement (un message entrant) : onmessage.

Si aucune erreur s'est produite pendant la traitement, une réponse de serveur est ensuite envoyée au client. En fonction de la configuration du serveur, il peut y avoir un ou plusieurs destinataires.

(4) ↓
Le message est reçu par le ou les destinataires. Il peut être affiché sur l'écran.

Installer un serveur WebSocket en Java

Pour installer notre serveur WebSocket utilisé pour le chat, on utilisera le package org.eclipse.jetty. Jetty fournit un serveur web ainsi qu'un container pour les servlets. Il supporte également les technologies suivantes : SPDY, Web Sockets, OSGi, JMX, JNDI, JASPI, AJP... .

Son implémentation sera basée sur 3 fichiers :
- Message.java : représente le message renvoyé au client. Il est composé uniquement de setters et de getters. C'est pourquoi son code ne sera pas expliqué dans cette partie.
- Launcher.java : démarre le serveur WebSocket.
- ChatWebSocketHandler.java : gère toute la communication entre le serveur et le client. Il s'occupe d'ouvrir une connexion, de la fermer, d'envoyer les messages à des destinataires.

On commencera notre intégration par ce dernier ficher dont la classe est utilisée par le démarreur :

afficher le code

Chaque fois où une nouvelle connexion est établie, la méthode doWebSocketConnect() est invoquée. Elle retourne l'implémentation de l'interface WebSocket.OnTextMessage qui représente les événements reçus de la part du client. Elle contient les méthodes qui sont appelées quand la connexion est ouverte (onOpen()), fermée (onClose()) et quand un nouveau message arrive (onMessage()). On s'intéressera à cette dernière fonction. Elle analyse d'abord le message reçu sous format JSON. Ensuite elle le délègue à son expéditeur. Si l'expéditeur n'est pas un administrateur, le message est également envoyé à l'administrateur avec qui l'expéditeur s'entretient.

Et voici le code de la classe qui démarre le serveur WebSocket :

afficher le code

Le code est simple. Tout d'abord on récupère l'adresse du serveur du WebSocket. Ensuite on l'initialise avec la classe Server. Plus loin on enregistre le gestionnaire des connexions WebSocket (ChatWebSocketHandler). A la fin on démarre le serveur.

Ensuite pour démarrer le serveur dans la ligne de commandes, il faut appeler java chat.Launcher. Il est nécessaire que le serveur démarre avant notre application de chat.

Créer un client WebSocket en JavaScript

Pour notre client (navigateur), on utilisera le code de source préparé pour ce projet : https://github.com/Flynsarmy/PHPWebSocket-Chat . Le voici :

afficher le code

On y remarque la présence des mêmes méthodes que pour le code du serveur. Elles gérent donc la connexion (connect()), la déconnexion (disconnect()) ainsi que la réception d'un nouveau message (message()).

L'implémentation de cette classe est la suivante (on utilise jQuery pour déterminer quand la page est chargée) :

afficher le code

Rien de spécial. On associe à l'objet Server les méthodes à invoquer à la connexion, à la déconnexion et à la réception d'un nouveau message. Et voici le dernier fichier, celui qui contient les méthodes utilisées ci-dessus :

afficher le code

Ces fonctions sont utilisées pour afficher l'état de connexion (log()), notifier l'utilisateur de la connexion/déconnexion (connected()/disconnected()) ainsi qu'envoyer le message au serveur (send).

Intégrer le WebSocket dans une application web Spring

L'intégration d'un chat basé sur le WebSocket dans Spring n'est pas une tâche compliquée. Dans notre cas on aura besoin des 2 contrôleurs et 2 vues (pour l'utilisateur et l'administrateur). Les deux contrôleurs fonctionnent selon le même schéma : tout d'abord on affiche une page avec le formulaire et ensuite on appelle une page en méthode POST afin d'insérer le contenu du chat dans la base de données. Cette insertion pourrait être évitée si l'on ne voulait pas archiver les conversations. Voici le code des deux contrôleurs qui, grâce à des articles précédents, devraient être automatiquement compréhensible :

afficher le code

Comme on peut le supposer, les fichiers de vue contiennent un formulaire, un conteneur pour afficher les messages liés au chat. Seule la vue de l'administrateur possède un élément supplémentaire qui est un conteneur pour toutes les conversations menées. Or, un administrateur, contrairement à un utilisateur, peut mener plusieurs chats en même temps. C'est pourquoi la méthode message() pour la page d'administration contient le code suivant :

afficher le code

Ce code a pour but de vérifier si une nouvelle conversation est initiée par l'utilisateur du côté frontend.

Bartosz KONIECZNY Communication en temps réel

Une question ? Une remarque ?

*

*

Un conseil Android

Comment accéder au localhost ?

A la place de 127.0.0.1 il faut utiliser 10.0.2.2.