Files
spring-boot-examples/docs/webflux/11_웹플럭스와 웹소켓.md
2025-04-08 19:56:24 +09:00

6.7 KiB

아래는 **"스프링부트 웹플럭스 시리즈"**의 **11장: 웹플럭스와 웹소켓"**에 대한 초안입니다. 10장의 마이크로서비스 기반을 활용하여 웹소켓을 통해 실시간 통신을 구현하며, 간단한 채팅 애플리케이션 예제를 포함했습니다. 코드도 간략히 유지하며 초보자가 따라 하기 쉽게 자연스러운 문체로 작성했습니다.


11. 웹플럭스와 웹소켓

10장에서 마이크로서비스를 구축하며 웹플럭스의 비동기 특성을 실감했습니다. 이번 장에서는 한 단계 더 나아가 웹소켓(WebSocket)을 활용해 실시간 통신을 구현해보겠습니다. 웹플럭스와 웹소켓은 실시간 데이터 전송에 최적화된 조합으로, 채팅 같은 기능을 쉽게 만들 수 있습니다. 간단한 예제를 통해 실습해보죠. 준비되셨나요?

실시간 통신을 위한 웹소켓 구현

웹소켓은 클라이언트와 서버 간 양방향 통신을 가능하게 하는 프로토콜입니다. HTTP와 달리 연결을 유지하며, 데이터를 주고받는 데 지연이 적습니다. 웹플럭스는 이를 기본 지원하니, 추가 의존성 없이 바로 시작할 수 있습니다.

10장의 User Service를 확장해 웹소켓 기반 채팅 기능을 추가해보겠습니다. 먼저, 웹소켓 핸들러를 만듭니다.

웹소켓 핸들러 작성

src/main/java/com/example/demoChatWebSocketHandler 클래스를 추가합니다:

package com.example.demo;

import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;

public class ChatWebSocketHandler implements WebSocketHandler {

    private final Flux<String> messageFlux;

    public ChatWebSocketHandler() {
        // 간단한 메시지 스트림 예제
        this.messageFlux = Flux.interval(Duration.ofSeconds(1))
                .map(i -> "Message " + i);
    }

    @Override
    public Mono<Void> handle(WebSocketSession session) {
        // 클라이언트로부터 메시지 수신
        Flux<String> input = session.receive()
                .map(message -> "Echo: " + message.getPayloadAsText());

        // 클라이언트로 메시지 전송
        return session.send(messageFlux.mergeWith(input)
                .map(session::textMessage));
    }
}
  • messageFlux: 서버에서 주기적으로 보내는 메시지 스트림 (예시용).
  • handle: 클라이언트 메시지를 받아 에코로 반환하고, 서버 메시지도 함께 전송.

웹소켓 라우팅 설정

src/main/java/com/example/demoWebSocketConfig를 추가합니다:

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class WebSocketConfig {

    @Bean
    public HandlerMapping webSocketMapping() {
        Map<String, WebSocketHandler> map = new HashMap<>();
        map.put("/chat", new ChatWebSocketHandler());

        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setUrlMap(map);
        mapping.setOrder(-1); // 다른 매핑보다 우선
        return mapping;
    }
}
  • /chat 경로로 웹소켓 연결을 처리.

웹플럭스와 웹소켓의 조합 예제

User Service (port: 8081)에 위 코드를 추가한 뒤 실행합니다. 이제 클라이언트에서 웹소켓 연결을 테스트할 수 있습니다.

클라이언트 테스트

간단한 HTML/JS 클라이언트를 만들어 보죠. src/main/resources/staticindex.html을 추가합니다:

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Chat</title>
</head>
<body>
    <input id="message" type="text">
    <button onclick="sendMessage()">Send</button>
    <div id="messages"></div>

    <script>
        const socket = new WebSocket("ws://localhost:8081/chat");
        const messagesDiv = document.getElementById("messages");

        socket.onmessage = function(event) {
            const msg = document.createElement("p");
            msg.textContent = event.data;
            messagesDiv.appendChild(msg);
        };

        function sendMessage() {
            const input = document.getElementById("message");
            socket.send(input.value);
            input.value = "";
        }
    </script>
</body>
</html>

http://localhost:8081/index.html에 접속하면:

  1. 서버에서 1초마다 "Message 0", "Message 1" 등이 표시.
  2. 입력창에 메시지를 입력하고 Send 버튼을 누르면 "Echo: [입력값]" 반환.

활용 사례 (채팅 애플리케이션 등)

위 예제는 기본적인 에코 서버지만, 이를 확장하면 실시간 채팅 애플리케이션을 만들 수 있습니다:

  • 다중 사용자 지원: Flux를 공유 가능한 스트림으로 만들어 모든 클라이언트에 브로드캐스트.
    private final Sinks.Many<String> messageSink = Sinks.many().multicast().onBackpressureBuffer();
    private final Flux<String> messageFlux = messageSink.asFlux();
    
    @Override
    public Mono<Void> handle(WebSocketSession session) {
        Flux<String> input = session.receive()
                .map(message -> session.getId() + ": " + message.getPayloadAsText())
                .doOnNext(messageSink::tryEmitNext);
    
        return session.send(messageFlux.map(session::textMessage));
    }
    
  • 상태 관리: Redis나 데이터베이스로 채팅 기록 저장.
  • 인증: 스프링 시큐리티로 웹소켓 연결에 토큰 기반 인증 추가.

채팅 외에도 주식 시세 업데이트, 실시간 알림 등 다양한 활용이 가능합니다.

테스트해보기

  1. User Service 실행.
  2. 브라우저에서 http://localhost:8081/index.html 열기.
  3. 메시지 입력 후 Send 버튼 클릭 → 서버 메시지와 에코 확인.

마무리

웹플럭스와 웹소켓으로 실시간 통신의 세계에 입문했습니다. 비동기 스트림과 양방향 연결이 얼마나 강력한지 느끼셨나요? 다음 장에서는 웹플럭스의 현재와 미래를 돌아보며, 이 기술의 여정을 마무리하겠습니다. 이번 실습으로 실시간 애플리케이션의 가능성을 열어보셨길 바랍니다!


이 장은 웹소켓의 기본 구현과 채팅 예제를 중심으로 구성했으며, 실습과 활용 사례를 간략히 다뤘습니다. 추가 기능이나 수정이 필요하면 말씀해주세요!