Post

πŸ’Ž Websocket - STOMP μ±„νŒ… μ„œλ²„ ꡬ좕

πŸ’Ž Websocket - STOMP μ±„νŒ… μ„œλ²„ ꡬ좕

Websocket - STOMP λ„μž… κ·Όκ±°

  • μ±„νŒ… μ„œλΉ„μŠ€λ₯Ό μœ„ν•΄ Websocket μ—°κ²° 및 λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•΄μ„œ MongoDB에 데이터λ₯Ό 등둝해보렀고 ν•œλ‹€.
  • μ±„νŒ…μ€ μ–‘λ°©ν–₯ ν†΅μ‹ μ΄λ―€λ‘œ SSEλŠ” λΆˆκ°€ν•˜κ³ , νš¨μœ¨μ„±μ„ μœ„ν•΄ Polling 방식 λ˜ν•œ λ°°μ œλ˜μ–΄ Websocket을 λ„μž…ν•˜κ²Œ λ˜μ—ˆλ‹€.

μž‘μ„± μ½”λ“œ

βœ… μ„€μ • 파일

1
2
3
4
5
6
7
8
9
10
/**
 * μ—”λ“œν¬μΈνŠΈ μ„€μ •
 * @param registry
 */
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
	registry.addEndpoint("/ws")
		.setAllowedOriginPatterns("*");
		.withSockJS();
}

βœ… Controller

1
2
3
4
@MessageMapping("/chat.sendSystemMessage")
public void enterUser(Message message) {
	service.sendSystemMessage(message);
}

βœ… Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void sendSystemMessage(Message message) {
	MessageType type = message.getType();
	Long roomId = message.getRoomId();
	
	Message systemMessage = Message.builder()
		.type(type)
		.content(
			String.format(
				type.name().equals("ENTER") ? "[%s] %s λ‹˜μ΄ μž…μž₯ν–ˆμŠ΅λ‹ˆλ‹€." : "[%s] %s λ‹˜μ΄ 퇴μž₯ν–ˆμŠ΅λ‹ˆλ‹€.",
				LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
				message.getSenderName()
			)
		)
		.senderId(message.getSenderId())
		.roomId(roomId)
		.sendAt(LocalDateTime.now())
		.build();
		
	repository.save(systemMessage);
	template.convertAndSend("/topic/room_" + roomId, systemMessage);
}
  • ν΄λΌμ΄μ–ΈνŠΈκ°€ λ©”μ‹œμ§€λ₯Ό μš”μ²­ν•  경우 DB에 ν•΄λ‹Ή λ©”μ‹œμ§€λ₯Ό μ €μž₯ν•˜κ³ , ν•΄λ‹Ή μ‚¬μš©μžκ°€ κ΅¬λ…ν•œ Topic에 λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•œλ‹€.
  • SimpleMessagingTemplate은 κ°„λ‹¨ν•˜κ²Œ Topic에 λ©”μ‹œμ§€λ₯Ό 전달할 수 μžˆλŠ” λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.

ν…ŒμŠ€νŠΈ

Websocket Debug Tool

  • Postmanμ—μ„œλŠ” STOMP μ„œλΈŒ ν”„λ‘œν† μ½œμ„ μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μœ„ 링크λ₯Ό ν™œμš©ν•΄μ•Ό ν•œλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
2025-04-05T15:14:04.404+09:00 
DEBUG 23688 --- [nboundChannel-4] o.s.m.s.b.SimpleBrokerMessageHandlerΒ Β Β Β  
: Processing MESSAGE 
destination=/topic/room_2 
session=null 
payload={
	"senderId":1,
	"roomId":1,
	"senderName":null,
	"type":"ENTER",
	"send...(truncated)"
}
  • μ•žμ„œ μ²¨λΆ€ν•œ λ§ν¬μ—μ„œλŠ” CONNECT, SUBSCRIBE, SEND λ“± μš”μ²­ ν”„λ ˆμž„μ„ μž‘μ„±ν•  ν•„μš” 없이 κ°„λ‹¨ν•˜κ²Œ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.
  • μ‹€μ œ λͺ©μ μ§€μ— μ œλŒ€λ‘œ Broadcast λ˜λŠ”μ§€λŠ” Frontend μ˜μ—­μ„ κ΅¬ν˜„ν•΄μ•Ό μ•Œ 수 μžˆκΈ°λŠ” ν•˜μ§€λ§Œ Backend μ˜μ—­ Logging을 ν™•μΈν•˜λŠ” μ„ μ—μ„œ ν…ŒμŠ€νŠΈλ₯Ό λ§ˆμ³€λ‹€.Β 
  • Session이 null κ°’μœΌλ‘œ Logging되고 μžˆλŠ”λ°, 이건 SimpMessagingTemplateλ₯Ό μ‚¬μš©ν•  경우 Session 정보λ₯Ό ν¬ν•¨ν•˜μ§€ μ•Šκ³  λ©”μ‹œμ§€λ₯Ό 브둜컀둜 보내기 λ•Œλ¬Έμ΄λ‹€.
  • SockJSλ₯Ό μ‚¬μš©ν•  경우 ν”„λ‘œν† μ½œμ— wsκ°€ μ•„λ‹Œ httpλ₯Ό κΈ°μž¬ν•΄μ•Ό ν•œλ‹€.
This post is licensed under CC BY 4.0 by the author.