Spring Boot로 WebSocket과 STOMP 기반 실시간 통신
Spring Boot와 STOMP를 사용한 WebSocket 실시간 통신의 핵심 개념, 서버 설정과 클라이언트 예제 코드 중심 설명 자료
목차
개요
WebSocket은 양방향 통신을 제공해 실시간 기능 구현에 적합하다. STOMP는 메시지 전송 규약으로, Spring과 조합하면 메시지 브로커 형태의 구조를 쉽게 구성할 수 있다. 이 글에서는 Spring Boot 환경에서 WebSocket과 STOMP를 이용해 기본 실시간 채팅 흐름을 이해하고 구현 예제를 통해 핵심 설정을 다룬다.
필수 개념
WebSocket
WebSocket은 클라이언트와 서버 간에 지속적인 연결을 유지해 양방향으로 데이터 교환이 가능하다. HTTP의 요청/응답 모델과 달리 낮은 지연으로 실시간성이 중요할 때 유리하다.
STOMP(Simple Text Oriented Messaging Protocol)
STOMP는 텍스트 기반의 메시지 프로토콜로서, 주고받는 메시지에 목적지(destination)와 구독(subscription) 개념을 더해 브로커를 통한 라우팅을 쉽게 한다. Spring은 이를 추상화해서 @MessageMapping, @SendTo 등을 제공한다.
프로젝트 준비
기본적으로 Spring Boot, spring-websocket, spring-messaging, spring-boot-starter-web 의존성이 필요하다. Maven 또는 Gradle로 설정한다.
예제 의존성 (Maven)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
WebSocket 설정
WebSocket 설정은 WebSocketMessageBrokerConfigurer를 구현해서 엔드포인트와 메시지 브로커를 정의한다.
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
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();
}
}
메시지 핸들러
컨트롤러는 @MessageMapping으로 클라이언트에서 보낸 메시지를 받고, @SendTo로 목적지로 전송한다. 단순 채팅 예제를 통해 흐름을 확인한다.
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/chat.send")
@SendTo("/topic/messages")
public ChatMessage send(ChatMessage message) {
return message;
}
}
public class ChatMessage {
private String from;
private String text;
// getters, setters
}
클라이언트 예제
브라우저에서는 SockJS와 stomp.js를 사용해 연결한다. 연결 후에는 구독을 통해 서버에서 발행하는 메시지를 받는다.
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
<script>
var socket = new SockJS('/ws');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function() {
stompClient.subscribe('/topic/messages', function(msg) {
console.log('받은 메시지:', msg.body);
});
stompClient.send('/app/chat.send', {}, JSON.stringify({from:'user1', text:'안녕하세요'}));
});
</script>
테스트와 고려사항
- 브로커는 간단한 테스트용 SimpleBroker와 외부 브로커(RabbitMQ, ActiveMQ)로 확장 가능하다.
- 보안: 인증과 권한 부여는 Stomp의 CONNECT 헤더를 통해 토큰 기반 인증으로 처리하는 방식이 일반적이다.
- 스케일링: 클러스터 환경에서는 외부 메시지 브로커를 사용해 세션을 공유해야 한다.
마무리
이 글은 spring boot websocket 예제 중심으로 STOMP 개념과 구현 흐름을 정리했다. stomp spring boot 실시간 통신의 핵심은 엔드포인트 정의, 목적지 설계, 그리고 클라이언트 구독 구조이다. 실제 채팅이나 알림 시스템을 구축할 때는 보안과 브로커 선택, 확장성을 함께 고려하면 효과적인 실시간 서비스 설계가 가능하다.