https://github.com/Seungkyu-Han/Toge-do-backend
GitHub - Seungkyu-Han/Toge-do-backend: Toge-do 앱의 백엔드 리포지토리입니다
Toge-do 앱의 백엔드 리포지토리입니다. Contribute to Seungkyu-Han/Toge-do-backend development by creating an account on GitHub.
github.com
이제 Stomp를 사용한 채팅 서버의 구현이다.
기존에 개발했던 채팅은 Websocket을 사용해서 소켓을 연결시켜두고, 거기에 Flux로 데이터를 전송해주었던 걸로 기억난다.
클라이언트로부터 데이터를 받을 수 있는 SSE 느낌으로 말이다.
이번에는 Stomp 라이브러리를 사용해 제대로 채팅을 구현해보려 한다.
Stomp는 우선 socket에 연결하고, subscribe하는 주소에 구독해 메시지를 받고 publish하는 주소로 메시지를 보낸다고 한다.
그래서 다른 방법으로는 테스트가 어렵고 저번에 작성했던 글의 방법으로 테스트해야 한다.
https://jiangxy.github.io/websocket-debug-tool/
WebSocket Debug Tool
jiangxy.github.io
해당 사이트로 설명을 해보자면
저렇게 url에 소켓을 연결하고 stomp subscribe에 서버에서 설정한 subscribe destination을 구독하면 해당 채팅방에서 생성된 메시지들이 실시간으로 전달된다.
사실 그냥 destication을 구독하는게 아니라 endpoint가 /subscribe면 뒤에 /subscribe/{chatGroupId} 이런 식으로 뒤에 채팅방의 정보가 있어야 한다.
마찬가지로 send destination을 통해 메시지를 보내며 이 때도 /publish/{chatGroupId}와 같이 채팅방의 정보가 추가되어야 한다.
헤더를 추가할 수도 있으며, 이거는 그냥 연결해두고 Rest API를 호출한다고 생각하면 편할것이다.
그럼 일단 Stomp를 사용하기 위해 추가해야 하는 라이브러리이다.
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation ("org.springframework.boot:spring-boot-starter-websocket")
이렇게 websocket과 webflux만 추가해주면 된다고 한다.
나는 기존에 webflux를 사용하고 있어 websocket만 추가해주었다.
이제 stomp의 config다
@Configuration
@EnableWebSocketMessageBroker
class ChatConfig: WebSocketMessageBrokerConfigurer {
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/websocket/v1/chat")
.setAllowedOriginPatterns("*")
.withSockJS()
registry.addEndpoint("/websocket/v1/chat")
.setAllowedOriginPatterns("*")
}
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
registry.enableSimpleBroker("/sub")
registry.setApplicationDestinationPrefixes("/pub")
}
}
우선 이런 식으로 작성하고 하나씩 설명해보자면
registerStompEndpoints는 웹소켓의 endpoint를 설정한다.
registry.addEndpoint에 해당 웹소켓의 end point를 설정해준다.
만약 사용하는 서버가 localhost:8080이라면 end point는 ws://localhost:8080/websocket/v1/chat이 될 것 이다.
setAllowedOriginPatterns에는 해당 웹소켓에 접속 가능한 주소를 적는 것이다.
클라우드 서버에서 사용하기 때문에 "*"로 지정해주었다.
withSockJs는 자바스크립트 라이브러리 관련된 것이라고 하는데, 나는 일단 몰라서 모두 등록해두었다.
configureMessageBroker는 위에서 보았던 subscribe, publish로 사용할 destination을 등록해주면 된다.
이제 message controller를 작성해보자.
@RestController안에 @MessageMapping을 적어주면 된다.
@MessageMapping("/{groupId}")
fun publishChatMessage(
@Parameter(hidden = true) @Header(HttpHeaders.AUTHORIZATION) accessToken: String,
@DestinationVariable groupId: String,
@RequestBody messageReqDto: MessageReqDto
): Mono<ResponseEntity<Void>> {
return chatService.publishMessage(
groupId = groupId,
userId = getUserIdFromToken(accessToken),
message = messageReqDto.message
).then(Mono.fromCallable { ResponseEntity(HttpStatus.OK) })
}
이렇게 원하는 Header를 가져올 수도 있고, dto를 정의해서 원하는 json 형식으로 값을 가져올 수 있다.
@DestinationVariable로 groupId를 가져왔으며, 해당 정보는 MongoDB에 그대로 저장한다.
이제 서버에서 클라이언트로 메시지를 보내는 방법이다.
simpMessageSendingOperations.convertAndSend(
"/sub/${chatDocument.groupId}", messageDocumentToDto(chatDocument)
그냥 간단하게 SimpMessageSendingOperations에 convertAndSend로 구독하고 있는 채팅방으로 메시지 dto를 전송하면 된다.
해당 이벤트를 가져오는 방법은 전 포스팅에서 MongoDB changeStream 부분을 찾아보면 된다.
테스트 결과도 전 포스팅의 사진으로 대체하도록 하겠다.
Stomp로 처음 채팅방을 만들어 보았는데, 채팅방 관리가 굉장히 쉬웠다.
WebSocket만 사용해서 구현하는 거보다 난이도가 더 쉬운 것 같다.
'토이 프로젝트' 카테고리의 다른 글
Hexagonal Architecture 적용하기 (1) | 2025.01.22 |
---|---|
직렬화 과정에서 함수 조건 검사 (0) | 2025.01.13 |
MSA에서 Kafka없이 MongoDB만으로 채팅서버 구현하기 (1) | 2025.01.03 |
WebFlux SwitchIfEmpty가 항상 시작되는 에러 (2) | 2024.12.23 |
MSA Gateway에 CircuitBreaker 적용 (0) | 2024.12.16 |