{"id":9487,"date":"2024-10-13T18:12:43","date_gmt":"2024-10-13T09:12:43","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=9487"},"modified":"2024-10-13T18:12:43","modified_gmt":"2024-10-13T09:12:43","slug":"websocket-with-spring-boot","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=9487","title":{"rendered":"WebSocket with Spring Boot"},"content":{"rendered":"<h1>WebSocket with Spring Boot<\/h1>\n<p>Spring Boot \uc5d0\uc11c WebSocket \uc11c\ubc84\ub97c \uad6c\uc131\ud558\ub294 \ubc29\ubc95\uc744 \uc124\uba85\ud569\ub2c8\ub2e4.<\/p>\n<h2>\uc758\uc874\uc131 \ucd94\uac00<\/h2>\n<pre><code class=\"language-groovy\">dependencies {\n    implementation &#039;org.springframework.boot:spring-boot-starter-web&#039;\n    implementation &quot;org.springframework.boot:spring-boot-starter-thymeleaf&quot;\n    implementation &#039;org.springframework.boot:spring-boot-starter-websocket&#039;\n}<\/code><\/pre>\n<h2>WebSocketHandler<\/h2>\n<pre><code class=\"language-java\">@Slf4j\n@Component\npublic class WebSocketHandler extends TextWebSocketHandler {\n\n    private static final ConcurrentHashMap&lt;String, WebSocketSession&gt; CLIENTS = new ConcurrentHashMap&lt;&gt;();\n\n    @Override\n    public void afterConnectionEstablished(WebSocketSession session) {\n        System.out.println(&quot;Connected : &quot; + session.getId());\n        CLIENTS.put(session.getId(), session);\n    }\n\n    @Override\n    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {\n        System.out.println(&quot;Disconnected : &quot; + session.getId());\n        System.out.println(&quot;Disconnect status code : &quot; + status.getCode());\n        CLIENTS.remove(session.getId());\n    }\n\n    @Override\n    protected void handleTextMessage(WebSocketSession session, TextMessage message) {\n        System.out.println(&quot;Sender : &quot; + session.getId());\n        System.out.println(&quot;Received message : &quot; + message.getPayload());\n        CLIENTS.forEach((key, value) -&gt; {\n            try {\n                value.sendMessage(message);\n            } catch (IOException e) {\n                log.error(&quot;Exception: {}&quot;, e.getMessage());\n            }\n        });\n    }\n}<\/code><\/pre>\n<h2>WebSocketConfig<\/h2>\n<pre><code class=\"language-java\">@Configuration\n@EnableWebSocket\n@RequiredArgsConstructor\npublic class WebSocketConfig implements WebSocketConfigurer {\n\n    private final WebSocketHandler webSocketHandler;\n\n    @Override\n    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {\n        registry.addHandler(webSocketHandler, &quot;\/ws&quot;).setAllowedOrigins(&quot;*&quot;);\n    }\n}<\/code><\/pre>\n<h2>\ud074\ub77c\uc774\uc5b8\ud2b8<\/h2>\n<p>\ud074\ub77c\uc774\uc5b8\ud2b8\ub294 JavaScript \ub85c \uc0dd\uc131\ud569\ub2c8\ub2e4.<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html lang=&quot;ko&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;UTF-8&quot;&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\n    &lt;title&gt;\uc6f9\uc18c\ucf13&lt;\/title&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;h1&gt;\uc6f9\uc18c\ucf13 \ud14c\uc2a4\ud2b8&lt;\/h1&gt;\n\n&lt;button id=&quot;btn_send&quot;&gt;\uba54\uc2dc\uc9c0 \uc804\uc1a1&lt;\/button&gt;\n&lt;button id=&quot;btn_close&quot;&gt;\uc5f0\uacb0 \ub04a\uae30&lt;\/button&gt;\n&lt;\/body&gt;\n&lt;script&gt;\n    \/\/ ====================================================\n    \/\/ connect\n    const webSocket = new WebSocket(&quot;ws:\/\/localhost:8080\/ws&quot;);\n\n    \/\/ ====================================================\n    \/\/ on open\n    webSocket.onopen = () =&gt; {\n        console.log(&quot;\uc6f9\uc18c\ucf13\uc11c\ubc84\uc640 \uc5f0\uacb0 \uc131\uacf5&quot;);\n    };\n\n    \/\/ ====================================================\n    \/\/ receive message\n    webSocket.onmessage = function (event) {\n        console.log(`\uc11c\ubc84 \uc6f9\uc18c\ucf13\uc5d0\uac8c \ubc1b\uc740 \ub370\uc774\ud130: ${event.data}`);\n    }\n\n    \/\/ ====================================================\n    \/\/ on close\n    webSocket.onclose = function() {\n        console.log(&quot;\uc11c\ubc84 \uc6f9\uc18c\ucf13 \uc5f0\uacb0 \uc885\ub8cc&quot;);\n    }\n\n    \/\/ ====================================================\n    \/\/ on error\n    webSocket.onerror = function(event) {\n        console.log(event)\n    }\n\n    let count = 1;\n    document.getElementById(&quot;btn_send&quot;).onclick = function() {\n        if(webSocket.readyState === webSocket.OPEN) {\n            \/\/ ============================================\n            \/\/ send\n            webSocket.send(`\uc99d\uac00\ud558\ub294 \uc22b\uc790\ub97c \ubcf4\ub0c5\ub2c8\ub2e4 =&gt; ${count}`);\n            count++;\n        }else{\n            alert(&quot;\uc5f0\uacb0\ub41c \uc6f9\uc18c\ucf13 \uc11c\ubc84\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.&quot;);\n        }\n    }\n\n    document.getElementById(&quot;btn_close&quot;).onclick = function() {\n        if(webSocket.readyState === webSocket.OPEN) {\n            \/\/ ============================================\n            \/\/ close\n            webSocket.close();\n        }else{\n            alert(&quot;\uc5f0\uacb0\ub41c \uc6f9\uc18c\ucf13 \uc11c\ubc84\uac00 \uc5c6\uc2b5\ub2c8\ub2e4.&quot;);\n        }\n    }\n&lt;\/script&gt;\n&lt;\/html&gt;<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>WebSocket with Spring Boot Spring Boot \uc5d0\uc11c WebSocket \uc11c\ubc84\ub97c \uad6c\uc131\ud558\ub294 \ubc29\ubc95\uc744 \uc124\uba85\ud569\ub2c8\ub2e4. \uc758\uc874\uc131 \ucd94\uac00 dependencies { implementation &#039;org.springframework.boot:spring-boot-starter-web&#039; implementation &quot;org.springframework.boot:spring-boot-starter-thymeleaf&quot; implementation &#039;org.springframework.boot:spring-boot-starter-websocket&#039; } WebSocketHandler @Slf4j @Component public class WebSocketHandler extends TextWebSocketHandler { private static final ConcurrentHashMap&lt;String, WebSocketSession&gt; CLIENTS = new ConcurrentHashMap&lt;&gt;(); @Override public void afterConnectionEstablished(WebSocketSession session) { System.out.println(&quot;Connected : &quot; + session.getId()); CLIENTS.put(session.getId(), session); }\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=9487\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-9487","post","type-post","status-publish","format-standard","hentry","category-spring-boot"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/9487","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9487"}],"version-history":[{"count":1,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/9487\/revisions"}],"predecessor-version":[{"id":9488,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/9487\/revisions\/9488"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9487"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9487"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9487"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}