From c9dcfeb95a60179d79f979fadfa9a248b809e4dd Mon Sep 17 00:00:00 2001
From: Hoai Viet Nguyen <viet.nguyen@th-koeln.de>
Date: Wed, 9 Apr 2025 11:48:56 +0200
Subject: [PATCH] add echo and simple chat

---
 build.gradle                                  |  1 +
 .../websocketsdemo/configs/WebSocketConfig.kt | 17 ++++++++++
 .../controllers/WelcomeController.kt          | 17 ++++++++++
 .../gm/websocketsdemo/handlers/EchoHandler.kt | 11 +++++++
 .../handlers/SimpleChatHandler.kt             | 26 +++++++++++++++
 src/main/resources/static/echoclient.html     | 32 +++++++++++++++++++
 src/main/resources/templates/index.ftlh       |  9 ++++++
 src/main/resources/templates/layout.ftlh      | 27 ++++++++++++++++
 src/main/resources/templates/simpleChat.ftlh  | 24 ++++++++++++++
 9 files changed, 164 insertions(+)
 create mode 100644 src/main/kotlin/de/thk/gm/websocketsdemo/configs/WebSocketConfig.kt
 create mode 100644 src/main/kotlin/de/thk/gm/websocketsdemo/controllers/WelcomeController.kt
 create mode 100644 src/main/kotlin/de/thk/gm/websocketsdemo/handlers/EchoHandler.kt
 create mode 100644 src/main/kotlin/de/thk/gm/websocketsdemo/handlers/SimpleChatHandler.kt
 create mode 100644 src/main/resources/static/echoclient.html
 create mode 100644 src/main/resources/templates/index.ftlh
 create mode 100644 src/main/resources/templates/layout.ftlh
 create mode 100644 src/main/resources/templates/simpleChat.ftlh

diff --git a/build.gradle b/build.gradle
index faa97d4..efa4a43 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,6 +26,7 @@ dependencies {
     implementation 'org.jetbrains.kotlin:kotlin-reflect'
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
     testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5'
+    developmentOnly 'org.springframework.boot:spring-boot-devtools'
     testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
 }
 
diff --git a/src/main/kotlin/de/thk/gm/websocketsdemo/configs/WebSocketConfig.kt b/src/main/kotlin/de/thk/gm/websocketsdemo/configs/WebSocketConfig.kt
new file mode 100644
index 0000000..71ef4b1
--- /dev/null
+++ b/src/main/kotlin/de/thk/gm/websocketsdemo/configs/WebSocketConfig.kt
@@ -0,0 +1,17 @@
+package de.thk.gm.websocketsdemo.configs
+
+import de.thk.gm.websocketsdemo.handlers.EchoHandler
+import de.thk.gm.websocketsdemo.handlers.SimpleChatHandler
+import org.springframework.context.annotation.Configuration
+import org.springframework.web.socket.config.annotation.EnableWebSocket
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
+
+@Configuration
+@EnableWebSocket
+class WebSocketConfig () : WebSocketConfigurer {
+    override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) {
+        registry.addHandler(EchoHandler(),"/echo")
+        registry.addHandler(SimpleChatHandler(),"/chat")
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/thk/gm/websocketsdemo/controllers/WelcomeController.kt b/src/main/kotlin/de/thk/gm/websocketsdemo/controllers/WelcomeController.kt
new file mode 100644
index 0000000..eedc6ec
--- /dev/null
+++ b/src/main/kotlin/de/thk/gm/websocketsdemo/controllers/WelcomeController.kt
@@ -0,0 +1,17 @@
+package de.thk.gm.websocketsdemo.controllers
+
+import org.springframework.stereotype.Controller
+import org.springframework.web.bind.annotation.GetMapping
+
+@Controller
+class WelcomeController {
+    @GetMapping("/")
+    fun index(): String {
+        return "index"
+    }
+
+    @GetMapping("/simplechat")
+    fun simpleChat(): String {
+        return "simpleChat"
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/EchoHandler.kt b/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/EchoHandler.kt
new file mode 100644
index 0000000..a93ce45
--- /dev/null
+++ b/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/EchoHandler.kt
@@ -0,0 +1,11 @@
+package de.thk.gm.websocketsdemo.handlers
+
+import org.springframework.web.socket.TextMessage
+import org.springframework.web.socket.WebSocketSession
+import org.springframework.web.socket.handler.TextWebSocketHandler
+
+class EchoHandler : TextWebSocketHandler() {
+    override fun handleTextMessage(session: WebSocketSession, message: TextMessage) {
+        session.sendMessage(message)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/SimpleChatHandler.kt b/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/SimpleChatHandler.kt
new file mode 100644
index 0000000..7bc632e
--- /dev/null
+++ b/src/main/kotlin/de/thk/gm/websocketsdemo/handlers/SimpleChatHandler.kt
@@ -0,0 +1,26 @@
+package de.thk.gm.websocketsdemo.handlers
+
+import org.springframework.web.socket.*
+import org.springframework.web.socket.handler.TextWebSocketHandler
+
+class SimpleChatHandler(): TextWebSocketHandler() {
+    private var sessions : ArrayList<WebSocketSession> = ArrayList()
+    override fun afterConnectionEstablished(session: WebSocketSession) {
+        sessions.add(session)
+    }
+
+    override fun handleTextMessage(session: WebSocketSession, message: TextMessage) {
+        for (session in sessions) {
+            session.sendMessage(message)
+        }
+    }
+
+    override fun afterConnectionClosed(session: WebSocketSession, status: CloseStatus) {
+        for (chatSession in sessions) {
+            if (chatSession.id == session.id) {
+                sessions.remove(chatSession)
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/static/echoclient.html b/src/main/resources/static/echoclient.html
new file mode 100644
index 0000000..d1b7cb0
--- /dev/null
+++ b/src/main/resources/static/echoclient.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Echo Demo</title>
+</head>
+<body>
+<h1>Echo Demo</h1>
+<input type="text" id="message">
+<button type="button" onclick="sendMessage()">Send</button>
+<div id="echo"></div>
+<a href="/">Back</a>
+<script>
+    var ws = new WebSocket("/echo")
+
+    ws.onopen = function (event) {
+        alert("WebSocket successfully established")
+    }
+
+    function sendMessage(){
+        var message = document.getElementById("message").value
+        ws.send(message)
+    }
+
+    ws.onmessage = function (message) {
+        echo.innerHTML += "<p>" + message.data + "</p>"
+    }
+
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/index.ftlh b/src/main/resources/templates/index.ftlh
new file mode 100644
index 0000000..eb82bb2
--- /dev/null
+++ b/src/main/resources/templates/index.ftlh
@@ -0,0 +1,9 @@
+<#import "layout.ftlh" as base>
+<#import "/spring.ftl" as spring />
+<@base.layout>
+    <ul>
+        <li><a href="/echoclient.html">Echo Client</a></li>
+        <li><a href="/simplechat">Simple Chat</a></li>
+        <li><a href="/chatrooms">Chat rooms</a></li>
+    </ul>
+</@base.layout>
diff --git a/src/main/resources/templates/layout.ftlh b/src/main/resources/templates/layout.ftlh
new file mode 100644
index 0000000..ff32195
--- /dev/null
+++ b/src/main/resources/templates/layout.ftlh
@@ -0,0 +1,27 @@
+<#macro layout>
+    <!doctype html>
+    <html lang="en">
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport"
+              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>WebSocket Demos</title>
+    </head>
+    <body>
+    <header>
+        <h1>WebSocket Demos</h1>
+    </header>
+    <hr>
+    <main>
+        <#nested>
+    </main>
+    <hr>
+    <footer>
+        <a href="/#">Imprint</a>
+        <a href="/#">About Us</a>
+        <a href="/#">Privacy</a>
+    </footer>
+    </body>
+    </html>
+</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/simpleChat.ftlh b/src/main/resources/templates/simpleChat.ftlh
new file mode 100644
index 0000000..75d821a
--- /dev/null
+++ b/src/main/resources/templates/simpleChat.ftlh
@@ -0,0 +1,24 @@
+<#import "layout.ftlh" as base>
+<@base.layout>
+    <h1>Simple Chat</h1>
+    <div id="chat">
+    </div>
+    <input type="text" id="sender" placeholder="Max Mustermann"><br>
+    <input type="text" id="text" placeholder="Message...">
+    <button type="button" onclick="sendMessage()">Send</button>
+    <script>
+        var ws = new WebSocket("/chat")
+        var chat = document.getElementById("chat")
+        ws.onmessage = function (message) {
+            var chatMessage = JSON.parse(message.data)
+            chat.innerHTML += "<p><b>" +chatMessage.sender+ "</b>:" + chatMessage.text + "</p>"
+        }
+        function sendMessage(){
+            var text = document.getElementById("text").value
+            var sender = document.getElementById("sender").value
+            var chatMessage = {"sender": sender, "text":text}
+            ws.send(JSON.stringify(chatMessage))
+        }
+
+    </script>
+</@base.layout>
\ No newline at end of file
-- 
GitLab