카테고리 없음

COW-CAMPUS-CONNECT 프로젝트 — 실시간 집계수(Onboarding Guide)

Frisbeen 2025. 8. 27. 21:31

오늘은 "현재 등록된 사용자 수" 같은 집계값을 실시간으로 보여주는 기능을 추가했습니다.

 

처음 개발을 시작하는 분도 이해할 수 있도록, 백엔드 → 프론트엔드 → 개발 환경(proxy) 순서로 차근차근 설명드리겠습니다.


1. 백엔드(Spring Boot)

(1) DTO 만들기

  • **DTO(Data Transfer Object)**는 프론트로 내려보낼 데이터를 담는 그릇입니다.
  • /src/main/java/org/example/cowmatchingbe/dto/SummaryDto.java:
package org.example.cowmatchingbe.dto;

public record SummaryDto(long totalUsers, long totalProfiles, long totalMatches, long distinctMatchers, long maleUsers, long femaleUsers) {
}

👉 여기서는 등록된 사용자 수, 프로필 수, 매칭 수 등을 담을 수 있게 필드를 정의했습니다.

(2) Repository 활용하기

  • 사용자 수를 세려면 DB에 직접 접근해야 합니다.
  • /src/main/java/org/example/cowmatchingbe/repository/UserRepository.java:
package org.example.cowmatchingbe.repository;

import org.example.cowmatchingbe.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    long count(); // 전체 유저 수
    long countByGender(String gender); // 성별별 카운트
}

(3) Service 작성

  • DB에서 꺼낸 값을 DTO에 담아 리턴합니다.
package org.example.cowmatchingbe.service;

import lombok.RequiredArgsConstructor;
import org.example.cowmatchingbe.dto.SummaryDto;
import org.example.cowmatchingbe.repository.UserRepository;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MetricsService {
    private final UserRepository userRepository;

    public SummaryDto getSummary() {
        long total = userRepository.count();
        long male = userRepository.countByGender("male");
        long female = userRepository.countByGender("female");

        return new SummaryDto(total, 0, 0, 0, male, female);
    }
}

👉 우선 totalUsers, maleUsers, femaleUsers만 실제 값 넣고, 나머지는 0으로 둡니다.

(4) Controller 추가

package org.example.cowmatchingbe.controller;

import lombok.RequiredArgsConstructor;
import org.example.cowmatchingbe.dto.SummaryDto;
import org.example.cowmatchingbe.service.MetricsService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class MetricsController {
    private final MetricsService metricsService;

    @GetMapping("/api/metrics/summary")
    public SummaryDto getSummary() {
        return metricsService.getSummary();
    }
}

👉 이제 브라우저에서 http://localhost:8080/api/metrics/summary 호출하면 JSON으로 집계수가 내려옵니다.

예시 응답:

{
  "totalUsers": 7,
  "totalProfiles": 4,
  "totalMatches": 3,
  "distinctMatchers": 3,
  "maleUsers": 3,
  "femaleUsers": 1
}

2. 프론트엔드(React + Vite)

(1) 타입 정의

  • /src/types/index.ts:
export interface SummaryDto {
  totalUsers: number;
  totalProfiles: number;
  totalMatches: number;
  distinctMatchers: number;
  maleUsers: number;
  femaleUsers: number;
}

(2) API 함수 만들기

  • /src/api/api.ts:
import { http } from './http';
import type { SummaryDto } from '../types';

export async function getSummaryMetrics() {
  const { data } = await http.get<SummaryDto>('/api/metrics/summary');
  return data;
}

(3) App.tsx 연동

const [summary, setSummary] = useState<SummaryDto | null>(null);

useEffect(() => {
  (async () => {
    try {
      const s = await getSummaryMetrics();
      setSummary(s);
    } catch (e) {
      console.error(e);
    }
  })();
}, []);

return (
  <div>
    {summary ? (
      <div>현재 등록 인원: {summary.totalUsers}명</div>
    ) : (
      <div>불러오는 중...</div>
    )}
  </div>
);

👉 이제 프론트 화면에 실시간 등록 인원이 뜹니다.


3. 개발 환경 (Proxy 설정)

개발할 때는 프론트가 5173, 백엔드가 8080으로 따로 뜨기 때문에 CORS 문제가 납니다. 이를 해결하려고 Vite 프록시를 추가했습니다.

vite.config.ts

/// <reference types="node" />

import path from 'path';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import svgr from 'vite-plugin-svgr';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [react(), tailwindcss(), svgr()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        secure: false,
      },
    },
  },
});

👉 이렇게 하면 프론트에서 /api/... 로 요청하면 자동으로 백엔드 8080으로 전달됩니다.


4. 오늘의 성과

  • 백엔드: DTO 정의, Service/Controller 작성, DB 조회 로직 추가
  • 프론트엔드: API 함수 + React useEffect로 실시간 데이터 불러오기
  • 개발 환경: Vite proxy 설정으로 CORS 문제 해결

결과적으로, "현재 몇 명이 가입했는지"를 프론트 화면에서 실시간으로 보여줄 수 있게 됨.