WebSockets avec Spring Boot : Tutoriel Avancé
Pourquoi WebSockets avec Spring Boot ?
En tant que développeur senior, vous avez certainement besoin de gérer des communications en temps réel entre les clients et le serveur dans vos applications web. Les WebSockets fournissent une solution idéale pour cela. Ils permettent aux serveurs et aux clients d'établir une connexion persistante qui reste ouverte même lorsque l'application est active. Cette connexion permet aux deux parties de transférer des données en temps réel sans avoir à recourir à des requêtes HTTP traditionnelles, ce qui augmente la performance de l'application.
Un cas d'utilisation concret serait un application de chat en direct, où chaque message envoyé par un utilisateur doit être instantanément affiché sur le côté du destinataire. Les WebSockets sont parfaitement adaptés à cette situation car ils permettent une communication bidirectionnelle et réactive entre les clients et le serveur.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Connaissance approfondie de Java et Spring Boot
- Un environnement de développement intégré (IDE) comme IntelliJ IDEA ou Eclipse
- Maven pour la gestion des dépendances
- Node.js et npm pour le serveur backend
Concepts fondamentaux
1. WebSocket Protocol
Le protocole WebSocket permet une connexion continue entre le client et le serveur, où les deux parties peuvent envoyer des données à tout moment sans avoir besoin de se reconnecter.
Schéma mental :
[Client] <------------------> [Serveur]
| |
| Handshake |
| |
v v
Established connection Established connection
^ ^
| |
| Send/Receive data | Send/Receive data
v v
Code :
// WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
2. StompMessageHandler
Le StompMessageHandler est utilisé pour traiter les messages STOMP (Simple Text Oriented Messaging Protocol), qui est le protocole de communication utilisé sur les WebSockets.
Schéma mental :
[Client] <------------------> [Serveur]
| |
| Send message |
| |
v v
MessageHandler processes the message
Code :
// MessageController.java
@Controller
public class MessageController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public String greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
return "Hello, " + message;
}
}
3. SockJS
SockJS est une bibliothèque JavaScript qui permet aux navigateurs de se connecter à un serveur WebSocket. Si la connexion WebSocket échoue, SockJS peut basculer sur d'autres méthodes de transport (comme HTTP long-polling).
Schéma mental :
[Client] <------------------> [Serveur]
| |
| Connect using SockJS |
| |
v v
Established connection via SockJS
Mise en pratique : projet fil rouge
Étape 1 : Créer un nouveau projet Spring Boot
Créer un nouveau projet Spring Boot avec les dépendances suivantes :
spring-boot-starter-webspring-boot-starter-websocket
Utilisez le générateur de projet Spring Initializr.
Code :
mvn archetype:generate -DgroupId=com.example -DartifactId=websocket-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Étape 2 : Configurer la connexion WebSocket
Ajoutez le code suivant dans WebSocketConfig.java pour configurer la connexion WebSocket.
Code :
// WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
Étape 3 : Créer le controller pour traiter les messages
Créez un MessageController.java pour traiter les messages STOMP.
Code :
// MessageController.java
@Controller
public class MessageController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public String greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
return "Hello, " + message;
}
}
Étape 4 : Créer le client JavaScript
Créez un fichier index.html avec un script JavaScript pour connecter au serveur WebSocket et envoyer/recevoir des messages.
Code :
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Example</title>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body>
<h1>WebSocket Example</h1>
<input type="text" id="messageInput" placeholder="Enter a message">
<button onclick="sendMessage()">Send</button>
<script type="text/javascript">
var stompClient = null;
function connect() {
var socket = new SockJS('/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (message) {
showMessage(JSON.parse(message.body).content);
});
});
}
function sendMessage() {
var messageInput = document.getElementById('messageInput');
var message = { content: messageInput.value };
stompClient.send("/app/hello", {}, JSON.stringify(message));
messageInput.value = '';
}
function showMessage(message) {
var ul = document.getElementById('messages');
var li = document.createElement('li');
li.textContent = message;
ul.appendChild(li);
}
window.onload = connect;
</script>
</body>
</html>
Étape 5 : Exécuter l'application
Exécutez le serveur Spring Boot et accédez à http://localhost:8080 dans votre navigateur pour voir l'exemple en action.
Commande :
mvn spring-boot:run
Erreurs frequentes et debugging
1. Connexion WebSocket échoue
Message d'erreur :
WebSocket connection to 'ws://localhost:8080/ws' failed
Code incorrect :
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public String greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
return "Hello, " + message;
}
Code correct :
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public String greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
return "Hello, " + message;
}
2. Message non reçu
Message d'erreur :
No destination found for message: ...
Code incorrect :
@Controller
public class MessageController {
@MessageMapping("/hello")
public void greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
System.out.println("Hello, " + message);
}
}
Code correct :
@Controller
public class MessageController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public String greeting(@Payload String message) throws Exception {
Thread.sleep(1000); // simulated delay
return "Hello, " + message;
}
}
3. Erreur de configuration
Message d'erreur :
Could not find default endpoint in registry
Code incorrect :
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
}
}
Code correct :
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}
Pour aller plus loin
1. Sécurité avec Spring Security
Pour sécuriser votre application WebSocket, vous pouvez utiliser Spring Security.
2. Gestion des abonnements
Vous pouvez gérer les abonnements de manière plus fine pour optimiser la performance et la sécurité.
3. Gestion des erreurs
Ajoutez une gestion robuste des erreurs pour améliorer l'expérience utilisateur et la fiabilité de votre application.
Handling Exceptions in Spring MVC
Défi pratique
Créez une application simple qui permet aux utilisateurs de partager des fichiers en temps réel. Utilisez WebSocket pour transmettre les fichiers entre le client et le serveur.