Spring Web Socket - STOMP (Simple Text Oriented Message Protocol)

목차

참고

STOMP (Simple/Stream Text Oriented Message Protocol)

WebSocket 기반 프로토콜이며 Client 와 Server 가 negotiate 하기 위한 sub-protocol 이 정의 돼 있다.

STOMP 은 메세징 전송을 효율적으로 하기 위해 탄생한 Text 지향 프로토콜 이며 Message Payload에는 Text or Binary 데이터를 포함 해 전송할 수 있다. 또한 sub-protocol 이 정의 돼 있어 Client 에서 서버로 전송할 메시지 유형, 형식, 내용등이 정의 돼 있다.

  • pub/sub 구조로 되어있어 메세지를 전송하고 메세지를 받아 처리하는 부분이 확실히 정해져 있기 때문에 개발자 입장에서 명확하게 인지하고 개발할 수 있는 이점이 있다.
  • 또한 STOMP를 이용하면 메세지의 헤더에 값을 줄 수 있어 헤더 값을 기반으로 통신 시 인증 처리(ChannelInterceptor) 를 구현하는 것도 가능하며 STOMP 스펙에 정의한 규칙만 잘 지키면 여러 언어 및 플랫폼 간 메세지를 상호 운영할 수 있다.
  • 만약 Spring에서 지원하는 STOMP를 사용하면 Spring WebSocket 어플리케이션은 STOMP Broker로 동작하게 된다.

STOMP (Simple Text Oriented Message Protocol) 구성

  • SimpAnnotationMethod
    • Client 로 부터 전달 받은 Message 를 처리한다.
  • clientInboundChannel
    • WebSocket client 로부터 전달 받은 메시지를 전송해준다.
  • clientOutboundChannel
    • Server 메시지를 WebSocket Client 에 전송해준다.
  • brokerChannel
    • Server 내부에서 사용하는 Channel, Message Broker 에 메시지를 전송해준다.

Simple Broker 를 이용한 구성

Simple Broker 는 In Memory 형태로 메시지를 저장하고 Client 로 Message 를 전달하는 Message Broker

Simple Broker 를 사용한 구성

외부 Broker 를 이용한 구성

외부 Message Broker 를 사용하는 경우 Broker Relay 를 이용해 외부 Broker 와 Client 에 메시지를 전달 한다.

외부 Broker 를 사용한 구성

의존성 설정하기

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-devtools'

STOMP 사용을 위한 Config

STOMP 를 사용하기 위해 @EnableWebSocketMessageBroker 를 선언하고 WebSocketMessageBrokerConfigurer 를 구현한다.

  • StompEndpointRegistry
    • WebSocket 연결을 위한 End Point 를 설정한다.
    • 설정된 End Point 를 이용해 Web Socket 통신(Connection) 을 위한 Hand Shaking 이 이뤄진다.
  • MessageBrokerRegistry
    • setApplicationDestinationPrefixes 메서드를 이용해 메시지 요청 에 대한 Prefix 를 설정한다.
      • /pub Prefix 로 시작한 요청은 @Controller 클래스 내 @MessageMapping 메서드로 라우팅 된다.
    • enableSimpleBroker 는 Simple Message Broker 를 활성화 하고 메시지 구독 을 위한 Prefix 를 설정한다.
      • /sub Prefix 로 시작한 메시지를 Broker 로 라우팅 한다.
    • 외부 Broker 를 사용할 경우 enableStompBrokerRelay 메서드를 이용해 STOMP broker relay 를 활성화 시켜준다.
WebSockConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSockConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-stomp")
.setAllowedOrigins("*")
.withSockJS();
}

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
// config.enableStompBrokerRelay("/sub"); // 외부 Broker 를 사용하는 경우
config.setApplicationDestinationPrefixes("/pub");
}
}

메시지 처리를 위한 Message Handler - MessageMapping

@MessageMapping 을 이용한 메시지 처리는 기본적으로 경로 기반 메시지 라우팅 방식에서 메시지 처리를 위해 서용한다.

@MessageMapping 를 이용해 Message 를 처리 한 후 값을 반환하게 되면 MessageConverter 에 의해 직렬화 되고 brokerChannel 로 전송 된 후에 Channel 을 구독하는 Client 들에게 전송(Broad Cast) 된다. 이 때, Out Bound 대상은 In Bound 로 들어온 메시지 처음 접두사만 바뀐고 나머지 경로는 동일하다.

  • 기본적으로 Ant 스타일 의 경로 패턴을 지원한다.
  • /foo/{id} 와 같이 Path Variable 을 사용하면 @DestinationVariable 를 이용해 값을 가져올 수 있다.
  • /pub/chat/message 경로로 들어오는 요청에 대해 Message 를 발행하고 /sub/chat/message/ 경로로 구독하고 있는 subscriber 들에게 응답값을 전달한다.
  • @SendTo, @SendToUser 를 이용해 메시지를 전달하는 경로를 직접 설정할 수 있다
  • @MessageMapping 메서드를 이용해 값을 반환하는 대신 SimpMessagingTemplate 를 이용해 brokerChannel 로 메시지를 보낼 수 있다.
ChatController.java
@RequiredArgsConstructor
@Controller
public class ChatController {

private final SimpMessageSendingOperations messagingTemplate;

@MessageMapping("/chat/message")
public void message(ChatMessage message) {
if (ChatMessage.MessageType.ENTER.equals(message.getType())) {
message.setMessage(message.getSender() + "님이 입장하셨습니다.");
}

messagingTemplate.convertAndSend("/sub/chat/room/" + message.getRoomId(), message);
}
}

CORS 문제

When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.setApplicationDestinationPrefixes("/pub");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-stomp")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
Share