Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

지석이의 일기

React + SpringBoot 를 사용해서 채팅을 구현해보자. WebSocket, Stomp 본문

Java

React + SpringBoot 를 사용해서 채팅을 구현해보자. WebSocket, Stomp

91년도에 철산에서 태어난 최지석 2024. 3. 21. 00:20

이번에 세미 프로젝트용으로 채팅을 구현하기로 했다.

서버는 Spring boot , 프론트는 React 로 구성했다.

채팅 기술스택은 websocket 을 사용하려고 한다.

 

WebSocket의 기본 원리
WebSocket 프로토콜은 ws (또는 보안 연결을 위한 wss) 스키마를 사용하여 작동. 클라이언트(보통 웹 브라우저)는 WebSocket 객체를 생성하여 서버에 연결을 시도한다. 이 연결 과정은 HTTP 프로토콜을 사용하여 시작되며, Upgrade 헤더를 통해 WebSocket 연결로 전환.

연결 과정
핸드셰이크 요청: 클라이언트는 서버로 HTTP 요청.

이 요청에는 Upgrade: websocket과 Connection: Upgrade 헤더가 포함되어 WebSocket 연결로의 전환을 요청.
핸드셰이크 응답: 서버가 이 요청을 수락하면, 101 Switching Protocols 상태 코드와 함께 응답합니다. 이로써 클라이언트와 서버 간의 연결이 WebSocket 프로토콜로 업그레이드.
데이터 교환: 핸드셰이크가 성공적으로 완료되면, 클라이언트와 서버는 이 연결을 통해 실시간으로 데이터를 교환할 수 있음.

 

1.서버 구성

build.gradle 파일에 WebSocket 관련 의존성을 추가함.
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
}

 

1.2 WebSocket 설정
WebSocket 설정을 위해 WebSocketConfig 클래스를 생성.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {

                 registry.addEndpoint("/ws")
                .setAllowedOrigins("http://localhost") //개발버전 인경우.
                .withSockJS();

    }

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

 

1.3 메시지 핸들러 및 모델 생성
메시지 핸들링을 위한 ChatController와 메시지 모델인 ChatMessage 클래스를 생성
public class ChatMessage {
    private String content;
    private String sender;
    // getter와 setter
}

@Controller
public class ChatController {
    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(ChatMessage chatMessage) {
        return chatMessage;
    }
}

 

2. React 프론트 구성

2.1 SockJS와 stompjs를 설치.
npm install sockjs-client stompjs

 

2.2 채팅 컴포넌트를 코딩한다.

import React, { useState, useEffect } from "react";
import SockJS from "sockjs-client";
import { Stomp } from "stompjs";

let stompClient = null;

const ChatRoom = () => {
    const [messages, setMessages] = useState([]);
    const [message, setMessage] = useState("");

    const connect = () => {
        const socket = new SockJS('http://localhost:8080/ws');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/public', function (messageOutput) {
                showMessageOutput(JSON.parse(messageOutput.body));
            });
        });
    };

    const sendMessage = () => {
        stompClient.send("/app/chat.sendMessage", {}, JSON.stringify({'content': message, 'sender': "Username"}));
    };

    const showMessageOutput = (messageOutput) => {
        setMessages(messages => [...messages, messageOutput]);
    };

    useEffect(() => {
        connect();
        return () => {
            if (stompClient !== null) {
                stompClient.disconnect();
            }
        };
    }, []);

    return (
        <div>
            <ul>
                {messages.map((msg, index) => (
                    <li key={index}>{msg.sender}: {msg.content}</li>
                ))}
            </ul>
            <input type="text" value={message} onChange={(e) => setMessage(e.target.value)} />
            <button onClick={sendMessage}>Send</button>
        </div>
    );
};

export default ChatRoom;

 

 

브라우저를 2개 뛰어서 확인해보면된다.

 

일단 총평을 하자면, 서로 같은 지점을 구독하고, 구독중인 구독자끼리 대화를 나눠 가진다고 보면된다.

개발 하고 이용중에 느낀점은 구독하는 과정이 상당히 느리다. 

구독이 되지 않는 시점에 메세지를 보내면 당연히 에러가 발생한다.

구독을 더 빠르게 하는 방법이나 편법에 대해서 알아봐야겠다.