240304 TIL - 2차 프로젝트(고도화 | 웹소켓 설정, 채팅방 생성)

jkeum·2024년 3월 4일
0

TECHIT-BackendSchool

목록 보기
47/50
post-thumbnail

웹소켓 설정

백엔드

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic");
		config.setApplicationDestinationPrefixes("/app");
	}

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:3000").withSockJS();
	}
}
@MessageMapping("/chat.sendMessage")
public void sendMessage(final @DestinationVariable String roomId, final Message message) {
		messagingTemplate.convertAndSend("/topic/messages", message);
}

프론트엔드

'use client'

import { useEffect, useState, useRef } from 'react';
import { Stomp } from '@stomp/stompjs';
import SockJS from 'sockjs-client';

export default function Chat({ roomId }) {
	const [stompClient, setStompClient] = useState(null);
	const [message, setMessage] = useState('');
	const [messages, setMessages] = useState([]);
	const messagesEndRef = useRef(null);

	useEffect(() => {
		const socket = new SockJS(`${process.env.NEXT_PUBLIC_BASE_URL}/chat`);
		const client = Stomp.over(socket);
		client.connect({}, (frame) => {
			console.log('Connected: ' + frame);
			client.subscribe('/topic/messages', (message) => {
				console.log('Received: ' + message.body);
				setMessages((prevMessages) => [...prevMessages, JSON.parse(message.body)]);
			});
		});
		setStompClient(client);
	}, []);

	const sendMessage = () => {
		if (stompClient && stompClient.connected) {
			const chatMessage = {
				content: message,
				type: 'CHAT',
			};
			stompClient.send('/app/chat.sendMessage', {}, JSON.stringify(chatMessage));
			setMessages((prevMessages) => [...prevMessages, chatMessage]);
			setMessage('');
		}
	};
...
}
  • 메시지 전송 과정
    • 유저가 메시지를 입력하고 전송 버튼을 누르면,
    • sendMessage 함수가 호출되고 stompClient.send 메서드를 사용해서 메시지를 서버로 전송한다.
      메시지는 JSON 형식으로 변환되고, /app/chat.sendMessage 경로로 전송된다.
      이는 클라이언트가 서버의 @MessageMapping("/chat.sendMessage")에 매핑된 메서드를 호출하고자 하는 것이다.
    • 백엔드에서 ChatControllersendMessage 메서드가 호출되고, 전송받은 메시지(Message 객체)를 /topic/messages로 다시 전송하기 위해 SimpMessagingTemplateconvertAndSend 메서드를 사용한다.
  • 메시지 수신 과정
    • 클라이언트는 초기화 할 때 /topic/messages를 구독하도록 설정되어 있다.
      이는 client.subscribe("/topic/messages", ...) 호출을 통해 이루어진다.
    • 백엔드에서 메시지가 /topic/messages로 전송될 때, 이 토픽을 구독하고 있는 모든 클라이언트에게 메시지가 전달된다.(메시지를 전송한 클라이언트도 포함됨)
    • 클라이언트에서는 client.subscribe에서 설정한 콜백 함수가 호출되고, message.body를 통해 전송받은 메시지 내용을 확인할 수 있다.
      이 메시지는 setMessages를 사용해서 클라이언트의 메시지 목록에 추가된다.

채팅방 생성

	return (
		<div className="flex flex-col h-[80vh] max-w-2xl mx-auto border border-gray-300 mt-32">
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {messages.map((msg, idx) => (
          <div key={idx} className="break-words p-2 rounded-lg bg-blue-100 max-w-xs ml-auto">
            {msg.content}
          </div>
        ))}
        <div ref={messagesEndRef} />
      </div>
      <div className="p-4 border-t border-gray-200 flex items-center">
        <input
          type="text"
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          className="w-full p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
          placeholder="텍스트를 입력하세요..."
        />
        <button
          onClick={sendMessage}
          className="ml-4 px-5 py-2 bg-blue-500 text-white rounded-lg float-right focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 hover:bg-blue-600"
        >
          Send
        </button>
      </div>
    </div>
	);
profile
It's me, jkeum!

0개의 댓글