오늘은 "현재 등록된 사용자 수" 같은 집계값을 실시간으로 보여주는 기능을 추가했습니다.
처음 개발을 시작하는 분도 이해할 수 있도록, 백엔드 → 프론트엔드 → 개발 환경(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 문제 해결
결과적으로, "현재 몇 명이 가입했는지"를 프론트 화면에서 실시간으로 보여줄 수 있게 됨.