본문 바로가기
IT이야기/PROJECT

[React + SpringBoot] 1대1 랜덤채팅 프로젝트 - 환경설정 및 구성

by JI_NOH 2024. 3. 8.

 

일대일 랜덤채팅 프로젝트

1. 환경설정 및 구성 (현재)

2. 화면기능 및 설계

3. Spring + 웹소켓 + STOMP 설정

4. Spring + Redis 설정 및 사용방법

5. Spring + Redis 매칭 로직


 

처음 프로젝트를 해보려고 할 때 socket을 이용한 채팅 사이트도 하나 만들어보고 싶었다.

하지만 REST API 통신부터 제대로 인지못한 상태에서 소켓을 이용한 실시간 통신을 한다는 건 힘들 것 같아서 미루고 미루다가 드디어 1인 프로젝트로 시작해보게 되었다.

 

기존에는 Thymeleaf를 이용한 간단한 웹 프로젝트를 진행하였으나

좀 더 많은 기능들을 편안하게 쓰기 위해서 React를 공부해서 진행했고 처음 쓰다보니 우당탕탕 코드들도 많다.

 


목적

- 로스트 아크 게임 유저들을 위한 깐부 찾기 랜덤채팅 사이트

구성

- 프론트 : React, Shadcn, Javascript, Socket, STOMP
- 백 : SpringBoot, Java, MySQL, Redis, WebSocket, STOMP


 

 

목차

    목적


    로스트아크라는 게임을 취미로 하고 있는데 다인 레이드 게임을 매주 반복하다보니 깐부를 찾아서 즐겁게 게임하려고 하는 사람들이 많다. 통합 디스코드가 존재해서 쉽게 구할 수는 있으나 아무래도 내 정보가 선노출이 된 후에 이야기하다 안맞으면 쉽게 바이바이~ 하는 부분이 조금 부담스러울 수도 있기에 랜덤 매칭을 통해 이야기 후, 서로 잘 맞다면 그 때 가서 본인의 정보를 공유할 수 있으면 좋지않을까? 하는 생각에서 시작되었다.

    이와 비슷한 사이트가 있으나 선호 레이드에 대한 선택을 할 수 있는 것이 아닌 완전한 랜덤매칭이라 좀 더 디테일한 매칭을 위해 구성해보게 되었다.

     

    각 사용 이유에 대해 간단히 설명해보겠다.

     

    -프론트

    React : 프론트 프레임 워크로 Vue도 있고 Angular도 있고 하지만 js기반으로 좀 더 쉽게 접할 수 있을 것 같아서 채택했다. 또한 자료도 방대한 편이라 찾기가 쉬우리라 생각해서 작업했으나 실제로는 ts로 알려주는 내용들이 더 많아서 생각보다 힘들었다.

    Shadcn : React, Vue, Next 등 여러 framework에서 쓸 수 있는 컴포넌트 오픈소스 library다. bootstrap을 가장 많이 들어봤지만 shadcn의 감성(?)이 좋아서 채택했다. 다만 React 라이브러리를 제공하나 typescript가 기본이라 js로 바꿔서 쓰는데 고생 좀 했다.

    Socket, STOMP : 1대1 실시간 통신을 위해 채택한 방식이며 pub/sub방식으로 이루어진다.

     

    -백

    SpringBoot : 기존에 SprinBoot로 프로젝트를 진행해왔고 Socket, stomp를 제대로 써보기 위해서 잘 아는 프레임워크로 선택했다.

    MySQL : 마찬가지로 무난한 선택지였다. PostgreSQL로 써볼까 하다가 굳이 필요성을 느끼지 못해 기존에 쓰던 것으로 진행했다.

    Redis : 원래 쓰지 않으려고 했으나 실시간 매칭 서비스까지 구현을 하면서 필요성을 느끼게 되어 선택하게됐다. 싱글스레드로 매칭의 경우는 매칭이 끝나면 더이상 필요가 없어지며 빠른 조회가 필요한 데이터들이다보니 인메모리 데이터베이스인 Redis를 이용하여 구현했다.

    WebSocket, STOMP : 프론트와 마찬가지의 이유다. 사실 양측 통신을 위해 둘 다 쓰다보니 중복 기재가 된 셈이다.

     

     

     

    프로젝트 구성

    -프론트

    Spring 프로젝트를 처음 진행할 때, 프로젝트 구성을 어떻게 해야할지 몰라서 수정하며 삽질을 많이 했는데

    리액트도 마찬가지로 처음엔 냅다 만들었다가 나중에 디렉토리를 구성해서 만들었다.

     

    ~ : shadcn 라이브러리들의 경로들이다. 자동생성 시켜줘서 이름이 저렇다.

     

    api : axios 연결을 할 때 필요한 API구성에 대한 저장을 해두었다. 인증방식을 JWT로 진행했기에 header를 포함하는 axios, 로그인 전의 axios 두개로 생성되어있다.

    export const instanceE =
      axios.create({
        baseURL: "http://localhost:8080",
        withCredentials: true,
      });
    
    
    export const instance = (accessToken) =>
      axios.create({
        baseURL: "http://localhost:8080",
        headers: {
          Authorization: `${accessToken}`,
        },
        withCredentials: true,
      });
     

    app: 프로젝트 전반에 걸쳐 필요한 js 나 css정도를 관리한 디렉토리다. 민감정보가 존재하지 않아 cookie를 사용하기로 결정했고 해당 쿠키를 관리할 수 있는 함수가 구현되어 있다.

     

    components : 각 페이지에 필요한 부분을 컴포넌트로 쪼개서 가지고 있는 디렉토리다. "채팅방"이라는 페이지가 있다면 채팅리스트, 실제로 채팅하는 구역 으로 나눌 수 있을 것이다. 그걸 하나의 js에 다 넣기엔 너무 지저분하고 소스코드가 길어지기 때문에 분리를 했다. 다만, 실제 프로젝트에는 제대로 쪼개지지 않은 부분도 있어 조금 너저분하다.

     

    pages : 대표적으로 보게 되는 페이지들을 구성했다. 메인 페이지는 App.js에 구현되어 있어 별도 이름이 붙어있지 않다.

     

     

    -백

    백 프로젝트 구성에 대해서 자세한 설명은 생략하겠다. domain중심의 구조를 짜는 경우도 있긴하지만 프로젝트 수정을 하다보면 개인적으로 나는 역할 중심의 구조가 찾기가 쉬워서 위와 같이 구성했다.

     

    application 설정은 공통설정, 로컬 설정, 개발 설정 으로 나누었다.

    해당 부분에 대한 설명은 AWS EC2 설정을 하며 필요했던 부분이라 해당 포스팅을 참고하면 되겠다.

     

     

     

     

     

    프로젝트 환경설정


    - 프론트

    shadcn 사용법

    https://ui.shadcn.com/ 에서 Components 탭으로 이동 후 원하는 컴포넌트를 선택해보면

    사용법에 설치부터 설정하는 법에 대한 설명이 나와있다.

    vs 터미널에서 해당 명령어를 입력하여 설치를 하고나면

    자동으로 경로생성과 함께 사용할 수 있는 jsx파일이 생성된다. 타입스크립트를 쓴다면 tsx파일이 생성될 것이다. 이 외의 자세한 설정 및 사용법은 따로 포스팅할 예정이다.

     

    socket, stomp 설정

    import {Stomp} from '@stomp/stompjs';
    import SockJS from 'sockjs-client';
    
    // socket생성
    const socket = new SockJS("http://localhost:8080/{엔드포인트}");
    const stomp = Stomp.over(socket);
    
    // 발행
    stomp.connect(() => {
        stomp.send('발행경로', {}, data);
    });
    
    // 구독
    stomp.connect(() => {
        stomp.subscribe('구독경로', (message)=> {
        //구현부
        });
    }
     

    마찬가지로 자세한 내용은 따로 포스팅예정이지만 리액트에서 구현하는 방법은 간단히 위와 같다.

    실제로는 좀더 귀찮고 header까지 들어가려면 더 많은 작업이 필요하며 실제로 백엔드랑은 어떻게 통신되는지 이해하는데 한세월 걸렸었다.

    

     

    - 백

    socket, stomp 설정

    /* build.gradle */
    // websocket - 실시간 통신
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
    implementation 'org.webjars:sockjs-client:1.1.2'
    
    // stomp - 구독
    implementation 'org.webjars:stomp-websocket:2.3.3-1'
     
    /* WebSocketConfig */
        @Override
        public void configureMessageBroker(MessageBrokerRegistry config) {
            // 메세지 구독 경로
            config.enableSimpleBroker("/sub");
            // 메시지 보낼 때 관련 경로 설정
            config.setApplicationDestinationPrefixes("/pub");
        }
    
        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            //Client에서 websocket 연결할 때 사용할 API 경로를 설정 - 채팅용
            registry.addEndpoint("/chat")
                    .setAllowedOriginPatterns("*")
                    .withSockJS();
           //Client에서 websocket 연결할 때 사용할 API 경로를 설정 - 매칭용
            registry.addEndpoint("/match")
                    .setAllowedOriginPatterns("*")
                    .withSockJS();
        }
     

    마찬가지로 세부 내용은 별도 포스팅예정이다.

    가장 큰 설정 부분은 build.gradle추가와 WebSocketConfig 설정이다.

    웹 통신이 아무래도 클라이언트 요청 -> 서버 응답이 디폴트인 구조인데

    실시간 통신같은 경우는 서버에서도 클라이언트에다 냅다 응답해야하는 경우가 필요한데 그 때 사용하기 좋은 라이브러리다. 덕분에 처음 웹 공부를 하며 혼자 궁금했던 부분이 꽤나 해소 됐다.

     

    프로젝트의 소개와 구성에 대해서 여기까지 하고

    어떻게 그간 삽질을 했고 어떻게 해결했는지에 대한 부분은 천천히 포스팅할 예정이다.