접속자 대기열 시스템 #3- 셋업

2024. 10. 10. 14:57·프레임워크/자바 스프링

접속자 대기열 시스템 #3 - 셋업

이번 포스팅에서는 waiting-web과 waiting-api 두 개의 서버를 구축하는 방법을 소개합니다. 이 두 서버는 각각 예매 웹페이지와 대기열 처리를 담당하며, Spring Boot를 사용하여 간단하게 셋업할 수 있습니다.

1. 프로젝트 개요

  • waiting-web: 대기열에서 성공적으로 빠져나온 사용자를 예매 웹페이지로 리디렉션하여 서비스합니다.
  • waiting-api: 대기 페이지를 제공하고 대기열 처리와 관련된 API 정보를 관리합니다.

이 두 서버는 분리된 서비스로 운영되어, 대기열 처리와 실제 웹페이지 서비스 로직을 독립적으로 관리할 수 있도록 합니다.

2. 프로젝트 셋업

두 개의 Spring Boot 프로젝트를 각각 설정하여 시작하겠습니다.

2.1. waiting-web 설정

waiting-web은 사용자가 대기열에서 빠져나오면 예매 웹페이지로 리디렉션하는 역할을 합니다. 이 서버는 간단한 웹 애플리케이션으로 설정하며, Thymeleaf와 Spring MVC를 사용해 정적 페이지를 제공할 수 있도록 구성합니다.

2.1.1. build.gradle 설정

waiting-web 프로젝트의 Gradle 설정은 다음과 같습니다:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.4'
    id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

tasks.named('test') {
    useJUnitPlatform()
}
2.1.2. 주요 의존성
  • spring-boot-starter-thymeleaf: Thymeleaf 템플릿 엔진을 사용하여 정적 HTML 페이지를 제공합니다.
  • spring-boot-starter-web: Spring MVC를 이용해 웹 애플리케이션을 구축합니다.

이 설정을 통해 waiting-web 프로젝트는 간단한 웹페이지 서빙과 리디렉션 기능을 수행할 수 있습니다.

2.2. waiting-api 설정

waiting-api는 대기열 처리와 관련된 백엔드 로직을 담당하며, Reactive Streams와 Redis를 사용하여 비동기 대기열 처리를 효율적으로 관리합니다.

2.2.1. build.gradle 설정

waiting-api 프로젝트의 Gradle 설정은 다음과 같이 구성합니다:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.4'
    id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
    testImplementation 'com.github.codemonstur:embedded-redis:1.0.0'
}

tasks.named('test') {
    useJUnitPlatform()
}
2.2.2. 주요 의존성
  • spring-boot-starter-data-redis-reactive: Redis를 사용하여 대기열 데이터를 비동기적으로 관리합니다.
  • spring-boot-starter-webflux: 비동기 웹 애플리케이션을 구축하기 위해 WebFlux를 사용합니다.
  • spring-boot-starter-thymeleaf: 필요 시 HTML 템플릿 엔진으로 대기 페이지를 제공합니다.
  • io.projectreactor:reactor-test: Reactive Streams 기반의 테스트를 지원합니다.
  • com.github.codemonstur:embedded-redis: 테스트 시 임베디드 Redis를 사용할 수 있게 해주는 라이브러리입니다.

3. html

resources > templates > index.html

3.1. waiting-web

resources > templates > index.html 파일을 만들고 아래 코드를 입력해줍니다.
디렉토리가 없다면 만들어주세요.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>영화 예매</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #1b1b1b;
            margin: 0;
            padding: 0;
            color: #fff;
        }
        .container {
            width: 90%;
            max-width: 1200px;
            margin: 20px auto;
            background-color: #2e2e2e;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        }
        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        .header img {
            width: 150px;
        }
        .header h1 {
            margin: 0;
            font-size: 24px;
        }
        .steps {
            display: flex;
            justify-content: space-between;
            margin: 20px 0;
        }
        .step {
            flex: 1;
            text-align: center;
            padding: 10px;
            background-color: #444;
            margin-right: 5px;
            border-radius: 5px;
            font-size: 14px;
        }
        .step.active {
            background-color: #d9534f;
            color: #fff;
        }
        .clearfix::after {
            content: "";
            clear: both;
            display: table;
        }
        .details-section {
            display: flex;
            justify-content: space-between;
            margin-top: 20px;
        }
        .movie-poster {
            width: 30%;
            text-align: center;
        }
        .movie-poster img {
            width: 100%;
            border-radius: 8px;
        }
        .seat-selection, .summary-section {
            width: 65%;
            margin-left: 20px;
        }
        .seat-selection h2, .summary-section h2 {
            font-size: 18px;
            margin-bottom: 10px;
        }
        .seats {
            display: grid;
            grid-template-columns: repeat(16, 30px);
            gap: 5px;
            margin: 20px 0;
            justify-content: center;
        }
        .seat {
            width: 30px;
            height: 30px;
            background-color: #444;
            border-radius: 5px;
            cursor: pointer;
        }
        .seat.selected {
            background-color: #d9534f;
        }
        .seat.occupied {
            background-color: #777;
            cursor: not-allowed;
        }
        .empty {
            background-color: transparent;
            pointer-events: none;
        }
        .summary-section {
            margin-top: 20px;
            background-color: #3c3c3c;
            padding: 15px;
            border-radius: 8px;
        }
        .summary p {
            margin: 5px 0;
        }
        .summary .total {
            font-size: 18px;
            margin-top: 10px;
        }
        .date-time-info {
            text-align: right;
            font-size: 14px;
        }
        .date-time-info p {
            margin: 5px 0;
        }
        .next-step {
            margin-top: 20px;
            text-align: center;
        }
        .next-button {
            background-color: #d9534f;
            color: #fff;
            border: none;
            padding: 10px 20px;
            font-size: 16px;
            border-radius: 5px;
            cursor: pointer;
        }
        .next-button:hover {
            background-color: #c9302c;
        }
        .cancel-button {
            background-color: #444;
            color: #fff;
            border: none;
            padding: 10px 20px;
            font-size: 16px;
            border-radius: 5px;
            cursor: pointer;
            margin-right: 10px;
        }
        @media (max-width: 768px) {
            .details-section {
                flex-direction: column;
            }
            .movie-poster, .seat-selection {
                width: 100%;
                margin: 0;
            }
            .seat-selection {
                margin-top: 20px;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header">
        <img src="https://resizing.flixster.com/wnZN6VrjWe4-xyFfhtXgmoRRNyM=/ems.cHJkLWVtcy1hc3NldHMvbW92aWVzLzFlNDNkZGQ3LTEwOWItNGFmZi1iYzNjLWRmYjJhYzZkNThhZS53ZWJw" alt="IMAGIX Cinema">
        <h1>MORTAL ENGINES</h1>
    </div>
    <div class="steps">
        <div class="step active">1. Choose your place</div>
        <div class="step">2. Payment</div>
        <div class="step">3. Ticket</div>
    </div>
    <div class="clearfix">
        <div class="details-section">
            <div class="movie-poster">
                <img src="https://resizing.flixster.com/wnZN6VrjWe4-xyFfhtXgmoRRNyM=/ems.cHJkLWVtcy1hc3NldHMvbW92aWVzLzFlNDNkZGQ3LTEwOWItNGFmZi1iYzNjLWRmYjJhYzZkNThhZS53ZWJw" alt="Movie Poster">
            </div>
            <div class="seat-selection">
                <h2>Choose your seats</h2>
                <div class="seats">
                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>

                    <!-- Row 1 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- Row 2 -->
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <div class="seat"></div><div class="seat"></div><div class="seat"></div><div class="seat"></div>
                    <div class="seat selected"></div><div class="seat selected"></div><div class="seat"></div><div class="seat"></div>
                    <div class="empty"></div><div class="empty"></div><div class="empty"></div><div class="empty"></div>
                    <!-- More rows as needed -->
                </div>
                <div class="summary-section">
                    <h2>Summary</h2>
                    <p>6 row 7th seat - $15</p>
                    <p>6 row 8th seat - $15</p>
                    <hr>
                    <p class="total"><strong>Total: $30</strong></p>
                </div>
                <div class="next-step">
                    <button class="cancel-button">Cancel</button>
                    <button class="next-button">Next</button>
                </div>
            </div>
            <div class="date-time-info">
                <h2>Date & Time</h2>
                <p>Date: 14 DEC</p>
                <p>Time: 9:40 pm</p>
                <p>Type: IMAX 3D</p>
            </div>
        </div>
    </div>
</div>
<script>
    document.querySelectorAll('.seat').forEach(seat => {
        seat.addEventListener('click', () => {
            if (!seat.classList.contains('occupied')) {
                seat.classList.toggle('selected');
            }
        });
    });
</script>
</body>
</html>

3.2. waiting-api

resources > templates > waiting-room.html 파일을 만들고 아래 코드를 입력해줍니다.

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>접속 대기 중</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        .queue-container {
            background-color: #fff;
            width: 300px;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            text-align: center;
            position: relative;
        }
        .queue-header {
            font-size: 18px;
            font-weight: bold;
            margin-bottom: 10px;
        }
        .queue-subheader {
            font-size: 14px;
            color: #666;
            margin-bottom: 20px;
        }
        .queue-info {
            background-color: #f9f9f9;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 10px;
        }
        .queue-info p {
            margin: 5px 0;
            font-size: 14px;
        }
        .queue-count {
            font-size: 24px;
            color: #ff5722;
            font-weight: bold;
        }
        .progress-bar {
            background-color: #ddd;
            border-radius: 5px;
            height: 8px;
            margin: 10px 0;
            position: relative;
        }
        .progress-fill {
            background-color: #ff5722;
            height: 100%;
            width: 50%;
            border-radius: 5px;
        }
        .queue-warning {
            font-size: 12px;
            color: #999;
            margin-top: 10px;
        }
        .close-button {
            position: absolute;
            top: 10px;
            right: 10px;
            font-size: 18px;
            color: #999;
            cursor: pointer;
        }
    </style>
</head>
<body>
<div class="queue-container">
    <div class="close-button">&times;</div>
    <div class="queue-header">YES24 티켓</div>
    <div class="queue-subheader">접속 대기 중입니다.<br>순서가 오면 다음 단계로 넘어갑니다.</div>
    <div class="queue-info">
        <p>대기 인원 <span id="number" class="queue-count">0명 이상</span></p>
        <div class="progress-bar">
            <div class="progress-fill" style="width: 50%;"></div>
        </div>
        <p>예상 대기 시간: <span id="waiting-time">00분 00초</span></p>
    </div>
    <div class="queue-warning">
        ※ 대기 중 새로고침을 하거나 다시 접속하시면<br>대기 시간이 늘어날 수 있으니 유의해 주세요.
    </div>
</div>
<script>
    function fetchWaitingRank() {
        const queue = `[[${queue}]]`;
        const userId = `[[${userId}]]`;
        const queryParam = new URLSearchParams({queue: queue, user_id: userId});

        fetch('/api/v1/queue/rank?' + queryParam)
            .then(response => response.json())
            .then(data => {
                const numberElement = document.querySelector('#number');
                const timeElement = document.querySelector('#waiting-time');

                if (data.rank < 0) {
                    fetch('/api/v1/queue/touch?' + queryParam)
                        .then(() => {
                            // 페이지 새로고침
                            window.location.reload();
                        })
                        .catch(error => console.error(error));
                    return;
                }

                // 대기 인원 업데이트
                if (numberElement) {
                    numberElement.innerHTML = data.rank + '명 이상';
                }

                // 예상 대기 시간 업데이트
                if (timeElement) {
                    timeElement.innerHTML = calculateEstimatedTime(data.rank);
                }
            })
            .catch(error => console.error(error));
    }

    function calculateEstimatedTime(rank) {
        // 대기열에서 10초마다 100명씩 제거
        const removalRatePerSecond = 100 / 10;
        const estimatedTimeInSeconds = rank / removalRatePerSecond;

        const minutes = Math.floor(estimatedTimeInSeconds / 60);
        const seconds = Math.floor(estimatedTimeInSeconds % 60);
        return `${minutes}분 ${seconds < 10 ? '0' : ''}${seconds}초`;
    }

    setInterval(fetchWaitingRank, 3000);
</script>
</body>
</html>

4. 컨트롤러

4.1. waiting-web

@SpringBootApplication
@Controller
public class WaitingWebApplication {

    RestTemplate restTemplate = new RestTemplate();

    public static void main(String[] args) {

        SpringApplication.run(WaitingWebApplication.class, args);
    }

    @GetMapping
    public String index(){
        return "index"
    }

4.2. waiting-api


@Controller
public class WaitingRoomController{

    @GetMapping("/waiting-room")
    Mono<REndering> waitingRoomPage(
        @RequestParam(name="queue", defaultValue="default") String queue, 
          @RequestParam(name="user_id") Long userId 
    ){
        return Mono.just(Rendering.view("waiting-room.html").build());
    }
}

5. 프로젝트 실행

각 프로젝트에서 다음 명령어를 실행하여 서버를 시작할 수 있습니다.

# waiting-web 프로젝트 실행
./gradlew :waiting-web:bootRun

# waiting-api 프로젝트 실행
./gradlew :waiting-api:bootRun

서버가 각각 실행되면 waiting-web은 사용자의 대기 상태를 확인하고 성공 시 예매 페이지로 리디렉션합니다. waiting-api는 대기열 상태를 관리하고 필요한 정보를 제공하는 API를 서빙합니다.

 

6. 다음 단계

이제 두 개의 서버를 구축했으니, 다음 단계에서는 각 서버의 기능을 상세히 구현하고 통합하는 방법을 살펴보겠습니다. 예를 들어, waiting-web과 waiting-api 간의 통신을 설정하거나 대기열 로직을 더욱 구체화할 수 있습니다.

 

저작자표시

'프레임워크 > 자바 스프링' 카테고리의 다른 글

접속자 대기열 시스템 #6- 접속 대기 웹페이지 개발  (1) 2024.10.10
접속자 대기열 시스템 #5- Redis를 이용한 대기열 관리 및 웹페이지 진입 API 구현  (1) 2024.10.10
접속자 대기열 시스템 #4- 대기열 등록 API 개발  (6) 2024.10.09
BlockHound: Java 비동기 애플리케이션에서 블로킹 호출을 감지하는 도구  (6) 2024.10.08
Spring MVC와 Spring Webflux 성능비교  (0) 2024.10.08
'프레임워크/자바 스프링' 카테고리의 다른 글
  • 접속자 대기열 시스템 #6- 접속 대기 웹페이지 개발
  • 접속자 대기열 시스템 #5- Redis를 이용한 대기열 관리 및 웹페이지 진입 API 구현
  • 접속자 대기열 시스템 #4- 대기열 등록 API 개발
  • BlockHound: Java 비동기 애플리케이션에서 블로킹 호출을 감지하는 도구
hyeseong-dev
hyeseong-dev
안녕하세요. 백엔드 개발자 이혜성입니다.
  • hyeseong-dev
    어제 오늘 그리고 내일
    hyeseong-dev
  • 전체
    오늘
    어제
    • 분류 전체보기 (282)
      • 여러가지 (107)
        • 알고리즘 & 자료구조 (72)
        • 오류 (4)
        • 이것저것 (29)
        • 일기 (1)
      • 프레임워크 (39)
        • 자바 스프링 (39)
        • React Native (0)
      • 프로그래밍 언어 (38)
        • 파이썬 (30)
        • 자바 (3)
        • 스프링부트 (5)
      • 운영체제 (0)
      • DB (17)
        • SQL (0)
        • Redis (17)
      • 클라우드 컴퓨팅 (2)
        • 도커 (2)
        • AWS (0)
      • 스케쥴 (65)
        • 세미나 (0)
        • 수료 (0)
        • 스터디 (24)
        • 시험 (41)
      • 트러블슈팅 (1)
      • 자격증 (0)
        • 정보처리기사 (0)
      • 재태크 (4)
        • 암호화폐 (4)
        • 기타 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    ecs
    백준
    DP
    mybatis
    docker
    WebFlux
    #개발자포트폴리오 #개발자이력서 #개발자취업 #개발자취준 #코딩테스트 #항해99 #취리코 #취업리부트코스
    항해99
    Docker-compose
    Spring Boot
    FastAPI
    시험
    OOP
    AWS
    reactor
    Spring WebFlux
    자바
    EC2
    Redis
    RDS
    spring
    완전탐색
    celery
    프로그래머스
    Python
    java
    취업리부트
    SAA
    그리디
    파이썬
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
hyeseong-dev
접속자 대기열 시스템 #3- 셋업
상단으로

티스토리툴바