[GDG] 홍대 맛집 아카이빙 프로젝트 #22 - 데모데이 발표자료 준비

2025. 8. 27. 14:36·팀 프로젝트/[2025][GDG]홍대 맛집 아카이빙 프로젝트

기능설명

- 회원가입

홍익대학교 이메일 인증을 거친 후 아이디, 비밀번호, 닉네임, 홍익대학교 이메일을 받아 아이디, 닉네임, 홍익대학교 이메일 중 어느하나라도 기존 DB에 저장되어 있는 값과 겹치면 회원가입 불가

 

- 로그인

아이디와 비밀번호를 입력받음

 

- 투표

1. 투표

재학생만 최대 3개의 가게에 투표 가능함. 재학생이 아니거나 이미 투표한 경우에는 투표가 불가능함

 

2. 자기투표조회

자기 자신이 현재까지 어떤 가게에 투표했는지 목록을 볼 수 있음

 

3. 월별결과보기

특정 연월의 투표결과를 볼 수 있음 (비재학생의 경우도 볼 수 있음)

 

4. 결과보기

현재 진행 중인 투표의 결과를 볼 수 있음 (비재학생의 경우도 볼 수 있음)

 

-> 회원가입과 로그인 기능에 대해서는 간단하게 넘어가도 될 듯함

 

코드설명

- 회원가입

    public ResponseEntity<ResponseDTO> signUp(MemberRequestDTO memberRequestDTO) throws Exception {
        String nickname = memberRequestDTO.getNickname();
        String userId = memberRequestDTO.getUserId();
        String password = memberRequestDTO.getPassword();
        String email = memberRequestDTO.getEmail();

        if (nickname == null || nickname.isEmpty()) { //userId 와 password 는 validity 검사 대상임
            ResponseDTO responseDTO = ResponseDTO.builder()
                    .status(400)
                    .message("닉네임을 입력해주세요")
                    .build();

            return new ResponseEntity<>(responseDTO, HttpStatus.BAD_REQUEST);
        } else if (email == null || email.isEmpty()) {
            ResponseDTO responseDTO = ResponseDTO.builder()
                    .status(400)
                    .message("이메일 주소를 입력해주세요")
                    .build();

            return new ResponseEntity<>(responseDTO, HttpStatus.BAD_REQUEST);
        }
        else {
            boolean isAlreadyExist = memberRepository.existsByUserIdOrEmailOrNickname(
                    userId, email, nickname);

            if (isAlreadyExist) {
                ResponseDTO responseDTO = ResponseDTO.builder()
                        .status(400)
                        .message("이미 가입한 사용자입니다.")
                        .build();

                return ResponseEntity
                        .status(HttpStatus.BAD_REQUEST)
                        .body(responseDTO);
            }

            Member member = Member.builder()
                    .nickname(nickname)
                    .userId(userId)
                    .password(password)
                    .email(email)
                    .voteAvailable(true)
                    .build();

            System.out.println("회원정보가 입력됨" + member);
            memberRepository.save(member);
            ResponseDTO responseDTO = ResponseDTO.builder()
                    .status(200)
                    .message("성공")
                    .build();

            return ResponseEntity.status(HttpStatus.OK).body(responseDTO);
        }
    }

회원가입에서 기본이 되는 코드

회원가입 할 때 요청으로 받는 requestDTO가 로그인 때 requestDTO와 공유 중이기 때문에 아이디와 비밀번호는 유효성검사의 대상이나 닉네임과 이메일주소는 유효성검사의 대상이 아니기 때문에 수동으로 유효성검사를 진행함

 

- 로그인

package com.hongchelin.service.login;

import com.hongchelin.Domain.Token;
import com.hongchelin.Repository.MemberRepositoryInterface;
import com.hongchelin.Repository.TokenRepositoryInterface;
import com.hongchelin.service.JWT.JWTFilter;
import com.hongchelin.dto.Request.MemberRequestDTO;
import com.hongchelin.dto.user.ResponseDTO;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class LoginMainService {
    private final MemberRepositoryInterface memberRepository;
    private final TokenRepositoryInterface tokenRepository;
    private final JWTFilter jwtFilter;

    public LoginMainService(MemberRepositoryInterface memberRepository,
                            JWTFilter jwtFilter,
                            TokenRepositoryInterface tokenRepository) {
        this.memberRepository = memberRepository;
        this.jwtFilter = jwtFilter;
        this.tokenRepository = tokenRepository;
    }

    public ResponseEntity<ResponseDTO> login(String secret, MemberRequestDTO memberRequestDTO) {
        System.out.println(memberRequestDTO);
        System.out.println("요청확인");

        String userId = memberRequestDTO.getUserId();
        String password = memberRequestDTO.getPassword();

        Integer count = memberRepository.countByUserIdAndPassword(userId, password);

        if (count == 1) { //정보 있음. 로그인
            String refreshToken = jwtFilter.createRefreshToken(secret, userId);

            ResponseDTO responseDTO = ResponseDTO.builder()
                    .status(200)
                    .message("성공")
                    .accessToken(jwtFilter.createToken(secret, userId))
                    .refreshToken(refreshToken)
                    .build();

            Token token = Token.builder()
                    .userId(userId)
                    .refreshToken(refreshToken)
                    .build();

            tokenRepository.save(token);
            System.out.println(responseDTO);

            return ResponseEntity.status(HttpStatus.OK).body(responseDTO);
        } else { //로그인 정보 없음
            ResponseDTO responseDTO = ResponseDTO.builder()
                    .status(400)
                    .message("아이디 또는 비밀번호가 올바르지 않습니다.")
                    .build();

            System.out.println(responseDTO);

            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseDTO);
        }
    }
}

로그인에서의 메인이 되는 코드

로그인 시 회원정보가 있을 경우에는 토큰을 만들어서 반환해주고 아닐 경우 에러를 반환한다.

 

- 투표

package com.hongchelin.service.Vote;

import com.hongchelin.Domain.*;
import com.hongchelin.Repository.*;
import com.hongchelin.exceptions.CannotFoundDbElementException;
import com.hongchelin.exceptions.UnauthorizedException;
import com.hongchelin.service.JWT.JWTFilter;
import com.hongchelin.dto.Request.voteRequstDTO;
import com.hongchelin.dto.Response.StoreForVoteResponseDTO;
import com.hongchelin.dto.user.ResponseDTO;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
public class VoteService {
    private final JWTFilter jwtFilter;
    private final MemberRepositoryInterface memberRepository;
    private final StoreForVoteRepositoryInterface storeForVoteRepository;
    private final StoreRepositoryInterface storeRepositoryInterface;
    private final VoteRecordRepository voteRecordRepository;
    private final PastStoreRepositoryInterface pastStoreRepositoryInterface;

    public VoteService(JWTFilter jwtFilter,
                       MemberRepositoryInterface memberRepository,
                       StoreForVoteRepositoryInterface storeForVoteRepository,
                       StoreRepositoryInterface storeRepositoryInterface,
                       VoteRecordRepository voteRecordRepository, PastStoreRepositoryInterface pastStoreRepositoryInterface) {
        this.jwtFilter = jwtFilter;
        this.memberRepository = memberRepository;
        this.storeForVoteRepository = storeForVoteRepository;
        this.storeRepositoryInterface = storeRepositoryInterface;
        this.voteRecordRepository = voteRecordRepository;
        this.pastStoreRepositoryInterface = pastStoreRepositoryInterface;
    }

    public ResponseEntity<StoreForVoteResponseDTO> voteMainService(
            String secret,
            voteRequstDTO voteRequstDTO,
            HttpServletRequest request) throws UnauthorizedException {

        Date date = new Date();
        List<Long> votedIds = voteRequstDTO.getVotedIdList();
        List<StoreForVote> storeForVoteList = new ArrayList<>(); //저장용 리스트 / 저장할 때 사용함

        boolean validity = jwtFilter.getTokenFromHeader(secret, request).getValidity();

        if (!validity) {
            throw new UnauthorizedException();
        }
        String userId = jwtFilter.getTokenFromHeader(secret, request).getMemberInfo().getIdentifier();

        boolean voteAvailable = memberRepository.findByUserId(userId).get(0).isVoteAvailable();   //사용자 투표여부 조사

        if (!voteAvailable) {         //이미투표한사용자
            StoreForVoteResponseDTO storeForVoteResponseDTO = StoreForVoteResponseDTO.builder()
                    .status(200)
                    .message("이미 투표한 사용자입니다.")
                    .build();

            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(storeForVoteResponseDTO);
        }

        if (votedIds == null || votedIds.isEmpty()) {     //사용자가 투표한 상점들의 id 리스트 - 메서드 인자로 제공됨
            StoreForVoteResponseDTO storeForVoteResponseDTO = StoreForVoteResponseDTO.builder()
                    .status(400)
                    .message("반드시 하나를 선택해주세요.")
                    .build();

            return ResponseEntity
                    .status(HttpStatus.BAD_REQUEST)
                    .body(storeForVoteResponseDTO);
        }

        if (votedIds.size() > 3) {     //3개이상 선택불가
            StoreForVoteResponseDTO storeForVoteResponseDTO = StoreForVoteResponseDTO.builder()
                    .status(400)
                    .message("3개 이상은 선택이 불가합니다.")
                    .build();

            return ResponseEntity
                    .status(HttpStatus.BAD_REQUEST)
                    .body(storeForVoteResponseDTO);
        }

        for (Long id : votedIds) {              //리스트를 순회하며 아이디를 따고 상점정보를 가져와 저장함
            Store store = storeRepositoryInterface.findById(id);

            if (store != null) {       //DB에 값이 있는 경우
                StoreForVote storeForVote = storeForVoteRepository.findByStoreId(id);

                if (storeForVote != null) {
                    storeForVoteList.add(storeForVote);
                } else {
                    throw new CannotFoundDbElementException();
                }
            } else {                                        //DB에 값이 없는 경우 - 저장 취소 및 오류 반환
                StoreForVoteResponseDTO storeForVoteResponseDTO = StoreForVoteResponseDTO.builder()
                        .status(400)
                        .message("입력된 값이 존재하지 않습니다.")
                        .build();

                storeForVoteList.clear();

                return ResponseEntity
                        .status(HttpStatus.BAD_REQUEST)
                        .body(storeForVoteResponseDTO);
            }
        }

        for (StoreForVote storeForVote : storeForVoteList) {    // 인자로 받은 값들이 모두 정상. DB에 저장하는 과정
            Integer votedCount = storeForVote.getVotedCount() + 1;
            storeForVote.setVotedCount(votedCount);
            storeForVoteRepository.save(storeForVote);
        }

        StoreForVoteResponseDTO storeForVoteResponseDTO = StoreForVoteResponseDTO.builder()
                .status(200)
                .message("성공")
                .build();

        modifyUserVoteAvailable(userId);

        for (long ids : votedIds) {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
            String formattedDate = formatter.format(date);

            VoteRecord voteRecord = VoteRecord.builder()
                    .userId(userId)
                    .votedId(ids)
                    .whenForVote(formattedDate)
                    .build();

            voteRecordRepository.save(voteRecord);
        }

        return ResponseEntity
                .status(HttpStatus.OK)
                .body(storeForVoteResponseDTO);
    }

    public ResponseDTO modifyUserVoteAvailable(String userId) {
        Member member = memberRepository.findByUserId(userId).get(0);
        member.setVoteAvailable(false);

        memberRepository.save(member);

        return ResponseDTO.builder()
                .status(200)
                .build();
    }
}

투표메인

투표한 가게의 아이디를 배열로 받아 배열을 순회하면서 해당 아이디가 유효한지 검사, 모든 요소들이 유효하다면 차례로 투표 후보들에게서 득표수를 1 증가시킨다.

잘못된 가게의 아이디가 들어온 경우, 아이디를 하나도 전달하지 않은 경우, 아이디를 3개 초과로 전달한 경우에 대해서 각각 조건문으로 exception 처리를 했다.

 

package com.hongchelin.service.Vote;

import com.hongchelin.Domain.StoreForVote;
import com.hongchelin.Repository.StoreForVoteRepositoryInterface;
import com.hongchelin.dto.Response.StoreForVoteResponseDTO;
import com.hongchelin.dto.Response.StoreResponseEntityDTO;
import com.hongchelin.service.StoreConverterService;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class VoteResultService {
    private final StoreForVoteRepositoryInterface storeForVoteRepository;
    private StoreConverterService storeConverterService;
    public VoteResultService(StoreForVoteRepositoryInterface storeForVoteRepository,
                             StoreConverterService storeConverterService) {
        this.storeForVoteRepository = storeForVoteRepository;
        this.storeConverterService = storeConverterService;
    }

    public ResponseEntity<StoreResponseEntityDTO> voteResult () {
        List<StoreForVote> voteList = getStoresForVote();

        return storeConverterService.convert(voteList);
    }

    public List<StoreForVote> getStoresForVote() {
        return storeForVoteRepository.findAll();
    }
}

투표조회

현재 투표 중인 가게들이 있는 DB 전체를 가져와 보여준다. 다만 투표 중인 가게들이 있는 DB 테이블은 정규화되어 있어 가게ID, 득표수만 표출할 수 있기 때문에 storeConverterService 객체를 호출하여 이를 사용자가 보기 좋게 바꿔 득표율 순으로 정렬한다.

 

package com.hongchelin.service;

import com.hongchelin.Domain.PastStoreForVote;
import com.hongchelin.Domain.Store;
import com.hongchelin.Domain.StoreForVote;
import com.hongchelin.Repository.StoreRepositoryInterface;
import com.hongchelin.dto.Response.StoreResponseDTO;
import com.hongchelin.dto.Response.StoreResponseEntityDTO;
import com.hongchelin.exceptions.CannotFoundDbElementException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class StoreConverterService {
    private final StoreRepositoryInterface storeRepository;

    public StoreConverterService(StoreRepositoryInterface storeRepository) {
        this.storeRepository = storeRepository;
    }

    public ResponseEntity<StoreResponseEntityDTO> convert(List<StoreForVote> storeForVotes) {

        List<StoreResponseDTO> storesList = storeForVotes.stream()
                .map(storeForVote -> {
                        Store store = storeRepository.findById(storeForVote.getStoreId());

                        if (store == null) {
                            throw new CannotFoundDbElementException();
                        }

                        return StoreResponseDTO.builder()
                            .storeId(store.getId())
                            .storeName(store.getStoreName())
                            .storeLocation(store.getStoreLocation())
                            .storeInfoOneline(store.getStoreInfoOneline())
                            .storeImg(store.getStoreImg())
                            .votedCount(storeForVote.getVotedCount())
                            .build();
                })
                .sorted((s1, s2) -> s2.getVotedCount() - s1.getVotedCount())
                .collect(Collectors.toList());

        StoreResponseEntityDTO storeResponseEntityDTO = StoreResponseEntityDTO.builder()
                .status(200)
                .message("성공")
                .stores(storesList)
                .build();

        return ResponseEntity
                .status(HttpStatus.OK)
                .body(storeResponseEntityDTO);
    }


    public ResponseEntity<StoreResponseEntityDTO> convertPast(List<PastStoreForVote> storeForVotes) {

        List<StoreResponseDTO> storesList = storeForVotes.stream()
                .map(pastStoreForVote -> {
                    Store store = storeRepository.findById(pastStoreForVote.getStoreId());

                    if (store == null) {
                        throw new CannotFoundDbElementException();
                    }

                    return StoreResponseDTO.builder()
                            .storeId(store.getId())
                            .storeName(store.getStoreName())
                            .storeLocation(store.getStoreLocation())
                            .storeInfoOneline(store.getStoreInfoOneline())
                            .storeImg(store.getStoreImg())
                            .votedCount(pastStoreForVote.getVotedCount())
                            .whenForVote(pastStoreForVote.getWhenForVote())
                            .isSelected(pastStoreForVote.isSelected())
                            .build();

                })
                .sorted((s1, s2) -> s2.getVotedCount() - s1.getVotedCount())
                .collect(Collectors.toList());

        StoreResponseEntityDTO storeResponseEntityDTO = StoreResponseEntityDTO.builder()
                .status(200)
                .message("성공")
                .stores(storesList)
                .build();

        return ResponseEntity
                .status(HttpStatus.OK)
                .body(storeResponseEntityDTO);
    }
}

컨버터

storeForVote와 pastStoreForVote 두 객체가 컨버터를 필요로하기 때문에 두 개의 메서드를 짰다. 제너릭 쓰면 좀 더 리팩토링이 쉬울 것 같은데 그럼 또 상속관계로 묶는 등의 일이 커지기 때문에 우선은 보류

 

투표후보들이 있는 DB에서 가져온 요소들을 리스트에 담아 컨버터에 보내면 스트림을 통해 이를 가게 정보를 담아 보낼 수 있도록 한다.

 

package com.hongchelin.service.Vote;

import com.hongchelin.Domain.PastStoreForVote;
import com.hongchelin.Domain.VoteRecord;
import com.hongchelin.Repository.PastStoreRepositoryInterface;
import com.hongchelin.Repository.VoteRecordRepository;
import com.hongchelin.dto.Response.PastStoreForVoteResponseDTO;
import com.hongchelin.exceptions.UnauthorizedException;
import com.hongchelin.service.JWT.JWTFilter;
import com.hongchelin.service.StoreConverterService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class AccessMyVoteService {
    private JWTFilter jwtFilter;
    private VoteRecordRepository voteRecordRepository;
    private PastStoreRepositoryInterface pastStoreRepository;
    private final StoreConverterService storeConverterService;

    public AccessMyVoteService(JWTFilter jwtFilter,
                               VoteRecordRepository voteRecordRepository,
                               PastStoreRepositoryInterface pastStoreRepository,
                               StoreConverterService storeConverterService) {
        this.jwtFilter = jwtFilter;
        this.voteRecordRepository = voteRecordRepository;
        this.pastStoreRepository = pastStoreRepository;
        this.storeConverterService = storeConverterService;
    }

    public ResponseEntity<PastStoreForVoteResponseDTO> accessMyVoteService(HttpServletRequest request, String secret) throws UnauthorizedException {
        boolean validity = jwtFilter.getTokenFromHeader(secret, request).getValidity();

        if (!validity) {
            throw new UnauthorizedException();
        }

        String userId = jwtFilter.getTokenFromHeader(secret, request).getMemberInfo().getIdentifier();

        List<VoteRecord> recordList = voteRecordRepository.findByUserId(userId);
        System.out.println(recordList);
        List<PastStoreForVote> pastStoreForVoteList = new ArrayList<>();

        for (VoteRecord record : recordList) {
            System.out.println(record);
            System.out.println(record.getVotedId());

            long votedId = record.getVotedId();
            String whenForVote = record.getWhenForVote();

            PastStoreForVote pastStoreForVote = pastStoreRepository.findByIdAndWhenForVote(votedId, whenForVote);
            pastStoreForVoteList.add(pastStoreForVote);
        }

        PastStoreForVoteResponseDTO pastStoreForVoteResponseDTO = PastStoreForVoteResponseDTO.builder()
                .status(200)
                .message("성공")
                .storeForPastVote(storeConverterService.convertPast(pastStoreForVoteList).getBody().getStores())
                .build();

        return ResponseEntity.ok(pastStoreForVoteResponseDTO);
    }
}

내투표조회하기

JWT토큰을 필요로한다.

 

voteRecord라는 별도의 DB테이블에 유저아이디와 가게id, 투표한 달의 정보가 들어있어 이를 가져온다.

 

package com.hongchelin.service;

import com.hongchelin.Domain.PastStoreForVote;
import com.hongchelin.Domain.Store;
import com.hongchelin.Domain.StoreForSelected;
import com.hongchelin.Domain.StoreForVote;
import com.hongchelin.Repository.PastStoreRepositoryInterface;
import com.hongchelin.Repository.StoreForSelectedRepository;
import com.hongchelin.Repository.StoreForVoteRepositoryInterface;
import com.hongchelin.Repository.StoreRepositoryInterface;
import com.hongchelin.dto.user.ResponseDTO;
import jakarta.transaction.Transactional;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ModifyDBInEndDayService {
    private final StoreForSelectedRepository storeForSelectedRepository;
    private final StoreForVoteRepositoryInterface storeForVoteRepository;
    private final StoreRepositoryInterface storeRepository;
    private final PastStoreRepositoryInterface pastStoreRepository;
    Date date = new Date();

    public ModifyDBInEndDayService(StoreForVoteRepositoryInterface storeForVoteRepository,
                                   StoreRepositoryInterface storeRepository,
                                   StoreForSelectedRepository storeForSelectedRepository,
                                   PastStoreRepositoryInterface pastStoreRepository) {
        this.storeForVoteRepository = storeForVoteRepository;
        this.storeRepository = storeRepository;
        this.storeForSelectedRepository = storeForSelectedRepository;
        this.pastStoreRepository = pastStoreRepository;
    }

    @Transactional
    @Scheduled(cron = "* 05 00 1 * *")
    public /*ResponseEntity<ResponseDTO>*/ void modifyInEnd() {
        List<StoreForVote> stores = storeForVoteRepository.findTop3ByOrderByVotedCountDesc();
        List<StoreForSelected> selectedList = new ArrayList<>();
        List<PastStoreForVote> unSelectedList = new ArrayList<>();
        List<PastStoreForVote> selected = new ArrayList<>();

        for (StoreForVote store : stores) {
            long storeId = store.getStoreId();
            Store individualizedStore = storeRepository.findById(storeId);

            long selectedStoreId = individualizedStore.getId();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
            String whenForSelected = formatter.format(date);

            Integer votedCount = store.getVotedCount();

            StoreForSelected storeForSelected = StoreForSelected.builder()
                    .WhenSelected(whenForSelected)
                    .idInDb(selectedStoreId)
                    .votedCount(votedCount)
                    .build();

            selectedList.add(storeForSelected);

            /* 여기서부터는 PAST_FOR_STORE 에 추가할 부분입니다.*/
            PastStoreForVote pastStoreForVote = PastStoreForVote.builder()
                    .isSelected(true)
                    .whenForVote(whenForSelected)
                    .storeId(storeForSelected.getIdInDb())
                    .votedCount(storeForSelected.getVotedCount())
                    .build();

            selected.add(pastStoreForVote);
        }

        for (PastStoreForVote pastStoreForVote : selected) {
            long storeId = pastStoreForVote.getStoreId();

            pastStoreRepository.save(pastStoreForVote);
            storeForVoteRepository.deleteByStoreId(storeId);
        }

        Iterable<StoreForVote> storeForVotes = storeForVoteRepository.findAll();

        for (StoreForVote storeForVote : storeForVotes) {
            Store individualizedStore = storeRepository.findById(storeForVote.getStoreId());

            long selectedStoreId = individualizedStore.getId();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
            String whenForSelected = formatter.format(date);

            Integer votedCount = storeForVote.getVotedCount();

            PastStoreForVote pastStoreForVote = PastStoreForVote.builder()
                    .whenForVote(whenForSelected)
                    .storeId(selectedStoreId)
                    .votedCount(votedCount)
                    .isSelected(false)
                    .build();

            unSelectedList.add(pastStoreForVote);
        }

        for (StoreForSelected store : selectedList) {
            storeForSelectedRepository.save(store);
        }

        for (PastStoreForVote pastStoreForVote : unSelectedList) {
            pastStoreRepository.save(pastStoreForVote);
            storeForVoteRepository.deleteByStoreId(pastStoreForVote.getStoreId());
        }

        ResponseDTO responseDTO = ResponseDTO.builder()
                .status(200)
                .message("성공")
                .build();

        //return ResponseEntity.ok(responseDTO);
    }
}

코드 리팩토링 좀 할 걸 그랬나

매달 1일 0시 5분에 기존 투표후보들 중에서 득표율 상위 3개의 가게만 뽑아 홍슐랭으로 선정한 뒤 선정된 가게들이 있는 db로 따로 이동시키고, 투표후보들은 선정여부 담아서 과거투표기록용 DB테이블로 이동시킨 다음 투표후보들이 있는 DB 테이블을 지움. 즉, 기존 지난달 투표를 정리하고 새로운 투표를 받기 위한 사전작업의 자동화

 

구현 중 오류

- 회원가입

 

 

- 로그인

 

- 투표

 

 

'팀 프로젝트 > [2025][GDG]홍대 맛집 아카이빙 프로젝트' 카테고리의 다른 글

[GDG] GDG 프로젝트 트랙 4기 FIL  (0) 2025.09.02
[GDG] GDG 프로젝트트랙 4기 백엔드 후기  (6) 2025.08.28
[GDG] 개발코스 6주차 WIL  (0) 2025.08.20
[GDG] 홍대 맛집 아카이빙 프로젝트 #21 - 카카오지도 API 짧게  (2) 2025.08.18
[GDG] 홍대 맛집 아카이빙 프로젝트 #20 - mySQL과 각종 코드 보강하기  (6) 2025.08.18
'팀 프로젝트/[2025][GDG]홍대 맛집 아카이빙 프로젝트' 카테고리의 다른 글
  • [GDG] GDG 프로젝트 트랙 4기 FIL
  • [GDG] GDG 프로젝트트랙 4기 백엔드 후기
  • [GDG] 개발코스 6주차 WIL
  • [GDG] 홍대 맛집 아카이빙 프로젝트 #21 - 카카오지도 API 짧게
윤마치
윤마치
개발을 합니다.
  • 윤마치
    윤마치
    윤마치
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • 링크

      • 컬러잇 개발블로그
    • 공지사항

    • 인기 글

    • 태그

      144
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.5
    윤마치
    [GDG] 홍대 맛집 아카이빙 프로젝트 #22 - 데모데이 발표자료 준비
    상단으로

    티스토리툴바