WebSocket 기반의 STOMP 메시징에서는 사용자 구분 및 특정 사용자에게 메시지를 전송하는 기능이 필요할 수 있습니다.

WebSocket에선 사용자가 WebSocket에 연결될 때 Principal 객체를 사용하여 구분할 수 있고, 특정 사용자의 세션 ID를 가져와서 메시지를 개별적으로 보낼 수 있습니다.

필요 라이브러리

// build.gradle
...
dependencies {  
    ...
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
}
...

구현

1. HandshakeHandler 구현 후 WebSocketMessageBrokerConfigurer에 등록

DefaultHandshakeHandler 페이지 참고

2. Controller 구현

SimpMessagingTemplate의 convertAndSendToUser()를 사용하면 특정 사용자의 브로커에 메시지를 전달할 수 있습니다.

@Controller
@RequiredArgsConstructor
public class PrivateChatController {
 
	private final SimpleMessagingTemplate messagingTemplate;
 
    @MessageMapping("/chat.whisper")
    public void sendPrivateMessage(UUID userId, ChatMessage chatMessage) {
        messagingTemplate.convertAndSendToUser(userId, "/queue/private", chatMessage);
    }
    
}

클라이언트에서 사용

1. WebSocket 연결

const socket = new SockJS('http://localhost:8083/ws');
const stompClient = Stomp.over(socket);

2. 연결 및 구독

위에서 설정한 대로 특정 사용자용 브랜치의 prefix인 /user와 귓속말이 전달될 경로인 /queue/private를 합쳐 /user/queue/private를 구독해야 합니다.

그러면 연결이 시작되고 handshake가 진행될 때 HandShakeHandler에서 지정한 대로 각 사용자별 고유 Principal이 생기고, 이를 통해 생긴 각 사용자별 /user/{userId}/queue/private를 구독하는 과정입니다.

stompClient.connect(headers, function(frame) {
 
	// 공용 메시지 구독
	const subscription = stompClient.subscribe('/topic/public', function(message) {
		displayChatMessage(message)
	});
	
	// 본인 개인에게 보내는 메시지 구독
	const userSubscription = stompClient.subscribe('/user/queue/private', function(message) {
		displayChatMessage(message)
	});
 
});

3. 특정 사용자에게 데이터 보내기

document.getElementById('whisper-form').addEventListener('submit', (e) => {
 
	e.preventDefault();
 
	const userId = document.getElementById('whisper-user-id').value;
	const input = document.getElementById('whisper-input');
	const message = input.value;
	const chatMessage = {
		type: 'WHISPER',
		roomId: roomId,
		sender: username,
		content: message
	};
	
	// 귀속말을 절달하는 경로에서 필요로한 데이터인 메시지를 받을 사용자의 id, 메시지 내용을 인자값으로 넣어 메시지를 전달할 수 있다
	stompClient.send("/app/chat.whisper", {}, JSON.stringify({userId: userId, chatMessage: chatMessage}));
});