STOMP 는 Simple Text Oriented Messaging Protocol 의 약자로 메시지 전송을 위한 프로토콜입니다. 기본적인 Websocket 과 가장 크게 다른 점은 기존의 Websocket 만을 사용한 통신은 발신자와 수신자를 Spring 단에서 직접 관리를 해야만 했습니다.
그러나 STOMP 는 다릅니다. stomp 는 pub/sub 기반으로 동작하기 때문에 메시지의 송신, 수신에 대한 처리를 명확하게 정의 할 수 있습니다. 즉 추가적으로 코드 작업할 필요 없이 @MessagingMapping 같은 어노테이션을 사용해서 메시지 발행 시 엔드포인트만 조정해줌으로써 훨씬 쉽게 메시지 전송/수신이 가능합니다.
->메시지 브로커를 활용하여 pub/sub 방식으로 클라이언트와 서버가 쉽게 메시지를 주고 받을 수 있습니다.
STOMP를 사용하기 위해서는 여러가지 설정이 필요합니다.
// websocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'
// STOMP
implementation group: 'org.webjars', name: 'stomp-websocket', version: '2.3.3-1'
@EnableWebSocketMessageBroker
@Configuration
@RequiredArgsConstructor
public class StompWebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp/chat") // 여기로 웹소켓 생성
.setAllowedOriginPatterns("*")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 메시지를 발행하는 요청 url -> 메시지를 보낼 때
registry.setApplicationDestinationPrefixes("/pub"); // 구독자 -> 서버(메세지보낼때)
// 메시지를 구독하는 요청 url -> 메시지를 받을 때
registry.enableSimpleBroker("/sub"); // 브로커 -> 구독자들(메세지받을때)
}
}
@EnableWebSocketMessageBroker :
메시지 브로커가 지원하는 ‘WebSocket 메시지 처리’를 활성화합니다.registerStompEndpoints()
: 기존의 WebSocket 설정과 마찬가지로 HandShake와 통신을 담당할 EndPoint를 지정한다. 클라이언트에서 서버로 WebSocket 연결을 하고 싶을 때, /stomp/chat
으로 요청을 보내도록 하였습니다.setAllowedOriginPatterns
: cors 설정configureMessageBroker()
: 메모리 기반의 Simple Message Broker를 활성화한다. 메시지 브로커는 /sub
으로 시작하는 주소의 Subscriber들에게 메시지를 전달하는 역할을 한다. 이때, 클라이언트가 서버로 메시지 보낼 때 붙여야 하는 prefix를 /pub
로 지정하였습니다.
setApplicationDestinationPrefixes
:
SEND
요청을 처리한다./pub
가 붙어있으면 Broker로 보내진다.enableSimpleBroker
:
/sub
가 api에 prefix로 붙은 경우, messageBroker가 해당 경로를 가로채 처리한다./sub
)로 SimpleBroker
를 등록한다. SimpleBroker
는 해당하는 경로를 구독하는 client에게 메시지를 전달하는 간단한 작업을 수행한다.@Controller
@RequiredArgsConstructor
@RequestMapping("/api")
public class ChatController {
private final SimpMessagingTemplate template; //특정 Broker 로 메세지를 전달
private final ChatService chatService;
// stompConfig 에서 설정한 applicationDestinationPrefixes 와 @MessageMapping 경로가 병합됨 (/pub + ...)
// /pub/chat/enter 에 메세지가 오면 동작
@MessageMapping(value = "/chat/enter")
public void enter(ChatRequestDto message){ // 채팅방 입장
message.setMessage(message.getWriter() + "님이 채팅방에 참여하였습니다.");
template.convertAndSend("/sub/chat/" + message.getRoomId(), message);
}
// /pub/chat/message 에 메세지가 오면 동작
@MessageMapping(value = "/chat/message")
public void message(ChatRequestDto message){
ChatResponseDto savedMessage = chatService.saveMessage(message);
template.convertAndSend("/sub/chat/" + savedMessage.getRoomId(), savedMessage);
}
@Controller
에서는 /pub
desination prefix를 제외한 경로 /chat/message
를 @MessageMapping
하면 됩니다./chat/message
: Config에서 setApplicationDestinationPrefixes()를 통해 prefix를 /pub
으로 설정 해주었기 때문에 경로가 한번 더 수정되어 /pub/chat/message
로 바뀝니다.convertAndSend
: /sub
을 Config에서 설정해주었습니다. 그래서 Message Broker가 해당 send를 캐치하고 해당 토픽을 구독하는 모든 사람에게 메세지를 보내게 됩니다./sub/chat/2
을 구독하고 있는 유저들에게 모두 보냅니다.postman은 웹소켓과 Socket.io는 지원하지만 STOMP 테스트를 지원하지 않아 apic 이라는 별도의 프로그램을 사용하여 로컬 환경에서 웹소켓 테스트를 할 수 있었습니다.
훌륭한 글 감사드립니다.