[HEY-TOSS-ME] 채팅 기능 - 2

허진혁·2023년 3월 13일
0

구현코드와 코드에 대한 설명은 각각 아래와 같다.

RabbitConfig.java

@Configuration
@EnableRabbit
public class RabbitConfig {

    private static final String CHAT_QUEUE_NAME = "chat.queue"; // 바인딩 할 Queue 이름
    private static final String CHAT_EXCHANGE_NAME = "chat.exchange"; // 바인딩 할 Exchange 이름
    private static final String ROUTING_KEY = "room.*"; // 라우팅키 설정 (큐와 라우팅 키의 역할은 아래에서 설명하도록 한다)

	// 큐 주입
    @Bean
    public Queue queue() {
        return new Queue(CHAT_QUEUE_NAME, false);
    }
	
    // 익스체인지 주입
    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(CHAT_EXCHANGE_NAME);
    }
    
    // 바인딩 설정
    @Bean
    public Binding binding(Queue queue, TopicExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
    }

	// RabitTemplete 설정
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(jsonMessageConverter()); // JSON을 String으로 변환
        rabbitTemplate.setRoutingKey(CHAT_QUEUE_NAME);

        return rabbitTemplate;
    }

    private Jackson2JsonMessageConverter jsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}

Exchage와 Queue의 Binding

Exchange는 메세지를 전달 받아 정해진 바인딩 규칙에 따라 특정 Queue에 메세지를 전달하는 역할을 수행한다.
그래서 위 코드에서는 routing key(회원이 들어있는 채팅방 고유 번호가 될 것이다)에 따라 회원이 요청한 메세지를 알맞은 queue에 전달하게 된다.

RabbitTemplete

RabbitTemplete은 메세지를 전달하기위한 객체이다. 하지만 RabbitMq의 메세지 컨버터는 기본적으로 String을 받도록 설정되어있다.
그래서 위 코드와 같이 RabbitTemplete의 기본 Converter를 변경해줌으로 String이 아닌 객체를 받을 수 있도록 하였다.

WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {

        registry.addEndpoint("/ws") // 클라이언트에서 ws://localhost:8080/ws로 요청 보낼시 STOMP 생성
                .setAllowedOriginPatterns("*") //"*" 설정을 위해서는 setAllowedOrgin이 아닌 setAllowedOriginPatterns로 설정해주어야 한다
                .withSockJS(); //WebSocket을 지원하지 않는 브라우저에 대해 채팅 기능이 잘 작동할 수 있도록하는 설정이다
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setPathMatcher(new AntPathMatcher(".")); 
        //url 경로 형식을 바꾸는 설정이다. 찾아보니 'Stomp에서는 이런 패턴을 {보통} 사용한다' 라고하는데 그 보통의 이유가 도대체 무엇인지 아직 알아내지 못했다.
		//ex) chat/room/3 -> chat.room.3 
        registry.setApplicationDestinationPrefixes("/pub"); // 매세지를 발행할 때 기본 경로이다.

        registry.enableStompBrokerRelay("/queue", "/topic", "/exchange", "/amq/queue"); // 어떤 채팅방에 입장할 것인지 구독할 때 Url의 prefix이며 각 방식마다 동작 방식이 다르다.
    }
}

rabbitmq github에 올라온 구독 형식 자료를 아래에 첨부한다

= "/exchange/"  X "/" RK  Consume from temp queue bound to X with routing key RK
| "/topic/"     RK        Consume from temp queue bound to amq.topic with routing key RK
| "/amq/queue/" Q         Consume from Q
| "/queue/"     Q         Consume from Q
| Q (no leading slash)    Consume from Q

ChatMessageController

@Controller
@RequiredArgsConstructor
@Slf4j
public class ChatMessageController {

    private static final String CHAT_EXCHANGE_NAME = "chat.exchange";
    private final ChatService chatService;
    private final RabbitTemplate template;

    public void getMessageList(Long roomId, @RequestHeader("Authorization") String token) {
		// RDBS에 저장된 메세지를 불러오기, 추후 적용 후 수정
        return;
    }

    @MessageMapping("chat.message.{chatRoomId}") // /pub/cart.message.1 의 주소로 메세지를 보내면 1번 방을 구독한 유저에게 메세지가 전달된다.
    public void sendMessage(@Payload MessageDto request,
            @DestinationVariable String chatRoomId) {
        log.info("message = {}", request.toString());
        chatService.sendMessage(request); //RDBS에 메세지를 저장하는 함수
        template.convertAndSend(CHAT_EXCHANGE_NAME, "room." + chatRoomId, request);
    }
}

다음 글은 채팅 기능에 대해 APIC이라는 chrome 외부 툴을 통해 Test 한 방법과 그 결과에 대해서 올리려고 한다.

회고

추가적으로 생각해 봐야 할 것은 우리가 실생활에서 사용되고 있는 채팅 앱처럼 읽지 않은 채팅방의 채팅 갯수를 표현 할 수 있도록 소켓을 통해 구현해 주려고 한다.
해당 기능이 완성되면 해당 글을 수정하여 올릴 계획이다.

출처
about rabbitTemplte : https://minholee93.tistory.com/entry/RabbitMQ-Jackson2JsonMessageConvertor

rabbitmq github : https://github.com/rabbitmq/rabbitmq-amqp1.0#routing-and-addressing

profile
멈추지 않는 개발자입니다.

0개의 댓글