Skip to content

Commit

Permalink
[Feat] 선착순 기능 구현 (#113)
Browse files Browse the repository at this point in the history
* [Infra] CI/CD test (#42)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* [Infra] CI CD test 3 (#45)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* Infra: environment 삭제

* config: jwt 속성을 yml에 설정

* rebase: 원본 develop 브랜치와 병합

* feat: FcfsException 클래스 구현

* feat: Fcfs 퀴즈 화면 응답 dto 구현

* feat: 선착순 페이지 접근을 관리하는 인터셉터 구현

* feat: 선착순 퀴즈 entity 클래스 구현

* feat: 선착순 퀴즈 dto 클래스 구현

* feat: 선착순 퀴즈 repository 클래스 구현

* feat: 인터셉터 등록

* feat: 선착순 정적 텍스트 등록

* feat: 선착순 동적 텍스트 바인딩

* feat: swagger에서 파라미터가 보이지 않도록 설정

* refactor: 이벤트 지표 응답 dto 수정

- 이벤트 시작, 종료 날짜를 DrawSettingManager에서 가져오도록 수정
- 각 이벤트 참여 비율 계산 시, 분모가 0이 되는 경우를 처리

* refactor: 사용하지 않는 메서드 삭제

* chore: 임시로 주석처리

* feat: 선착순 컨트롤러 메서드 구현

- 선착순 튜토리얼 페이지 정보를 제공하는 메서드 구현
- 선착순 결과를 응답하는 메서드 구현

* refactor: 패키지 변경

* feat: 선착순 당첨 실패 응답 dto에 필드 추가

* chore: import문 삭제

* feat: 선착순 퀴즈 페이지 정보를 제공하는 메서드 구현

* feat: 선착순 설정 매니저에서 메서드 추가

- 선착순 당첨가능한 수를 반환하는 메서드
- 다음 선착순 게임에서 사용될 힌트 반환하는 메서드
- 현재 선착순 게임의 퀴즈 정보를 반환하는 메서드
- 선착순 페이지에 접근 가능한지 여부를 반환하는 메서드
- 현재 선착순 게임이 몇 라운드인지를 반환하는 메서드

* refactor: 사용하지 않는 메서드 삭제

* feat: 선착순 당첨 응답 dto에 필드 추가

* refactor: json format에서 시간값 형식 변경

* feat: 메인 페이지 응답 dto에 선착순 힌트 필드 추가

* feat: 메서드에 파라미터 추가

* feat: 이벤트 페이지에 선착순 힌트를 설정

* Revert "어드민 기능 인덱스 에러 수정 및 선착순 기능 일부 구현 (#106)" (#107)

This reverts commit ceb48fa.

* [Infra] CI/CD test (#42)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* [Infra] CI CD test 3 (#45)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* Infra: environment 삭제

* rebase: 원본 repo의 develop 브랜치와 충돌 rebase

* feat: 매개변수 swagger에서 나타나지 않도록 설정

* [Infra] CI/CD test (#42)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* [Infra] CI CD test 3 (#45)

* infra: 빌드 테스트 yml 작성

* infra: DB 정보 추가

* infra: ssh-agent 버전 변경

* infra: known_hosts 추가

* infra: db port 변경

* infra: database test 설정 변경

* infra: DB 환경변수 설정 및 application.yml 생성

* infra: application.yml 동적 생성 스크립트 수정

* infra: 레디스 설정 추가

* infra: redis test 추가

* infra: redis 버전 변경

* infra: redis cli 설치

* infra: application.yml 위치 및 내용 확인

* infra: Github Actions 환경변수에 REDIS_HOST, REDIS_PORT 추가

* infra: 환경변수 확인 추가

* infra: zip file 만들기 추가, AWS credentials 추가

* infra: 환경변수 이름 변경

- ARN -> AWS_ARN

* infra: s3 bucket에 업로드 추가

* infra: code deploy 추가

* infra: code deploy 수정

* infra: code deploy 수정

* infra: appspec.yml 작성

* infra: application.yml 생성 경로 변경

* infra: application.yml 확인 스크립트 삭제

* infra: application.yml 생성 스크립트 수정

* infra: application-prod.yml 추가

* infra: appspec.yml 수정, 배포를 위한 sh파일 추가

* infra: deploy.yml 이름 변경

- test_deploy -> deploy

* infra: body = null 설정

* infra: develop에 머지되었을 때만 발동하도록 수정

* feat: draw_rank column 이름 수정

* Infra: environment 삭제

* Infra: environment 삭제

* config: jwt 속성을 yml에 설정

* rebase: 원본 develop 브랜치와 병합

* feat: FcfsException 클래스 구현

* feat: Fcfs 퀴즈 화면 응답 dto 구현

* feat: 선착순 페이지 접근을 관리하는 인터셉터 구현

* feat: 선착순 퀴즈 entity 클래스 구현

* feat: 선착순 퀴즈 dto 클래스 구현

* feat: 선착순 퀴즈 repository 클래스 구현

* feat: 인터셉터 등록

* feat: 선착순 정적 텍스트 등록

* feat: 선착순 동적 텍스트 바인딩

* refactor: 이벤트 지표 응답 dto 수정

- 이벤트 시작, 종료 날짜를 DrawSettingManager에서 가져오도록 수정
- 각 이벤트 참여 비율 계산 시, 분모가 0이 되는 경우를 처리

* refactor: 사용하지 않는 메서드 삭제

* chore: 임시로 주석처리

* feat: 선착순 컨트롤러 메서드 구현

- 선착순 튜토리얼 페이지 정보를 제공하는 메서드 구현
- 선착순 결과를 응답하는 메서드 구현

* refactor: 패키지 변경

* feat: 선착순 당첨 실패 응답 dto에 필드 추가

* chore: import문 삭제

* feat: 선착순 퀴즈 페이지 정보를 제공하는 메서드 구현

* feat: 선착순 설정 매니저에서 메서드 추가

- 선착순 당첨가능한 수를 반환하는 메서드
- 다음 선착순 게임에서 사용될 힌트 반환하는 메서드
- 현재 선착순 게임의 퀴즈 정보를 반환하는 메서드
- 선착순 페이지에 접근 가능한지 여부를 반환하는 메서드
- 현재 선착순 게임이 몇 라운드인지를 반환하는 메서드

* refactor: 사용하지 않는 메서드 삭제

* feat: 선착순 당첨 응답 dto에 필드 추가

* feat: 메인 페이지 응답 dto에 선착순 힌트 필드 추가

* feat: 메서드에 파라미터 추가

* feat: 이벤트 페이지에 선착순 힌트를 설정

* feat: 선착순 redis util 클래스 구현

* refactor: FcfsRedisUtil을 사용하도록 변경

* feat: 추첨 이벤트 시간을 변경하는 메서드 구현

* feat: 추첨 시간을 변경하는 코드 삽입

* feat: EventLock 예외가 발생하면 redirect 하도록 구현

* feat: 선착순 entity에 code 필드 추가

* feat: 선착순 code값과 당첨여부를 redirect하는 기능 구현

* feat: 선착순 등록 로직 구현

* feat: ScheduledFuture import

* feat: 선착순 관련 redis key 상수 추가

* feat: 어드민 페이지 cors 설정

* feat: 선착순 fcfsClosed 변수를 false로 초가화

* feat: integer 레디스 템플릿으로 hash값 저장

* feat: 에러 로그 추가

* refactor: list 초기화

* refactor: get, post요청 모두 round값 전달

* feat: hash 키, 값 serializer 등록

---------

Co-authored-by: DrRivaski <[email protected]>
Co-authored-by: hyeokson <[email protected]>
  • Loading branch information
3 people authored Aug 15, 2024
1 parent 0b575f8 commit b286b97
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ private void updateDrawSetting(DrawSetting drawSetting, LocalDate startDate, Loc

drawSetting.setStartDate(startDateOfDraw);
drawSetting.setEndDate(endDateOfDraw);

drawSettingManager.setDrawDate(drawSetting);
}

public void updateDrawEventTime(DrawEventTimeRequestDto drawEventTimeRequestDto) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ private void addWinnerToDatabase() {
}
}

public void setDrawDate(DrawSetting drawSetting) {
this.startDate = drawSetting.getStartDate();
this.endDate = drawSetting.getEndDate();
}

public void setDrawTime(DrawSetting drawSetting) {
this.startTime = drawSetting.getStartTime();
this.endTime = drawSetting.getEndTime();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,28 @@ public String handleFcfs(@Parameter(hidden = true) HttpServletRequest request,

int round = (Integer) request.getAttribute("round");

// boolean isFcfsWinner = fcfsService.handleFcfsEvent(userId, round, answer);
//
// // 리다이렉트 시 쿼리 파라미터를 추가하여 정보 전달
// redirectAttributes.addAttribute("fcfsWin", isFcfsWinner);
String fcfsCode = fcfsService.handleFcfsEvent(userId, round, answer);

if(fcfsCode != null){
request.getSession().setAttribute("fcfsCode", fcfsCode);

redirectAttributes.addAttribute("fcfsWin", true);
}
else{
redirectAttributes.addAttribute("fcfsWin", false);
}

// GET 요청으로 리다이렉트
return "redirect:/fcfs/result";
}

@GetMapping("/result")
@ResponseBody
public ResponseDto<FcfsResponseDto> getFcfsResult(@RequestParam("fcfsWin") Boolean fcfsWin){
FcfsResponseDto fcfsResponseDto = fcfsService.getFcfsResult(fcfsWin);
public ResponseDto<FcfsResponseDto> getFcfsResult(@Parameter(hidden = true) HttpServletRequest request,
@RequestParam("fcfsWin") Boolean fcfsWin){

String fcfsCode = (String) request.getSession().getAttribute("fcfsCode");

FcfsResponseDto fcfsResponseDto = fcfsService.getFcfsResult(fcfsWin, fcfsCode);

return ResponseDto.onSuccess(fcfsResponseDto);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public class Fcfs {
@Column(name = "round")
private int round;

@Column(name = "code")
private String code;

@CreatedDate
@Column(name = "winning_date", nullable = false)
private LocalDateTime winningDate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
throw new FcfsException(ErrorStatus._BAD_REQUEST);
}

if(request.getMethod().equals("GET")){
int round = fcfsSettingManager.getFcfsRound(now);
request.setAttribute("round", round);
}

int round = fcfsSettingManager.getFcfsRound(now);
request.setAttribute("round", round);


return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
package com.softeer.backend.fo_domain.fcfs.service;

import com.softeer.backend.fo_domain.fcfs.domain.Fcfs;
import com.softeer.backend.fo_domain.fcfs.dto.*;
import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsFailResponseDto;
import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResponseDto;
import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsSuccessResponseDto;
import com.softeer.backend.fo_domain.fcfs.exception.FcfsException;
import com.softeer.backend.fo_domain.fcfs.repository.FcfsRepository;
import com.softeer.backend.fo_domain.user.domain.User;
import com.softeer.backend.fo_domain.user.exception.UserException;
import com.softeer.backend.fo_domain.user.repository.UserRepository;
import com.softeer.backend.global.annotation.EventLock;
import com.softeer.backend.global.common.code.status.ErrorStatus;
import com.softeer.backend.global.common.constant.RedisKeyPrefix;
import com.softeer.backend.global.staticresources.util.StaticResourcesUtil;
import com.softeer.backend.global.util.EventLockRedisUtil;
import com.softeer.backend.global.util.FcfsRedisUtil;
import com.softeer.backend.global.util.RandomCodeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.stereotype.Service;

import java.util.Set;

/**
* 선착순 관련 이벤트를 처리하는 클래스
*/
Expand All @@ -20,10 +33,9 @@
public class FcfsService {

private final FcfsSettingManager fcfsSettingManager;
private final FcfsRepository fcfsRepository;
private final EventLockRedisUtil eventLockRedisUtil;
private final UserRepository userRepository;
private final FcfsRedisUtil fcfsRedisUtil;
private final StaticResourcesUtil staticResourcesUtil;
private final RandomCodeUtil randomCodeUtil;


public FcfsPageResponseDto getFcfsPage(int round) {
Expand Down Expand Up @@ -55,60 +67,78 @@ public FcfsPageResponseDto getFcfsTutorialPage() {
* 1. 선착순 당첨자가 아직 다 결정되지 않았으면, 선착순 당첨 응답 생성 및 반환
* 2. 선착순 당첨자가 다 결정됐다면, Redisson lock을 사용하지 않고 Redis에 저장된 선착순 이벤트 참여자 수를 1명씩 더한다.
*/
// public FcfsResponseDto handleFcfsEvent(int userId, int round, String answer) {
// if (fcfsSettingManager.isFcfsClosed())
// return countFcfsParticipant(fcfsSettingManager.getRound());
//
// return saveFcfsWinners(userId, fcfsSettingManager.getRound());
// }
public String handleFcfsEvent(int userId, int round, String answer) {

/**
* 1. Redisson lock을 걸고 선착순 이벤트 참여자 수가 지정된 수보다 적다면, 선착순 당첨 정보를 DB에 저장하고
* Redis에 저장된 선착순 이벤트 참여자 수를 1만큼 증가시키도 선착순 당첨 응답을 생성하여 반환한다.
* 만약, 참여자 수가 총 당첨자 수와 같아졌으면, fcfsSettingManager의 setFcfsClosed를 true로 변환한다.
* 2. setFcfsClosed가 true로 바뀌게 전에 요청이 들어왔다면, 선착순 실패 응답을 생성하여 반환한다.
*/
// @EventLock(key = "FCFS_WINNER_#{#round}")
// private FcfsResponseDto saveFcfsWinners(int userId, int round) {
// Set<Integer> participantIds = eventLockRedisUtil.getAllDataAsSet(RedisLockPrefix.FCFS_LOCK_PREFIX.getPrefix() + round);
//
// if (participantIds.size() < fcfsSettingManager.getWinnerNum() &&
// !eventLockRedisUtil.isParticipantExists(RedisLockPrefix.FCFS_LOCK_PREFIX.getPrefix() + round, userId)) {
// User user = userRepository.findById(userId)
// .orElseThrow(() -> {
// log.error("user not found in saveFcfsWinners method.");
// return new UserException(ErrorStatus._NOT_FOUND);
// });
//
// Fcfs fcfs = Fcfs.builder()
// .user(user)
// .round(round)
// .build();
// fcfsRepository.save(fcfs);
//
// eventLockRedisUtil.incrementParticipantCount(RedisLockPrefix.FCFS_PARTICIPANT_COUNT_PREFIX.getPrefix() + round);
// if (participantIds.size() + 1 == fcfsSettingManager.getWinnerNum()) {
// fcfsSettingManager.setFcfsClosed(true);
// }
//
// return new FcfsSuccessResponseDto(1);
// }
//
// return new FcfsFailResponseDtoDto(1);
// }

public FcfsResponseDto getFcfsResult(boolean fcfsWin){
// if(fcfsWin){
// return FcfsSuccessResponseDto.builder()
// .title(staticResourcesUtil.getData("FCFS_WINNER_TITLE"))
// .subTitle(staticResourcesUtil.getData("FCFS_WINNER_SUBTITLE"))
// .qrCode(staticResourcesUtil.getData("barcode_image"))
// .codeWord(staticResourcesUtil.getData("FCFS_WINNER_CODE_WORD"))
// .fcfsCode()
// .expirationDate(staticResourcesUtil.getData("FCFS_WINNER_EXPIRY_DATE"))
// .caution(staticResourcesUtil.getData("FCFS_WINNER_CAUTION"))
// .build();
// }
if(!answer.equals(fcfsSettingManager.getQuiz(round).getAnswerWord())) {
log.error("fcfs quiz answer is not match, correct answer: {}, wrong anwer: {}",
fcfsSettingManager.getQuiz(round).getAnswerWord(), answer);
throw new FcfsException(ErrorStatus._BAD_REQUEST);
}

if (fcfsSettingManager.isFcfsClosed()){
countFcfsParticipant(round);

return null;
}

return saveFcfsWinners(userId, round);
}

@EventLock(key = "FCFS_WINNER_#{#round}")
private String saveFcfsWinners(int userId, int round) {

long numOfWinners = fcfsRedisUtil.getIntegerSetSize(RedisKeyPrefix.FCFS_LOCK_PREFIX.getPrefix() + round);

if (numOfWinners < fcfsSettingManager.getFcfsWinnerNum()
&& !fcfsRedisUtil.isValueInIntegerSet(RedisKeyPrefix.FCFS_LOCK_PREFIX.getPrefix() + round, userId)) {

// redis에 userId 등록
fcfsRedisUtil.addToIntegerSet(RedisKeyPrefix.FCFS_LOCK_PREFIX.getPrefix() + round, userId);

// redis에 code 등록
String code = makeFcfsCode(round);
while(fcfsRedisUtil.isValueInStringSet(RedisKeyPrefix.FCFS_CODE_PREFIX.getPrefix() + round, code)){
code = makeFcfsCode(round);
}
fcfsRedisUtil.addToStringSet(RedisKeyPrefix.FCFS_CODE_PREFIX.getPrefix() + round, code);

// redis에 code-userId 형태로 등록(hash)
fcfsRedisUtil.addToHash(RedisKeyPrefix.FCFS_CODE_USERID_PREFIX.getPrefix() + round, code, userId);

// redis에 선착순 참가자 수 +1
countFcfsParticipant(round);

// 선착순 당첨이 마감되면 FcfsSettingManager의 fcfsClodes 변수값을 true로 설정
if (numOfWinners + 1 == fcfsSettingManager.getFcfsWinnerNum()) {
fcfsSettingManager.setFcfsClosed(true);
}

return code;
}

return null;
}

private String makeFcfsCode(int round){
return (char)('A'+round-1) + randomCodeUtil.generateRandomCode(5);
}

private void countFcfsParticipant(int round) {
fcfsRedisUtil.incrementValue(RedisKeyPrefix.FCFS_PARTICIPANT_COUNT_PREFIX.getPrefix() + round);
}

public FcfsResponseDto getFcfsResult(boolean fcfsWin, String fcfsCode){
if(fcfsWin){
return FcfsSuccessResponseDto.builder()
.title(staticResourcesUtil.getData("FCFS_WINNER_TITLE"))
.subTitle(staticResourcesUtil.getData("FCFS_WINNER_SUBTITLE"))
.qrCode(staticResourcesUtil.getData("barcode_image"))
.codeWord(staticResourcesUtil.getData("FCFS_WINNER_CODE_WORD"))
.fcfsCode(fcfsCode)
.expirationDate(staticResourcesUtil.getData("FCFS_WINNER_EXPIRY_DATE"))
.caution(staticResourcesUtil.getData("FCFS_WINNER_CAUTION"))
.build();
}

return FcfsFailResponseDto.builder()
.title(staticResourcesUtil.getData("FCFS_LOSER_TITLE"))
Expand All @@ -117,4 +147,6 @@ public FcfsResponseDto getFcfsResult(boolean fcfsWin){
.build();
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;

/**
* 선착순 이벤트 정보를 관리하는 클래스
Expand Down Expand Up @@ -60,7 +59,7 @@ public FcfsSettingDto getFcfsSettingByRound(int round) {
public void loadInitialData() {

List<FcfsSetting> fcfsSettings = fcfsSettingRepository.findAll();
fcfsSettingList = new ArrayList<>(4);
fcfsSettingList = new ArrayList<>();

for (int i = 0; i < 4; i++) {
fcfsSettingList.add(null); // 인덱스 0부터 3까지 빈 슬롯을 추가
Expand All @@ -76,11 +75,7 @@ public void loadInitialData() {
});

List<Quiz> quizs = quizRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
quizList = new ArrayList<>(4);

for (int i = 0; i < 4; i++) {
quizList.add(null); // 인덱스 0부터 3까지 빈 슬롯을 추가
}
quizList = new ArrayList<>();

quizs.forEach((quiz) -> {

Expand Down Expand Up @@ -157,7 +152,7 @@ public String getHint(){
}

public QuizDto getQuiz(int round){

log.info("quiz: {}", quizList.get(round-1));
return quizList.get(round - 1);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@

@Getter
public enum RedisKeyPrefix {
// 선착순
FCFS_LOCK_PREFIX("LOCK:FCFS_WINNER_"),
FCFS_CODE_PREFIX("FCFS_CODE_"),
FCFS_CODE_USERID_PREFIX("FCFS_CODE_USERID_"),
FCFS_PARTICIPANT_COUNT_PREFIX("FCFS_PARTICIPANT_COUNT_"),

// 추첨
DRAW_LOCK_PREFIX("LOCK:DRAW_WINNER"),
DRAW_WINNER_LIST_PREFIX("DRAW_WINNER_LIST_"),
FCFS_PARTICIPANT_COUNT_PREFIX("FCFS_PARTICIPANT_COUNT_"),
DRAW_PARTICIPANT_COUNT_PREFIX("DRAW_PARTICIPANT_COUNT"),

// 사이트 방문자 수
TOTAL_VISITORS_COUNT_PREFIX("TOTAL_VISITORS_COUNT_");


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.*;
Expand All @@ -39,7 +40,7 @@ public ResponseEntity<Object> handleGeneralException(GeneralException generalExc
}

@ExceptionHandler
public ResponseEntity<Object> handleEventLockException(EventLockException eventLockException, WebRequest webRequest) {
public ModelAndView handleEventLockException(EventLockException eventLockException, WebRequest webRequest) {
return handleEventLockExceptionInternal(eventLockException, HttpHeaders.EMPTY, webRequest);
}

Expand Down Expand Up @@ -129,27 +130,24 @@ private ResponseEntity<Object> handleGeneralExceptionInternal(Exception e, Respo
}

// EventLockException에 대한 client 응답 객체를 생성하는 메서드
private ResponseEntity<Object> handleEventLockExceptionInternal(EventLockException e, HttpHeaders headers, WebRequest webRequest) {
private ModelAndView handleEventLockExceptionInternal(EventLockException e, HttpHeaders headers, WebRequest webRequest) {

log.error("EventLockException captured in ExceptionAdvice", e);

String redissonKeyName = e.getRedissonKeyName();

ResponseDto<Object> body = null;
ModelAndView modelAndView = new ModelAndView();

// if (redissonKeyName.contains("FCFS"))
// body = ResponseDto.onSuccess(new FcfsFailResponseDtoDto(1));
if (redissonKeyName.contains("FCFS")){

modelAndView.setViewName("redirect:/fcfs/result");
modelAndView.addObject("fcfsWin", false);
}

//TODO
// DRAW 관련 예외일 경우, body 구성하는 코드 필요

return super.handleExceptionInternal(
e,
body,
headers,
HttpStatus.OK,
webRequest
);
return modelAndView;
}

// ConstraintViolationException에 대한 client 응답 객체를 생성하는 메서드
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFac

template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));

template.setHashKeySerializer(new StringRedisSerializer());

template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));

return template;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public void addInterceptors(InterceptorRegistry registry) {
public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**")
.allowedOrigins("https://softeer.site", "http://localhost:5173", "https://softeer.shop") // 허용할 도메인 설정
.allowedOrigins("https://softeer.site", "http://localhost:5173", "https://softeer.shop",
"https://d3qmq1ffhp5il9.cloudfront.net") // 허용할 도메인 설정
.allowedMethods("OPTIONS", "GET", "POST", "PUT", "DELETE") // 허용할 HTTP 메서드 설정
.allowedHeaders("Content-Type", "Authorization", "Authorization-Refresh") // 허용할 헤더 설정
.exposedHeaders("Authorization", "Authorization-Refresh") // 클라이언트에 노출할 헤더 설정
Expand Down
Loading

0 comments on commit b286b97

Please sign in to comment.