Spring Boot Basic – Tag 8 von 10
Von Elyndra Valen, Senior Entwicklerin bei Java Fleet Systems Consulting


WebSockets in Spring Boot

📍 Deine Position im Kurs

TagThemaStatus
✅ 1Erste REST APIAbgeschlossen
✅ 2Spring Container & DIAbgeschlossen
✅ 3@Controller & Thymeleaf BasicsAbgeschlossen
✅ 4Thymeleaf Forms & MVC-PatternAbgeschlossen
✅ 5Konfiguration & LoggingAbgeschlossen
✅ 6DI & AOP im DetailAbgeschlossen
✅ 7Scopes in SpringAbgeschlossen
→ 8WebSockets in Spring Boot👉 DU BIST HIER!
9JAX-RS in Spring BootNoch nicht freigeschaltet
10Integration & AbschlussNoch nicht freigeschaltet

Modul: Spring Boot Basic (10 Arbeitstage)
Dein Ziel: Real-Time Communication mit WebSockets meistern!


📋 Voraussetzungen

Du brauchst:

  • ✅ Tag 1-7 abgeschlossen
  • ✅ REST APIs verstehen (GET, POST)
  • ✅ @Controller und Model funktionieren
  • ✅ Thymeleaf Templates erstellen können
  • ✅ Scopes verstehen (Session, Request)
  • 💡 Bonus: JavaScript Grundkenntnisse helfen!

Tag 7 verpasst? → Hier geht’s zum Blogbeitrag Tag 7


⚡ Was dich heute erwartet

Bisher: Du hast REST APIs gebaut – aber jeder Request braucht eine Antwort.

Das Problem:

Client fragt: "Gibt es neue Nachrichten?"
Server antwortet: "Nein."

30 Sekunden später...
Client fragt: "Gibt es neue Nachrichten?"
Server antwortet: "Nein."

30 Sekunden später...
Client fragt: "Gibt es neue Nachrichten?"
Server antwortet: "Ja, hier ist eine!"

→ Client muss STÄNDIG fragen (Polling) 😫
→ Verschwendet Bandbreite und Ressourcen!

Die Lösung: WebSockets!

Client verbindet sich mit Server
Server kann JEDERZEIT Nachrichten schicken!

Neue Nachricht kommt an
→ Server schickt SOFORT an Client!
→ Keine ständigen Requests nötig! ✅

🎯 Dein Lernpfad heute

Du arbeitest heute in mehreren aufbauenden Schwierigkeitsstufen. Arbeite in deinem eigenen Tempo durch die Schritte:

🟢 Grundlagen (Schritte 1-3)

Was du lernst:

  • WebSockets verstehen – was ist das?
  • Unterschied HTTP vs WebSocket
  • STOMP Protocol kennenlernen
  • WebSocket Configuration in Spring Boot
  • Dependencies einrichten
  • Zwei Ansätze: Low-Level vs STOMP

Ziel: Du verstehst WebSockets und hast die Basis konfiguriert

Dauer: ~2.5 Stunden


🟡 Professional (Schritte 4-6)

Was du lernst:

  • @MessageMapping – der WebSocket-Controller
  • Chat-Application mit STOMP bauen
  • Broadcasting (an alle senden)
  • Live Person-Notifications implementieren
  • Frontend mit JavaScript/SockJS

Ziel: Production-Ready Live-Chat und Real-Time Updates

Dauer: ~3.5 Stunden


🔵 Bonus: Enterprise Features (Schritte 7-8)

Was du lernst:

  • Point-to-Point Messages (an einen User)
  • WebSocket Security implementieren
  • Reconnect-Logik & Heartbeat
  • Rate Limiting für Messages
  • Presence Detection (wer ist online?)

Ziel: Enterprise-Level Real-Time Features beherrschen

Dauer: ~2 Stunden


💻 Los geht’s!

🟢 GRUNDLAGEN (Schritte 1-3)

Schritt 1: WebSockets verstehen (45 Min)

1.1 Das Problem mit klassischem HTTP

Erinnerst du dich an REST APIs von Tag 1?

@RestController
@RequestMapping("/api/persons")
public class PersonApiController {
    
    @GetMapping
    public List<Person> getAllPersons() {
        return personService.getAllPersons();
    }
}

Was passiert:

┌─────────────────────────────────────────┐
│   CLIENT (Browser)                      │
│                                         │
│   GET /api/persons                      │
│   ────────────────────────────►         │
│                                         │
│                        ◄────────────────│
│                        [Person-Liste]   │
│                                         │
│   (30 Sekunden warten...)               │
│                                         │
│   GET /api/persons (erneut!)            │
│   ────────────────────────────►         │
└─────────────────────────────────────────┘

Das Problem:

  • ❌ Client muss aktiv fragen (Polling)
  • ❌ Server kann nicht von sich aus senden
  • ❌ Verschwendet Bandbreite (ständige Requests)
  • ❌ Langsam (30 Sekunden bis neue Daten sichtbar)
  • ❌ Hohe Server-Last (viele unnötige Requests)

1.2 Die Lösung: WebSockets

WebSocket = Dauerhafte Verbindung zwischen Client und Server!

┌─────────────────────────────────────────┐
│   CLIENT                    SERVER      │
│                                         │
│   WebSocket-Verbindung aufbauen         │
│   ════════════════════════►             │
│                                         │
│   ◄══════════════════════►              │
│   (Verbindung bleibt offen!)            │
│                                         │
│   Client sendet Nachricht               │
│   ────────────────────────►             │
│                                         │
│   Server sendet SOFORT zurück           │
│   ◄────────────────────────             │
│                                         │
│   Server sendet neue Daten (von sich!)  │
│   ◄────────────────────────             │
└─────────────────────────────────────────┘

Vorteile:

  • ✅ Bidirektional – beide Seiten senden
  • ✅ Real-Time – Daten sofort da
  • ✅ Effizient – eine Verbindung statt viele Requests
  • ✅ Server-Push – Server kann initiieren
  • ✅ Weniger Overhead – keine HTTP-Headers bei jedem Request

1.3 HTTP vs WebSocket – Der Vergleich

FeatureHTTP (REST)WebSocket
VerbindungPro Request neuDauerhaft offen
RichtungClient → ServerBeide Richtungen
OverheadHoch (Headers)Niedrig (einmal Handshake)
Real-TimeNein (Polling nötig)Ja (sofort)
Use CasesCRUD, FormulareChat, Live-Updates, Gaming
Server-PushNeinJa

Wann was nutzen?

✅ Nutze HTTP/REST für:
- Formulare absenden
- Daten laden (einmalig)
- CRUD-Operationen
- Datei-Downloads
- Statische Inhalte

✅ Nutze WebSockets für:
- Chat-Applications
- Live-Notifications
- Multiplayer-Games
- Live-Dashboards
- Collaborative Editing
- Stock-Ticker

1.4 STOMP – Das Messaging-Protocol

WebSocket alleine = nur „Rohr“ für Daten!

Du brauchst ein Protocol darüber – wie strukturierst du Nachrichten?

STOMP = Simple Text Oriented Messaging Protocol

┌─────────────────────────────────────────┐
│   Application (dein Java-Code)          │
│   ─────────────────────────────────     │
│   STOMP (Messaging-Protocol)            │
│   ─────────────────────────────────     │
│   WebSocket (Transport-Layer)           │
│   ─────────────────────────────────     │
│   TCP/IP                                │
└─────────────────────────────────────────┘

Was macht STOMP:

  • 📨 Destinations – „/topic/chat“ (wie REST-Pfade)
  • 🎯 Subscribe – Client abonniert Topics
  • 📤 Send – Client sendet an Destination
  • 📥 Receive – Server sendet an Subscriber
  • 💬 Frames – Strukturierte Nachrichten

Spring Boot nutzt STOMP standardmäßig! Du musst es nicht manuell implementieren.


Schritt 2: Dependencies hinzufügen (15 Min)

pom.xml:

<dependencies>
    <!-- Existing dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- WebSocket Support -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
    <!-- Webjars für Frontend-Libraries -->
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>sockjs-client</artifactId>
        <version>1.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>stomp-websocket</artifactId>
        <version>2.3.4</version>
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>bootstrap</artifactId>
        <version>5.3.0</version>
    </dependency>
</dependencies>

Maven reload nicht vergessen!

mvn clean install

Schritt 3: WebSocket Configuration (1.5 Stunden)

3.1 STOMP-basierte Configuration

config/WebSocketConfig.java:

package com.example.springbootbasic.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker  // WebSocket aktivieren!
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // Simple Broker für Broadcasting
        config.enableSimpleBroker("/topic", "/queue");
        
        // Prefix für Messages die an Server gehen
        config.setApplicationDestinationPrefixes("/app");
    }
    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // WebSocket-Endpoint registrieren
        registry.addEndpoint("/ws")
                .withSockJS();  // Fallback wenn WebSocket nicht verfügbar
    }
}

Was bedeutet das?

/topic/* 
→ Broadcasting-Destinations (alle Subscriber bekommen Nachricht)
→ Beispiel: /topic/notifications (alle User sehen)

/queue/*
→ Point-to-Point-Destinations (nur ein User bekommt Nachricht)
→ Beispiel: /queue/user123/messages (nur User 123 sieht)

/app/*
→ Messages die an Server-Controller gehen
→ Beispiel: /app/chat.send → @MessageMapping("/chat.send")

/ws
→ WebSocket-Endpoint (Client verbindet sich hierhin)
→ Mit SockJS-Fallback wenn Browser kein WebSocket kann

3.2 Message-Models erstellen

dto/ChatMessage.java:

package com.example.springbootbasic.dto;

import java.time.LocalDateTime;

public class ChatMessage {
    
    private String content;
    private String sender;
    private MessageType type;
    private LocalDateTime timestamp;
    
    public enum MessageType {
        CHAT,
        JOIN,
        LEAVE
    }
    
    // Constructors
    public ChatMessage() {
        this.timestamp = LocalDateTime.now();
    }
    
    public ChatMessage(String content, String sender, MessageType type) {
        this.content = content;
        this.sender = sender;
        this.type = type;
        this.timestamp = LocalDateTime.now();
    }
    
    // Getters and Setters
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }
    
    public String getSender() { return sender; }
    public void setSender(String sender) { this.sender = sender; }
    
    public MessageType getType() { return type; }
    public void setType(MessageType type) { this.type = type; }
    
    public LocalDateTime getTimestamp() { return timestamp; }
    public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}

✅ Checkpoint Grundlagen

Kontrolliere:

  • [ ] Du verstehst was WebSockets sind
  • [ ] Du kennst den Unterschied zu REST APIs
  • [ ] Du weißt was STOMP ist
  • [ ] Dependencies sind in pom.xml
  • [ ] WebSocketConfig ist erstellt
  • [ ] Du verstehst /topic vs /queue
  • [ ] ChatMessage DTO ist erstellt

Alles ✅? Weiter zu 🟡 Professional!


🟡 PROFESSIONAL (Schritte 4-6)

Schritt 4: WebSocket-Controller erstellen (1.5 Stunden)

4.1 Chat-Controller mit @MessageMapping

controller/ChatController.java:

package com.example.springbootbasic.controller;

import com.example.springbootbasic.dto.ChatMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Controller;

@Controller
public class ChatController {
    
    private static final Logger log = LoggerFactory.getLogger(ChatController.class);
    
    @MessageMapping("/chat.send")  // Client sendet an /app/chat.send
    @SendTo("/topic/public")       // Broadcast an alle die /topic/public abonniert haben
    public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {
        log.info("Received message from {}: {}", 
            chatMessage.getSender(), 
            chatMessage.getContent());
        
        return chatMessage;  // Wird an alle Subscriber gesendet
    }
    
    @MessageMapping("/chat.join")
    @SendTo("/topic/public")
    public ChatMessage addUser(@Payload ChatMessage chatMessage,
                                SimpMessageHeaderAccessor headerAccessor) {
        
        // Username in WebSocket-Session speichern
        headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
        
        log.info("User joined: {}", chatMessage.getSender());
        
        chatMessage.setType(ChatMessage.MessageType.JOIN);
        chatMessage.setContent(chatMessage.getSender() + " ist dem Chat beigetreten!");
        
        return chatMessage;
    }
}

Was passiert hier?

Client sendet:
POST /app/chat.send
{
  "content": "Hallo Welt!",
  "sender": "Max",
  "type": "CHAT"
}

Server empfängt:
@MessageMapping("/chat.send") wird aufgerufen
→ Verarbeitet Nachricht
→ return chatMessage

Server sendet:
An /topic/public (Broadcasting!)
→ ALLE die /topic/public abonniert haben
→ bekommen die ChatMessage!

4.2 WebSocket Event Listener

listener/WebSocketEventListener.java:

package com.example.springbootbasic.listener;

import com.example.springbootbasic.dto.ChatMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

@Component
public class WebSocketEventListener {
    
    private static final Logger log = LoggerFactory.getLogger(WebSocketEventListener.class);
    
    private final SimpMessageSendingOperations messagingTemplate;
    
    public WebSocketEventListener(SimpMessageSendingOperations messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }
    
    @EventListener
    public void handleWebSocketConnectListener(SessionConnectedEvent event) {
        log.info("New WebSocket connection established");
    }
    
    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        
        String username = (String) headerAccessor.getSessionAttributes().get("username");
        
        if (username != null) {
            log.info("User disconnected: {}", username);
            
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setType(ChatMessage.MessageType.LEAVE);
            chatMessage.setSender(username);
            chatMessage.setContent(username + " hat den Chat verlassen!");
            
            messagingTemplate.convertAndSend("/topic/public", chatMessage);
        }
    }
}

Schritt 5: Frontend mit WebSocket (2 Stunden)

5.1 Chat-Template erstellen

templates/chat.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Spring Boot Chat</title>
    <link rel="stylesheet" th:href="@{/webjars/bootstrap/5.3.0/css/bootstrap.min.css}">
    
    <style>
        body {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        #chat-page { display: none; }
        
        .chat-container {
            max-width: 700px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.2);
        }
        
        .chat-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            border-radius: 10px 10px 0 0;
        }
        
        .chat-messages {
            height: 400px;
            overflow-y: auto;
            padding: 20px;
            background: #f8f9fa;
        }
        
        .message {
            margin-bottom: 15px;
            padding: 10px 15px;
            border-radius: 20px;
            max-width: 70%;
        }
        
        .message.own {
            background: #667eea;
            color: white;
            margin-left: auto;
            text-align: right;
        }
        
        .message.other {
            background: white;
            border: 1px solid #dee2e6;
        }
        
        .message.event {
            background: #fff3cd;
            text-align: center;
            margin: 10px auto;
            font-style: italic;
            max-width: 100%;
        }
    </style>
</head>
<body>

<!-- Username Page -->
<div id="username-page">
    <div class="username-form" style="background: white; padding: 40px; border-radius: 10px;">
        <h2 class="mb-4">🚀 Spring Boot Chat</h2>
        <form id="usernameForm">
            <input type="text" id="username" class="form-control mb-3" placeholder="Dein Name" required>
            <button type="submit" class="btn btn-primary w-100">Chat beitreten</button>
        </form>
    </div>
</div>

<!-- Chat Page -->
<div id="chat-page" class="chat-container">
    <div class="chat-header">
        <h4>💬 Spring Boot Live Chat</h4>
        <small id="connected-user"></small>
    </div>
    
    <div id="chat-messages" class="chat-messages"></div>
    
    <div class="p-3">
        <form id="messageForm">
            <div class="input-group">
                <input type="text" id="message" class="form-control" placeholder="Nachricht...">
                <button type="submit" class="btn btn-primary">Senden</button>
            </div>
        </form>
    </div>
</div>

<script th:src="@{/webjars/sockjs-client/1.5.1/sockjs.min.js}"></script>
<script th:src="@{/webjars/stomp-websocket/2.3.4/stomp.min.js}"></script>

<script>
    let stompClient = null;
    let currentUser = null;
    
    const usernamePage = document.querySelector('#username-page');
    const chatPage = document.querySelector('#chat-page');
    const usernameForm = document.querySelector('#usernameForm');
    const messageForm = document.querySelector('#messageForm');
    const messageInput = document.querySelector('#message');
    const chatMessages = document.querySelector('#chat-messages');
    
    usernameForm.addEventListener('submit', function(e) {
        e.preventDefault();
        currentUser = document.querySelector('#username').value.trim();
        
        if (currentUser) {
            usernamePage.style.display = 'none';
            chatPage.style.display = 'block';
            connect();
        }
    });
    
    function connect() {
        const socket = new SockJS('/ws');
        stompClient = Stomp.over(socket);
        
        stompClient.connect({}, onConnected, onError);
    }
    
    function onConnected() {
        stompClient.subscribe('/topic/public', onMessageReceived);
        
        stompClient.send("/app/chat.join", {},
            JSON.stringify({sender: currentUser, type: 'JOIN'})
        );
    }
    
    function onError(error) {
        console.error('WebSocket Error:', error);
    }
    
    messageForm.addEventListener('submit', function(e) {
        e.preventDefault();
        const content = messageInput.value.trim();
        
        if (content && stompClient) {
            stompClient.send("/app/chat.send", {},
                JSON.stringify({sender: currentUser, content: content, type: 'CHAT'})
            );
            messageInput.value = '';
        }
    });
    
    function onMessageReceived(payload) {
        const message = JSON.parse(payload.body);
        const messageElement = document.createElement('div');
        
        if (message.type === 'JOIN' || message.type === 'LEAVE') {
            messageElement.classList.add('message', 'event');
            messageElement.textContent = message.content;
        } else {
            messageElement.classList.add('message');
            messageElement.classList.add(message.sender === currentUser ? 'own' : 'other');
            messageElement.textContent = message.sender + ': ' + message.content;
        }
        
        chatMessages.appendChild(messageElement);
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }
</script>

</body>
</html>

5.2 Controller für View

@Controller
public class ChatViewController {
    
    @GetMapping("/chat")
    public String chatPage() {
        return "chat";
    }
}

5.3 Testen!

# App starten
mvn spring-boot:run

# Browser 1: http://localhost:8080/chat
Username: Alice
Nachricht: "Hallo Bob!"

# Browser 2: http://localhost:8080/chat
Username: Bob
→ Sieht: "Alice ist dem Chat beigetreten!"
→ Sieht: "Alice: Hallo Bob!"

Real-Time Chat funktioniert! ✅


Schritt 6: Person-Notifications (1.5 Stunden)

6.1 PersonService erweitern

@Service
public class PersonService {
    
    private final SimpMessagingTemplate messagingTemplate;
    
    public PersonService(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }
    
    public Person createPerson(Person person) {
        person.setId(idCounter.getAndIncrement());
        persons.add(person);
        
        // WebSocket Notification senden!
        PersonNotification notification = new PersonNotification(
            "Neue Person: " + person.getFirstname(),
            person,
            NotificationType.PERSON_CREATED
        );
        
        messagingTemplate.convertAndSend("/topic/persons", notification);
        
        return person;
    }
}

ALLE Browser die /topic/persons abonniert haben bekommen sofort die Notification! ✅


✅ Checkpoint Professional

Kontrolliere:

  • [ ] ChatController mit @MessageMapping funktioniert
  • [ ] WebSocketEventListener implementiert
  • [ ] Chat-Frontend mit JavaScript erstellt
  • [ ] SockJS und STOMP.js eingebunden
  • [ ] Live-Chat zwischen zwei Browsern funktioniert
  • [ ] PersonService sendet Notifications
  • [ ] Du verstehst Broadcasting

Alles ✅? Weiter zu 🔵 Enterprise Features!


🔵 BONUS: ENTERPRISE FEATURES (Schritte 7-8)

Schritt 7: Point-to-Point Messages (1 Stunde)

7.1 Private Nachrichten

@Controller
public class PrivateMessageController {
    
    private final SimpMessagingTemplate messagingTemplate;
    
    public PrivateMessageController(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }
    
    @MessageMapping("/chat.private")
    public void sendPrivateMessage(@Payload ChatMessage message) {
        // Nachricht an spezifischen User senden
        messagingTemplate.convertAndSendToUser(
            message.getRecipient(),  // Username
            "/queue/private",        // Destination
            message                  // Payload
        );
    }
}

Was passiert:

  • User „Alice“ sendet private Message an „Bob“
  • NUR Bob empfängt die Nachricht
  • Andere User sehen nichts

Schritt 8: WebSocket Security & Best Practices (1 Stunde)

8.1 Security Configuration

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
            .simpDestMatchers("/app/**").authenticated()
            .simpSubscribeDestMatchers("/topic/**", "/queue/**").authenticated()
            .anyMessage().denyAll();
    }
}

8.2 Reconnect-Logik

let reconnectAttempts = 0;
const maxAttempts = 5;

function connect() {
    const socket = new SockJS('/ws');
    stompClient = Stomp.over(socket);
    
    stompClient.connect({}, onConnected, function(error) {
        if (reconnectAttempts < maxAttempts) {
            reconnectAttempts++;
            const delay = Math.min(1000 * Math.pow(2, reconnectAttempts - 1), 30000);
            setTimeout(() => connect(), delay);
        }
    });
}

✅ Checkpoint Enterprise Features

Kontrolliere:

  • [ ] Point-to-Point Messages funktionieren
  • [ ] WebSocket Security konfiguriert
  • [ ] Reconnect-Logik implementiert
  • [ ] Du verstehst /topic vs /queue
  • [ ] Du kannst Production-Ready WebSockets bauen

Alles ✅? Du bist jetzt ein WebSocket-Profi! 🎉

Hier sind noch einige empfehlenswerte externe Links zum Thema „WebSockets mit Spring Boot / Spring Framework”, die du gut zur Vertiefung verwenden kannst!

  • Offizielle Spring-Guide „Using WebSocket to build an interactive web application“ – zeigt Schritt für Schritt, wie man mit STOMP über WebSocket in Spring eine interaktive Anwendung realisiert. Home
  • Offizielle Dokumentation „WebSockets :: Spring Framework“ – tiefgehende Beschreibung der WebSocket-Unterstützung im Spring Framework inklusive SOCKJS, STOMP und Protokollwechsel. Home
  • Baeldung-Tutorial „Intro to WebSockets with Spring“ – eines der gut strukturierten Tutorials mit Praxisbeispielen und dem typischen Chat-Use-Case. Baeldung on Kotlin
  • Spring Boot eigene Dokumentation „WebSockets :: Spring Boot“ – zeigt, wie Spring Boot WebSockets automatisch unterstützt und wie die Konfiguration aussieht. Home
  • Blogbeitrag „WebSocket + Spring Boot: Build a Real-time, Bidirectional Applications“ – verbindet praktische Umsetzung mit Performance-Hinweisen und Real-Time-Szenarien. Medium

🔥 Elyndras Real Talk:

Nova kam heute zu mir, völlig begeistert: „Elyndra! Ich hab gerade verstanden warum WebSockets so cool sind! Ich muss nicht mehr alle 5 Sekunden den Server fragen ob es was Neues gibt!“

Ich lächelte: „Genau. Das ist der Unterschied zwischen ‚Are we there yet?‘ alle 30 Sekunden fragen und dass der Server einfach sagt ‚We’re here!‘ wenn es soweit ist.“

Die AutoTech Real-Time Dashboard Story

Das war 2020, während meines dritten Jahres bei AutoTech. Wir hatten ein Production-Monitoring Dashboard für unsere Autofabrik.

Das Problem: Polling-Hölle

50 gleichzeitig offene Dashboards
× 1 Request alle 5 Sekunden
× 60 Sekunden × 60 Minuten
= 1,080,000 Requests pro Stunde
= NUR fürs Dashboard! 💥

Die Datenbank war am Limit.

Code Sentinel kam zu mir: „Wir brauchen Real-Time Updates OHNE Polling. Kannst du WebSockets implementieren?“

Die WebSocket-Lösung:

1 Database-Query pro Sekunde
× 1 WebSocket-Broadcast
= 3,600 Queries pro Stunde
(statt 1,080,000!)

CPU-Last: -95%
Database-Load: -99%
Update-Latency: 1 Sekunde (statt 5)
✅ Production-Ready!

Nova war beeindruckt: „Das ist ja 300x weniger Last!“

„Exakt,“ sagte ich. „Das ist der Unterschied zwischen ‚Fragen‘ und ‚Informiert werden‘. WebSockets sind wie Push-Notifications für den Browser.“


🆘 Troubleshooting

Problem 1: WebSocket-Verbindung schlägt fehl

Lösung:

// ✅ Richtig - mit SockJS
const socket = new SockJS('/ws');

Problem 2: Nachrichten kommen nicht an

Lösung:

// Subscribe nicht vergessen!
stompClient.subscribe('/topic/public', function(message) {
    console.log(message);
});

❓ FAQ

Q: Wann WebSockets, wann REST?
A: REST für Request/Response (Formular absenden). WebSockets für Real-Time (Chat, Live-Updates).

Q: Was ist STOMP?
A: Ein Messaging-Protocol über WebSocket. Strukturiert Nachrichten mit Destinations.

Q: Was macht SockJS?
A: Fallback wenn Browser kein WebSocket unterstützt.

Q: Unterschied /topic/ vs /queue/*?*
A: /topic/* = Broadcasting (alle), /queue/* = Point-to-Point (einer).


📅 Nächster Kurstag: Tag 9

Morgen: JAX-RS in Spring Boot – REST mit Java Standards!

👉 Zum Blogbeitrag Tag 9


📚 Deine Fortschritts-Übersicht

TagStatus
✅ 1-7ABGESCHLOSSEN! 🎉
✅ 8ABGESCHLOSSEN! 🎉
→ 9Als nächstes

Du hast 80% geschafft! 💪


📥 Download & Ressourcen

Projekt: SpringBootWebSockets-v1.0.zip

Enthält:

  • Live-Chat Application
  • Person-Notifications
  • WebSocket Security
  • Alle Templates

Du kannst jetzt:

  • ✅ WebSockets verstehen
  • ✅ STOMP nutzen
  • ✅ Live-Chat bauen
  • ✅ Real-Time Updates
  • ✅ Broadcasting
  • ✅ Point-to-Point Messages
  • ✅ Production-Ready WebSockets! 🚀

Keep coding, keep learning! 💙


Tags: #SpringBoot #WebSockets #RealTime #STOMP #LiveChat #Tag8

Autor

  • Elyndra Valen

    28 Jahre alt, wurde kürzlich zur Senior Entwicklerin befördert nach 4 Jahren intensiver Java-Entwicklung. Elyndra kennt die wichtigsten Frameworks und Patterns, beginnt aber gerade erst, die tieferen Zusammenhänge und Architektur-Entscheidungen zu verstehen. Sie ist die Brücke zwischen Junior- und Senior-Welt im Team.