채팅 토이 프로젝트를 진행하면서 공부했던 STOMP 관련 내용 정리 - dnwls16071/Backend_Summary GitHub Wiki
📚 WebSocketMessageBrokerConfigurer
Spring Framework에서 STOMP(Simple Text Oriented Messaging Protocol) 기반의 WebSocket 메시징을 설정하기 위한 인터페이스
주요 역할 정리
STOMP 메시징 활성화 : WebSocketMessageBrokerConfigurer를 구현한 설정 클래스에 @EnableWebSocketMessageBroker 어노테이션을 추가하여 WebSocket을 통한 STOMP 메시지 처리를 활성화한다.
엔드포인트 등록 : 클라이언트가 웹소켓 연결을 시작할 수 있는 STOMP 엔드포인트를 등록한다.
메시지 브로커 구성 : 클라이언트의 SUBSCRIBE 요청을 처리하고 메시지를 전달하는 메시지 브로커를 설정한다.
애플리케이션 대상 경로 설정 : 클라이언트가 서버로 메시지를 보낼 때 사용하는 목적지(destination) 접두사를 설정한다.
토이 프로젝트 시 작성했던 코드 정리
@Slf4j@Configuration@EnableWebSocket@EnableWebSocketMessageBroker@RequiredArgsConstructorpublicclassStompWebSocketConfigimplementsWebSocketMessageBrokerConfigurer {
privatefinalStompHandlerstompHandler;
@OverridepublicvoidregisterStompEndpoints(StompEndpointRegistryregistry) {
// Register STOMP endpoints mapping each to a specific URL and (optionally) enabling and configuring SockJS fallback options.registry.addEndpoint("/connect")
.setAllowedOrigins("http://localhost:3000")
.withSockJS();
}
@OverridepublicvoidconfigureMessageBroker(MessageBrokerRegistryregistry) {
// Configure message broker options.// @MessageMapping이 있는 컨트롤러 메서드// 클라이언트 → 서버(애플리케이션)로 메시지를 보낼 때 사용되는 목적지 접두사를 설정합니다.registry.setApplicationDestinationPrefixes("/publish");
// 메모리 기반의 내장 메시지 브로커// 서버 → 클라이언트(브로드캐스트)로 메시지를 보낼 때 사용되는 목적지 접두사를 설정합니다.registry.enableSimpleBroker("/topic");
}
@OverridepublicvoidconfigureClientInboundChannel(ChannelRegistrationregistration) {
// 클라이언트 메시지가 실제 핸들러에 도달하기 전에 메시지를 가로채고 처리// 클라이언트가 보낸 메시지에 대한 인증, 권한 부여, 로깅 등을 처리log.info("Interceptor - OK...");
registration.interceptors(stompHandler);
}
}
📚 ChannelInterceptor
Spring Framework의 메시징 모듈에서 메시지가 MessageChannel을 통해 전송되거나 수신될 때 이를 가로채서 처리하는 역할을 하는 인터페이스
웹소켓(WebSocket)과 STOMP(Simple Text Oriented Messaging Protocol) 기반 애플리케이션에서 주로 사용되며, 메시지 전송 및 수신 과정에 공통적인 로직을 적용하는 필터와 유사한 역할을 수행한다.
주요 역할 정리
메시지 가로채기 : 클라이언트가 서버로 보내는 STOMP 메시지(CONNECT, SEND, SUBSCRIBE 등)나 서버가 클라이언트로 보내는 메시지를 가로챈다. 이를 통해 메시지가 처리되기 전후로 다양한 작업을 수행할 수 있다.
인증 및 권한 부여 : 웹소켓 연결 시 JWT(JSON Web Token)와 같은 인증 정보를 메시지 헤더에서 추출하여 인증 및 권한 확인 로직을 구현할 수 있다. 예를 들어, preSend() 메서드를 오버라이드하여 메시지 전송 전에 사용자의 유효성을 검사할 수 있다.
로깅 및 모니터링 : 메시지 채널을 통과하는 모든 메시지를 로깅하여 디버깅이나 모니터링에 활용할 수 있다.
토이 프로젝트 시 작성했던 코드 정리
@Component@RequiredArgsConstructorpublicclassStompHandlerimplementsChannelInterceptor {
privatefinalJwtDecoderjwtDecoder;
@OverridepublicMessage<?> preSend(Message<?> message, MessageChannelchannel) {
// 메시지가 실제로 전송되기 전에 호출되는 사전 처리 단계를 의미finalStompHeaderAccessoraccessor = StompHeaderAccessor.wrap(message);
System.out.println("StompHandler.preSend() called - Command: " + accessor.getCommand());
if (StompCommand.CONNECT == accessor.getCommand()) {
finalStringbearerToken = accessor.getFirstNativeHeader("Authorization");
if (bearerToken == null) {
System.out.println("No Authorization header found!");
thrownewIllegalArgumentException("Authorization header is missing");
}
finalStringtoken = bearerToken.substring(7);
try {
jwtDecoder.decode(token);
} catch (Exceptione) {
thrownewIllegalArgumentException("Invalid JWT token");
}
}
returnChannelInterceptor.super.preSend(message, channel);
}
}
📚 ChatController
관련 어노테이션/메서드/클래스
@MessageMapping : 웹소켓에서 클라이언트가 서버로 메시지를 보내는 경로를 지정한다. 해당 경로로 메시지를 보내면 이 메서드가 해당 메시지를 받아서 처리한다. 다시 말해 클라이언트가 메시지를 발행하는 통로 역할을 한다.
SimpMessagingTemplate : 서버에서 클라이언트로 메시지를 전송할 때 사용하는 핵심 컴포넌트. 서버가 메시지 브로커에게 메시지를 전달하는 역할을 수행한다.
@DestinationVariable : STOMP 메시지의 도착지(destination) 헤더에서 변수 값을 추출하여 roomId 매개변수에 바인딩한다. 이를 통해 서버는 클라이언트가 보낸 메시지가 어느 채팅방에 대한 것인지를 식별할 수 있게 된다.
클라이언트에서 지정 경로로 메시지를 발행하면 서버와 직접 통신하는 것이 아니라 broker에 의해서 채널에 메시지가 전달된다.
이 때, 특정 채널을 구독하고 있는 클라이언트에게 실시간으로 메시지가 전달된다.
SimpleBroker란, 메모리 기반 브로커로서 경로에 따라 메시지를 분배하고 클라이언트에게 메시지를 전달하는 역할을 수행한다. 내장 브로커일 경우 Spring에서 제공하는 메모리 기반 브로커를 사용하게 되고 외장 브로커일 경우 대표적으로 Kafka와 Redis가 쓰일 수 있다.