From cf3f1e437e8e47544ce8c18af7dd8c8b36cff6df Mon Sep 17 00:00:00 2001 From: Son Chanhyeok <127181634+hyeokson@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:14:59 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20=EC=A0=95=EC=A0=81=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=BA=90=EC=8B=B1=ED=95=98=EA=B8=B0=20(#161)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [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: Caffeine cache 설정 * feat: 메인페이지 이벤트 정보 응답 dto 구현 * feat: s3 파일 이름을 enum으로 관리하도록 구현 * feat: static 자원 util 클래스 구현 * feat: 정적 텍스트 entity 구현 * feat: 정적 텍스트 repository 구현 * config: 의존성 설정 - spring cache 설정 - caffeine cache 설정 * chore: import문 삭제 * refactor: 정적 자원 가져오는 로직 변경 * refactor: 클래스 삭제 * feat: etag 필터 등록 * feat: 정적 텍스트의 이름을 관리하는 enum 구현 * refactor: 문자열을 상수로 관리 * feat: s3content repository 구현 * refactor: DB 테이블명 변경 * refactor: redis key 상수 변경 * refactor: 전화번호 regex 변경 * refactor: 코드 리팩토링 * refactor: 필드 삭제 * feat: 이벤트 페이지 정보를 응답하는 메서드 구현 * feat: 인증검사를 하지 않는 url 설정 * feat: setter 설정 * feat: 선착순 결과 캐싱하기 * refactor: redirect 하지 않도록 변경 * refactor: 정적 자원 가져오는 로직 변경 * refactor: 문자열을 상수로 관리 * [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: Caffeine cache 설정 * feat: 메인페이지 이벤트 정보 응답 dto 구현 * feat: s3 파일 이름을 enum으로 관리하도록 구현 * feat: static 자원 util 클래스 구현 * feat: 정적 텍스트 entity 구현 * feat: 정적 텍스트 repository 구현 * config: 의존성 설정 - spring cache 설정 - caffeine cache 설정 * chore: import문 삭제 * refactor: 정적 자원 가져오는 로직 변경 * refactor: 클래스 삭제 * feat: etag 필터 등록 * feat: 정적 텍스트의 이름을 관리하는 enum 구현 * rebase: 원본 repo develop 브랜치와 충돌 해결 * feat: s3content repository 구현 * refactor: DB 테이블명 변경 * refactor: redis key 상수 변경 * refactor: 전화번호 regex 변경 * refactor: 코드 리팩토링 * refactor: 필드 삭제 * feat: 이벤트 페이지 정보를 응답하는 메서드 구현 * feat: 인증검사를 하지 않는 url 설정 * feat: setter 설정 * feat: 선착순 결과 캐싱하기 * refactor: redirect 하지 않도록 변경 * refactor: 정적 자원 가져오는 로직 변경 * refactor: 문자열을 상수로 관리 * refactor: 변수명 변경 --------- Co-authored-by: DrRivaski <48974215+DrRivaski@users.noreply.github.com> Co-authored-by: hyeokson --- build.gradle | 6 + .../softeer/backend/BackendApplication.java | 1 + .../serializer/PhoneNumberSerializer.java | 2 +- .../draw/util/DrawModalGenerateUtil.java | 64 +-- .../draw/util/DrawResponseGenerateUtil.java | 7 +- .../backend/fo_domain/draw/util/DrawUtil.java | 38 +- .../fcfs/controller/FcfsController.java | 34 +- .../fcfs/dto/result/FcfsSuccessResult.java | 1 + .../fo_domain/fcfs/service/FcfsService.java | 102 +++-- .../controller/MainPageController.java | 32 +- .../dto/MainPageEventInfoResponseDto.java | 28 ++ ...va => MainPageEventStaticResponseDto.java} | 17 +- .../mainpage/service/MainPageService.java | 372 +++++++++++------- .../share/service/ShareUrlInfoService.java | 7 +- .../common/constant/RedisKeyPrefix.java | 2 +- .../global/config/cache/CacheConfig.java | 34 ++ .../global/config/web/WebMvcConfig.java | 9 + .../filter/JwtAuthenticationFilter.java | 2 +- .../staticresources/constant/S3FileName.java | 37 ++ .../staticresources/constant/StaticText.java | 130 ------ .../constant/StaticTextName.java | 98 +++++ .../{StaticResources.java => S3Content.java} | 7 +- .../staticresources/domain/TextContent.java | 26 ++ .../repository/S3ContentRepository.java | 8 + .../repository/StaticResourcesRepository.java | 7 - .../repository/TextContentRepository.java | 7 + .../util/StaticResourceUtil.java | 60 +++ .../util/StaticResourcesUtil.java | 119 ------ 28 files changed, 735 insertions(+), 522 deletions(-) create mode 100644 src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java rename src/main/java/com/softeer/backend/fo_domain/mainpage/dto/{MainPageEventResponseDto.java => MainPageEventStaticResponseDto.java} (66%) create mode 100644 src/main/java/com/softeer/backend/global/config/cache/CacheConfig.java create mode 100644 src/main/java/com/softeer/backend/global/staticresources/constant/S3FileName.java delete mode 100644 src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java create mode 100644 src/main/java/com/softeer/backend/global/staticresources/constant/StaticTextName.java rename src/main/java/com/softeer/backend/global/staticresources/domain/{StaticResources.java => S3Content.java} (73%) create mode 100644 src/main/java/com/softeer/backend/global/staticresources/domain/TextContent.java create mode 100644 src/main/java/com/softeer/backend/global/staticresources/repository/S3ContentRepository.java delete mode 100644 src/main/java/com/softeer/backend/global/staticresources/repository/StaticResourcesRepository.java create mode 100644 src/main/java/com/softeer/backend/global/staticresources/repository/TextContentRepository.java create mode 100644 src/main/java/com/softeer/backend/global/staticresources/util/StaticResourceUtil.java delete mode 100644 src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java diff --git a/build.gradle b/build.gradle index 8b29a9e9..0aeecfa8 100644 --- a/build.gradle +++ b/build.gradle @@ -97,6 +97,12 @@ dependencies { // Bcrypt 설정 implementation 'org.mindrot:jbcrypt:0.4' + // Spring Cache 설정 + implementation 'org.springframework.boot:spring-boot-starter-cache' + + // Caffeine Cache 설정 + implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8' + compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/softeer/backend/BackendApplication.java b/src/main/java/com/softeer/backend/BackendApplication.java index cd93086e..d87c320f 100644 --- a/src/main/java/com/softeer/backend/BackendApplication.java +++ b/src/main/java/com/softeer/backend/BackendApplication.java @@ -3,6 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; diff --git a/src/main/java/com/softeer/backend/bo_domain/admin/serializer/PhoneNumberSerializer.java b/src/main/java/com/softeer/backend/bo_domain/admin/serializer/PhoneNumberSerializer.java index 9ca88b5a..fe31768b 100644 --- a/src/main/java/com/softeer/backend/bo_domain/admin/serializer/PhoneNumberSerializer.java +++ b/src/main/java/com/softeer/backend/bo_domain/admin/serializer/PhoneNumberSerializer.java @@ -11,7 +11,7 @@ public class PhoneNumberSerializer extends JsonSerializer { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - String formatted = value.replaceAll("(\\d{3})(\\d{3})(\\d+)", "$1-$2-$3"); + String formatted = value.replaceAll("(\\d{3})(\\d{4})(\\d+)", "$1-$2-$3"); gen.writeString(formatted); } } \ No newline at end of file diff --git a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawModalGenerateUtil.java b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawModalGenerateUtil.java index be65c3b7..a35f5d3e 100644 --- a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawModalGenerateUtil.java +++ b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawModalGenerateUtil.java @@ -1,63 +1,75 @@ package com.softeer.backend.fo_domain.draw.util; import com.softeer.backend.fo_domain.draw.dto.modal.WinModal; -import com.softeer.backend.global.staticresources.util.StaticResourcesUtil; +import com.softeer.backend.global.staticresources.constant.S3FileName; +import com.softeer.backend.global.staticresources.constant.StaticTextName; +import com.softeer.backend.global.staticresources.util.StaticResourceUtil; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; +import java.util.Map; + @Component @RequiredArgsConstructor public class DrawModalGenerateUtil { - private final StaticResourcesUtil staticResourcesUtil; + + private final StaticResourceUtil staticResourceUtil; /** * @return 등수에 따른 WinModal을 반환 */ + @Cacheable(value = "staticResources", key = "'draw_modal_' + #ranking") public WinModal generateWinModal(int ranking) { + + Map textContentMap = staticResourceUtil.getTextContentMap(); + Map s3ContentMap = staticResourceUtil.getS3ContentMap(); + if (ranking == 1) { - return generateFirstWinModal(); + return generateFirstWinModal(textContentMap, s3ContentMap); } else if (ranking == 2) { - return generateSecondWinModal(); + return generateSecondWinModal(textContentMap, s3ContentMap); } else if (ranking == 3) { - return generateThirdWinModal(); + return generateThirdWinModal(textContentMap, s3ContentMap); } else { - return generateFullAttendModal(); + return generateFullAttendModal(textContentMap, s3ContentMap); } } /** * @return 1등 WinModal 반환 */ - private WinModal generateFirstWinModal() { + + private WinModal generateFirstWinModal(Map textContentMap, Map s3ContentMap) { return WinModal.builder() - .title(staticResourcesUtil.getData("DRAW_WINNER_MODAL_TITLE")) - .subtitle(staticResourcesUtil.getData("DRAW_FIRST_WINNER_MODAL_SUBTITLE")) - .img(staticResourcesUtil.getData("draw_reward_image_1")) - .description(staticResourcesUtil.getData("DRAW_WINNER_MODAL_DESCRIPTION")) + .title(textContentMap.get(StaticTextName.DRAW_WINNER_MODAL_TITLE.name())) + .subtitle(textContentMap.get(StaticTextName.DRAW_FIRST_WINNER_SUBTITLE.name())) + .img(s3ContentMap.get(S3FileName.DRAW_REWARD_IMAGE_1.name())) + .description(StaticTextName.DRAW_WINNER_MODAL_DESCRIPTION.name()) .build(); } /** * @return 2등 WinModal 반환 */ - private WinModal generateSecondWinModal() { + private WinModal generateSecondWinModal(Map textContentMap, Map s3ContentMap) { return WinModal.builder() - .title(staticResourcesUtil.getData("DRAW_WINNER_MODAL_TITLE")) - .subtitle(staticResourcesUtil.getData("DRAW_SECOND_WINNER_MODAL_SUBTITLE")) - .img(staticResourcesUtil.getData("draw_reward_image_2")) - .description(staticResourcesUtil.getData("DRAW_WINNER_MODAL_DESCRIPTION")) + .title(textContentMap.get(StaticTextName.DRAW_WINNER_MODAL_TITLE.name())) + .subtitle(textContentMap.get(StaticTextName.DRAW_SECOND_WINNER_SUBTITLE.name())) + .img(s3ContentMap.get(S3FileName.DRAW_REWARD_IMAGE_2.name())) + .description(textContentMap.get(StaticTextName.DRAW_WINNER_MODAL_DESCRIPTION.name())) .build(); } /** * @return 3등 WinModal 반환 */ - private WinModal generateThirdWinModal() { + private WinModal generateThirdWinModal(Map textContentMap, Map s3ContentMap) { return WinModal.builder() - .title(staticResourcesUtil.getData("DRAW_WINNER_MODAL_TITLE")) - .subtitle(staticResourcesUtil.getData("DRAW_THIRD_WINNER_MODAL_SUBTITLE")) - .img(staticResourcesUtil.getData("draw_reward_image_3")) - .description(staticResourcesUtil.getData("DRAW_WINNER_MODAL_DESCRIPTION")) + .title(textContentMap.get(StaticTextName.DRAW_WINNER_MODAL_TITLE.name())) + .subtitle(textContentMap.get(StaticTextName.DRAW_THIRD_WINNER_SUBTITLE.name())) + .img(s3ContentMap.get(S3FileName.DRAW_REWARD_IMAGE_3.name())) + .description(textContentMap.get(StaticTextName.DRAW_WINNER_MODAL_DESCRIPTION.name())) .build(); } @@ -66,12 +78,12 @@ private WinModal generateThirdWinModal() { * * @return FullAttendModal 반환 */ - public WinModal generateFullAttendModal() { + public WinModal generateFullAttendModal(Map textContentMap, Map s3ContentMap) { return WinModal.builder() - .title(staticResourcesUtil.getData("FULL_ATTEND_MODAL_TITLE")) - .subtitle(staticResourcesUtil.getData("FULL_ATTEND_MODAL_SUBTITLE")) - .img(staticResourcesUtil.getData("attendance_reward_image")) - .description(staticResourcesUtil.getData("FULL_ATTEND_MODAL_DESCRIPTION")) + .title(textContentMap.get(StaticTextName.FULL_ATTEND_MODAL_TITLE.name())) + .subtitle(textContentMap.get(StaticTextName.FULL_ATTEND_MODAL_SUBTITLE.name())) + .img(s3ContentMap.get(S3FileName.ATTENDANCE_REWARD_IMAGE.name())) + .description(textContentMap.get(StaticTextName.FULL_ATTEND_MODAL_DESCRIPTION.name())) .build(); } } diff --git a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawResponseGenerateUtil.java b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawResponseGenerateUtil.java index a7a3f633..e69e455f 100644 --- a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawResponseGenerateUtil.java +++ b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawResponseGenerateUtil.java @@ -9,17 +9,18 @@ import com.softeer.backend.fo_domain.share.exception.ShareUrlInfoException; import com.softeer.backend.fo_domain.share.repository.ShareUrlInfoRepository; import com.softeer.backend.global.common.code.status.ErrorStatus; -import com.softeer.backend.global.staticresources.util.StaticResourcesUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class DrawResponseGenerateUtil { + public static final String BASE_URL = "https://softeer.shop/share/"; + private final ShareUrlInfoRepository shareUrlInfoRepository; private final DrawUtil drawUtil; private final DrawModalGenerateUtil drawModalGenerateUtil; - private final StaticResourcesUtil staticResourcesUtil; + /** * 7일 연속 출석 시 상품 정보 모달 만들어서 반환하는 메서드 @@ -112,7 +113,7 @@ public DrawHistoryLoserResponseDto generateDrawHistoryLoserResponse(Integer user * @return 공유 url */ private String getShareUrl(Integer userId) { - return staticResourcesUtil.getData("BASE_URL") + shareUrlInfoRepository.findShareUrlByUserId(userId) + return BASE_URL + shareUrlInfoRepository.findShareUrlByUserId(userId) .orElseThrow(() -> new ShareUrlInfoException(ErrorStatus._NOT_FOUND)); } } diff --git a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawUtil.java b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawUtil.java index 0ecc204c..a6eb53a4 100644 --- a/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawUtil.java +++ b/src/main/java/com/softeer/backend/fo_domain/draw/util/DrawUtil.java @@ -1,19 +1,28 @@ package com.softeer.backend.fo_domain.draw.util; -import com.softeer.backend.global.staticresources.util.StaticResourcesUtil; +import com.softeer.backend.fo_domain.fcfs.service.FcfsService; +import com.softeer.backend.global.staticresources.constant.S3FileName; +import com.softeer.backend.global.staticresources.repository.S3ContentRepository; +import com.softeer.backend.global.staticresources.util.StaticResourceUtil; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Random; @Component @RequiredArgsConstructor public class DrawUtil { - private final StaticResourcesUtil staticResourcesUtil; + + private final ObjectProvider drawUtilProvider; + private final StaticResourceUtil staticResourceUtil; + @Getter private boolean isDrawWin = false; @Getter @@ -53,7 +62,8 @@ public List generateWinImages() { Random random = new Random(); int direction = random.nextInt(4); // 랜덤 수 - String directionImage = getImageUrl(direction); + DrawUtil drawUtil = drawUtilProvider.getObject(); + String directionImage = drawUtil.getImageUrl(direction); ArrayList images = new ArrayList<>(3); images.add(directionImage); @@ -66,6 +76,8 @@ public List generateWinImages() { * @return 낙첨자를 위한 랜덤 방향 이미지 List 반환 */ public List generateLoseImages() { + DrawUtil drawUtil = drawUtilProvider.getObject(); + ArrayList images = new ArrayList<>(3); Random random = new Random(); int firstDirection, secondDirection, thirdDirection; @@ -76,9 +88,9 @@ public List generateLoseImages() { thirdDirection = random.nextInt(4); } while (firstDirection == secondDirection && secondDirection == thirdDirection); - images.add(getImageUrl(firstDirection)); - images.add(getImageUrl(secondDirection)); - images.add(getImageUrl(thirdDirection)); + images.add(drawUtil.getImageUrl(firstDirection)); + images.add(drawUtil.getImageUrl(secondDirection)); + images.add(drawUtil.getImageUrl(thirdDirection)); return images; } @@ -86,16 +98,20 @@ public List generateLoseImages() { * @param direction 방향을 나타냄. 0, 1, 2, 3이 각각 위, 오른쪽, 밑, 왼쪽 * @return 방향에 따른 이미지 url을 반환 */ - private String getImageUrl(int direction) { + @Cacheable(value = "staticResources", key = "'drawImage_' + #direction") + public String getImageUrl(int direction) { + + Map textContentMap = staticResourceUtil.getTextContentMap(); + String directionImage; if (direction == 0) { - directionImage = staticResourcesUtil.getData("draw_block_up_image"); + directionImage = textContentMap.get(S3FileName.DRAW_BLOCK_UP_IMAGE.name()); } else if (direction == 1) { - directionImage = staticResourcesUtil.getData("draw_block_right_image"); + directionImage = textContentMap.get(S3FileName.DRAW_BLOCK_RIGHT_IMAGE.name()); } else if (direction == 2) { - directionImage = staticResourcesUtil.getData("draw_block_down_image"); + directionImage = textContentMap.get(S3FileName.DRAW_BLOCK_DOWN_IMAGE.name()); } else { - directionImage = staticResourcesUtil.getData("draw_block_left_image"); + directionImage = textContentMap.get(S3FileName.DRAW_BLOCK_LEFT_IMAGE.name()); } return directionImage; } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java index 44fcb13b..0349778f 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/controller/FcfsController.java @@ -51,44 +51,16 @@ public ResponseDto getFcfsTutorialPage() { } @PostMapping - public ResponseEntity handleFcfs(@Parameter(hidden = true) HttpServletRequest request, + public ResponseDto handleFcfs(@Parameter(hidden = true) HttpServletRequest request, @Parameter(hidden = true) @AuthInfo Integer userId, @RequestBody FcfsRequestDto fcfsRequestDto) { int round = (Integer) request.getAttribute("round"); - String fcfsCode = fcfsService.handleFcfsEvent(userId, round, fcfsRequestDto); - - log.info("fcfsCode in handleFcfs : {}", fcfsCode); - - HttpHeaders headers = new HttpHeaders(); - String redirectUrl = "https://softeer.shop/fcfs/result"; - - if(fcfsCode != null){ - request.getSession().setAttribute("fcfsCode", fcfsCode); - redirectUrl += "?fcfsWin=" + URLEncoder.encode("true", StandardCharsets.UTF_8); - headers.add("Location", redirectUrl); - } - else{ - redirectUrl += "?fcfsWin=" + URLEncoder.encode("true", StandardCharsets.UTF_8); - headers.add("Location", redirectUrl); - } - - return new ResponseEntity<>(headers, HttpStatus.FOUND); - } - - @GetMapping("/result") - public ResponseDto getFcfsResult(@Parameter(hidden = true) HttpServletRequest request, - @RequestParam("fcfsWin") Boolean fcfsWin){ - - - String fcfsCode = (String) request.getSession().getAttribute("fcfsCode"); - log.info("fcfsCode in getFcfsResult : {}", fcfsCode); - request.getSession().invalidate(); - - FcfsResultResponseDto fcfsResultResponseDto = fcfsService.getFcfsResult(fcfsWin, fcfsCode); + FcfsResultResponseDto fcfsResultResponseDto = fcfsService.handleFcfsEvent(userId, round, fcfsRequestDto); return ResponseDto.onSuccess(fcfsResultResponseDto); } + } diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResult.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResult.java index 953c4c05..c588464a 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResult.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/dto/result/FcfsSuccessResult.java @@ -6,6 +6,7 @@ @AllArgsConstructor(access = AccessLevel.PUBLIC) @Builder @Getter +@Setter public class FcfsSuccessResult implements FcfsResult { private String title; diff --git a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java index f1cd102a..2983c40e 100644 --- a/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java +++ b/src/main/java/com/softeer/backend/fo_domain/fcfs/service/FcfsService.java @@ -1,21 +1,33 @@ package com.softeer.backend.fo_domain.fcfs.service; +import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; import com.softeer.backend.fo_domain.fcfs.dto.*; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsFailResult; -import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResult; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsResultResponseDto; import com.softeer.backend.fo_domain.fcfs.dto.result.FcfsSuccessResult; import com.softeer.backend.fo_domain.fcfs.exception.FcfsException; 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.staticresources.constant.S3FileName; +import com.softeer.backend.global.staticresources.constant.StaticTextName; +import com.softeer.backend.global.staticresources.domain.S3Content; +import com.softeer.backend.global.staticresources.domain.TextContent; +import com.softeer.backend.global.staticresources.repository.S3ContentRepository; +import com.softeer.backend.global.staticresources.repository.TextContentRepository; +import com.softeer.backend.global.staticresources.util.StaticResourceUtil; 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.beans.factory.ObjectProvider; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.stream.Collectors; + /** * 선착순 관련 이벤트를 처리하는 클래스 */ @@ -23,35 +35,43 @@ @Service @RequiredArgsConstructor public class FcfsService { + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M월 d일"); + private final ObjectProvider fcfsServiceProvider; private final FcfsSettingManager fcfsSettingManager; + private final DrawSettingManager drawSettingManager; private final FcfsRedisUtil fcfsRedisUtil; - private final StaticResourcesUtil staticResourcesUtil; private final RandomCodeUtil randomCodeUtil; + private final StaticResourceUtil staticResourceUtil; public FcfsPageResponseDto getFcfsPage(int round) { QuizDto quiz = fcfsSettingManager.getQuiz(round); + Map textContentMap = staticResourceUtil.getTextContentMap(); return FcfsPageResponseDto.builder() .answerWord(quiz.getAnswerWord()) .answerSentence(quiz.getAnswerSentence()) .startIndex(quiz.getStartIndex()) .endIndex(quiz.getEndIndex()) - .quizDescription(staticResourcesUtil.getData("FCFS_QUIZ_DESCRIPTION")) + .quizDescription(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_QUIZ_DESCRIPTION.name()), + fcfsSettingManager.getFcfsWinnerNum())) .build(); } public FcfsPageResponseDto getFcfsTutorialPage() { + QuizDto tutorialQuiz = fcfsSettingManager.getTutorialQuiz(); + Map textContentMap = staticResourceUtil.getTextContentMap(); return FcfsPageResponseDto.builder() .answerWord(tutorialQuiz.getAnswerWord()) .answerSentence(tutorialQuiz.getAnswerSentence()) .startIndex(tutorialQuiz.getStartIndex()) .endIndex(tutorialQuiz.getEndIndex()) - .quizDescription(staticResourcesUtil.getData("FCFS_QUIZ_DESCRIPTION")) + .quizDescription(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_QUIZ_DESCRIPTION.name()), + fcfsSettingManager.getFcfsWinnerNum())) .build(); } @@ -59,7 +79,7 @@ public FcfsPageResponseDto getFcfsTutorialPage() { * 1. 선착순 당첨자가 아직 다 결정되지 않았으면, 선착순 당첨 응답 생성 및 반환 * 2. 선착순 당첨자가 다 결정됐다면, Redisson lock을 사용하지 않고 Redis에 저장된 선착순 이벤트 참여자 수를 1명씩 더한다. */ - public String handleFcfsEvent(int userId, int round, FcfsRequestDto fcfsRequestDto) { + public FcfsResultResponseDto handleFcfsEvent(int userId, int round, FcfsRequestDto fcfsRequestDto) { if(!fcfsRequestDto.getAnswer().equals(fcfsSettingManager.getQuiz(round).getAnswerWord())) { log.error("fcfs quiz answer is not match, correct answer: {}, wrong anwer: {}", @@ -70,25 +90,26 @@ public String handleFcfsEvent(int userId, int round, FcfsRequestDto fcfsRequestD if (fcfsSettingManager.isFcfsClosed()){ countFcfsParticipant(round); - return null; + return getFcfsResult(false, null); } - - return saveFcfsWinners(userId, round); + FcfsService fcfsService = fcfsServiceProvider.getObject(); + return fcfsService.saveFcfsWinners(userId, round); } @EventLock(key = "FCFS_WINNER_#{#round}") - private String saveFcfsWinners(int userId, int round) { + public FcfsResultResponseDto 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)){ + while (fcfsRedisUtil.isValueInStringSet(RedisKeyPrefix.FCFS_CODE_PREFIX.getPrefix() + round, code)) { code = makeFcfsCode(round); } fcfsRedisUtil.addToStringSet(RedisKeyPrefix.FCFS_CODE_PREFIX.getPrefix() + round, code); @@ -104,8 +125,10 @@ private String saveFcfsWinners(int userId, int round) { fcfsSettingManager.setFcfsClosed(true); } - return code; + return getFcfsResult(true, code); + } + return getFcfsResult(false, null); } @@ -118,16 +141,19 @@ private void countFcfsParticipant(int round) { } public FcfsResultResponseDto getFcfsResult(boolean fcfsWin, String fcfsCode){ + + Map textContentMap = staticResourceUtil.getTextContentMap(); + Map s3ContentMap = staticResourceUtil.getS3ContentMap(); + + FcfsSettingDto firstFcfsSetting = fcfsSettingManager.getFcfsSettingByRound(1); + + FcfsService fcfsService = fcfsServiceProvider.getObject(); + if(fcfsWin){ - FcfsSuccessResult fcfsSuccessResult = FcfsSuccessResult.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(); + FcfsSuccessResult fcfsSuccessResult = fcfsService.getFcfsSuccessResult( + textContentMap, s3ContentMap, firstFcfsSetting + ); + fcfsSuccessResult.setFcfsCode(fcfsCode); return FcfsResultResponseDto.builder() .isFcfsWinner(fcfsWin) @@ -135,11 +161,7 @@ public FcfsResultResponseDto getFcfsResult(boolean fcfsWin, String fcfsCode){ .build(); } - FcfsFailResult fcfsFailResult = FcfsFailResult.builder() - .title(staticResourcesUtil.getData("FCFS_LOSER_TITLE")) - .subTitle(staticResourcesUtil.getData("FCFS_LOSER_SUBTITLE")) - .caution(staticResourcesUtil.getData("FCFS_LOSER_CAUTION")) - .build(); + FcfsFailResult fcfsFailResult = fcfsService.getFcfsFailResult(textContentMap); return FcfsResultResponseDto.builder() .isFcfsWinner(fcfsWin) @@ -147,6 +169,32 @@ public FcfsResultResponseDto getFcfsResult(boolean fcfsWin, String fcfsCode){ .build(); } + @Cacheable(value = "staticResources", key = "'fcfsSuccess'") + public FcfsSuccessResult getFcfsSuccessResult(Map textContentMap, Map s3ContentMap, + FcfsSettingDto firstFcfsSetting){ + + return FcfsSuccessResult.builder() + .title(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_WINNER_TITLE.name()), + fcfsSettingManager.getFcfsWinnerNum())) + .subTitle(textContentMap.get(StaticTextName.FCFS_WINNER_SUBTITLE.name())) + .qrCode(s3ContentMap.get(S3FileName.BARCODE_IMAGE.name())) + .codeWord(textContentMap.get(StaticTextName.FCFS_WINNER_CODE_WORD.name())) + .expirationDate(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_WINNER_EXPIRY_DATE.name()), + firstFcfsSetting.getStartTime().getYear(), + firstFcfsSetting.getStartTime().format(dateFormatter), + drawSettingManager.getEndDate().plusDays(14).format(dateFormatter))) + .caution(textContentMap.get(StaticTextName.FCFS_WINNER_CAUTION.name())) + .build(); + } + + @Cacheable(value = "staticResources", key = "'fcfsFail'") + public FcfsFailResult getFcfsFailResult(Map textContentMap){ + return FcfsFailResult.builder() + .title(textContentMap.get(StaticTextName.FCFS_LOSER_TITLE.name())) + .subTitle(textContentMap.get(StaticTextName.FCFS_LOSER_SUBTITLE.name())) + .caution(textContentMap.get(StaticTextName.FCFS_LOSER_CAUTION.name())) + .build(); + } } diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/controller/MainPageController.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/controller/MainPageController.java index f71a62b2..335ee877 100644 --- a/src/main/java/com/softeer/backend/fo_domain/mainpage/controller/MainPageController.java +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/controller/MainPageController.java @@ -1,14 +1,20 @@ package com.softeer.backend.fo_domain.mainpage.controller; import com.softeer.backend.fo_domain.mainpage.dto.MainPageCarResponseDto; -import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventResponseDto; +import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventInfoResponseDto; +import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventStaticResponseDto; import com.softeer.backend.fo_domain.mainpage.service.MainPageService; import com.softeer.backend.global.common.response.ResponseDto; import lombok.RequiredArgsConstructor; +import org.springframework.http.CacheControl; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.concurrent.TimeUnit; + @RestController @RequiredArgsConstructor @RequestMapping("/main") @@ -16,19 +22,31 @@ public class MainPageController { private final MainPageService mainPageService; - @GetMapping("/event") - public ResponseDto getEventPage(){ - MainPageEventResponseDto mainPageEventResponseDto = mainPageService.getEventPage(); + @GetMapping("/event/static") + public ResponseEntity> getEventPageStatic(){ + MainPageEventStaticResponseDto mainPageEventStaticResponseDto= mainPageService.getEventPageStatic(); + + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic()) // 1일 동안 public 캐싱 + .body(ResponseDto.onSuccess(mainPageEventStaticResponseDto)); + } + + @GetMapping("/event/info") + public ResponseDto getEventPageInfo(){ + + MainPageEventInfoResponseDto mainPageEventInfoResponseDto = mainPageService.getEventPageInfo(); - return ResponseDto.onSuccess(mainPageEventResponseDto); + return ResponseDto.onSuccess(mainPageEventInfoResponseDto); } @GetMapping("/car") - public ResponseDto getCarPage(){ + public ResponseEntity> getCarPage(){ MainPageCarResponseDto mainPageCarResponseDto = mainPageService.getCarPage(); - return ResponseDto.onSuccess(mainPageCarResponseDto); + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic()) // 1일 동안 public 캐싱 + .body(ResponseDto.onSuccess(mainPageCarResponseDto)); } } diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java new file mode 100644 index 00000000..e397fae0 --- /dev/null +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventInfoResponseDto.java @@ -0,0 +1,28 @@ +package com.softeer.backend.fo_domain.mainpage.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.*; + +import java.time.LocalDateTime; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@Builder +@Getter +public class MainPageEventInfoResponseDto { + + private String startDate; + + private String endDate; + + private String fcfsInfo; + + private String totalDrawWinner; + + private String remainDrawCount; + + private String fcfsHint; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime fcfsStartTime; +} diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventResponseDto.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventStaticResponseDto.java similarity index 66% rename from src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventResponseDto.java rename to src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventStaticResponseDto.java index 9b3d1164..5d13af3c 100644 --- a/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventResponseDto.java +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/dto/MainPageEventStaticResponseDto.java @@ -10,27 +10,12 @@ @AllArgsConstructor(access = AccessLevel.PUBLIC) @Builder @Getter -public class MainPageEventResponseDto { - - private String startDate; - - private String endDate; +public class MainPageEventStaticResponseDto { private String eventTitle; private String eventDescription; - private String fcfsInfo; - - private String totalDrawWinner; - - private String remainDrawCount; - - private String fcfsHint; - - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime fcfsStartTime; - private List eventInfoList; @Getter diff --git a/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java b/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java index c1024d90..83b43b6e 100644 --- a/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java +++ b/src/main/java/com/softeer/backend/fo_domain/mainpage/service/MainPageService.java @@ -1,194 +1,294 @@ package com.softeer.backend.fo_domain.mainpage.service; +import com.softeer.backend.fo_domain.draw.repository.DrawRepository; import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; +import com.softeer.backend.fo_domain.fcfs.dto.FcfsSettingDto; import com.softeer.backend.fo_domain.fcfs.service.FcfsSettingManager; import com.softeer.backend.fo_domain.mainpage.dto.MainPageCarResponseDto; -import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventResponseDto; +import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventInfoResponseDto; +import com.softeer.backend.fo_domain.mainpage.dto.MainPageEventStaticResponseDto; import com.softeer.backend.global.common.constant.RedisKeyPrefix; -import com.softeer.backend.global.staticresources.util.StaticResourcesUtil; +import com.softeer.backend.global.staticresources.constant.S3FileName; +import com.softeer.backend.global.staticresources.constant.StaticTextName; +import com.softeer.backend.global.staticresources.util.StaticResourceUtil; import com.softeer.backend.global.util.EventLockRedisUtil; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.text.DecimalFormat; +import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +@Slf4j @Service @RequiredArgsConstructor public class MainPageService { private final DateTimeFormatter eventTimeFormatter = DateTimeFormatter.ofPattern("yyyy.MM.dd"); + private final DateTimeFormatter fcfsTimeFormatter = DateTimeFormatter.ofPattern("a h", Locale.KOREAN); + private final DecimalFormat decimalFormat = new DecimalFormat("#,###"); private final EventLockRedisUtil eventLockRedisUtil; - private final StaticResourcesUtil staticResourcesUtil; private final FcfsSettingManager fcfsSettingManager; private final DrawSettingManager drawSettingManager; + private final DrawRepository drawRepository; + private final StaticResourceUtil staticResourceUtil; - public MainPageEventResponseDto getEventPage(){ + @Transactional(readOnly = true) + @Cacheable(value = "staticResources", key = "'event'") + public MainPageEventStaticResponseDto getEventPageStatic(){ - setTotalVisitorsCount(); + Map textContentMap = staticResourceUtil.getTextContentMap(); + Map s3ContentMap = staticResourceUtil.getS3ContentMap(); - MainPageEventResponseDto.EventInfo fcfsInfo = MainPageEventResponseDto.EventInfo.builder() - .title(staticResourcesUtil.getData("FCFS_TITLE")) - .content(staticResourcesUtil.getData("FCFS_CONTENT")) - .rewardImage1(staticResourcesUtil.getData("fcfs_reward_image_1")) - .rewardImage2(staticResourcesUtil.getData("fcfs_reward_image_2")) + MainPageEventStaticResponseDto.EventInfo fcfsInfo = MainPageEventStaticResponseDto.EventInfo.builder() + .title(textContentMap.get(StaticTextName.FCFS_TITLE.name())) + .content(textContentMap.get(StaticTextName.FCFS_CONTENT.name())) + .rewardImage1(s3ContentMap.get(S3FileName.FCFS_REWARD_IMAGE_1.name())) + .rewardImage2(s3ContentMap.get(S3FileName.FCFS_REWARD_IMAGE_2.name())) .build(); - MainPageEventResponseDto.EventInfo drawInfo = MainPageEventResponseDto.EventInfo.builder() - .title(staticResourcesUtil.getData("DRAW_TITLE")) - .content(staticResourcesUtil.getData("DRAW_CONTENT")) - .rewardImage1(staticResourcesUtil.getData("draw_reward_image_1")) - .rewardImage2(staticResourcesUtil.getData("draw_reward_image_2_3")) + MainPageEventStaticResponseDto.EventInfo drawInfo = MainPageEventStaticResponseDto.EventInfo.builder() + .title(textContentMap.get(StaticTextName.DRAW_TITLE.name())) + .content(textContentMap.get(StaticTextName.DRAW_CONTENT.name())) + .rewardImage1(s3ContentMap.get(S3FileName.DRAW_REWARD_IMAGE_1.name())) + .rewardImage2(s3ContentMap.get(S3FileName.DRAW_REWARD_IMAGE_2_3.name())) .build(); - return MainPageEventResponseDto.builder() - .startDate(drawSettingManager.getStartDate().format(eventTimeFormatter)) - .endDate(drawSettingManager.getEndDate().format(eventTimeFormatter)) - .eventTitle(staticResourcesUtil.getData("EVENT_TITLE")) - .eventDescription(staticResourcesUtil.getData("EVENT_DESCRIPTION")) - .fcfsInfo(staticResourcesUtil.getData("FCFS_INFO")) - .totalDrawWinner(staticResourcesUtil.getData("TOTAL_DRAW_WINNER")) - .remainDrawCount(staticResourcesUtil.getData("REMAIN_DRAW_COUNT")) - .fcfsHint(fcfsSettingManager.getHint()) - .fcfsStartTime(fcfsSettingManager.getNextFcfsTime(LocalDateTime.now())) + return MainPageEventStaticResponseDto.builder() + .eventTitle(textContentMap.get(StaticTextName.EVENT_TITLE.name())) + .eventDescription(textContentMap.get(StaticTextName.EVENT_DESCRIPTION.name())) .eventInfoList(Arrays.asList(fcfsInfo, drawInfo)) .build(); } - // 이벤트 기간이면 redis에 사이트 방문자 수 +1 하기 - private void setTotalVisitorsCount(){ - - LocalDate now = LocalDate.now(); + @Transactional(readOnly = true) + public MainPageEventInfoResponseDto getEventPageInfo(){ - if (!now.isBefore(drawSettingManager.getStartDate()) && !now.isAfter(drawSettingManager.getEndDate())) { - eventLockRedisUtil.incrementData(RedisKeyPrefix.TOTAL_VISITORS_COUNT_PREFIX.getPrefix()); - } + setTotalVisitorsCount(); - } + Map textContentMap = staticResourceUtil.getTextContentMap(); - public MainPageCarResponseDto getCarPage(){ + FcfsSettingDto firstFcfsSetting = fcfsSettingManager.getFcfsSettingByRound(1); + FcfsSettingDto secondFcfsSetting = fcfsSettingManager.getFcfsSettingByRound(2); - MainPageCarResponseDto.CarInfo carInfo1 = MainPageCarResponseDto.CarInfo.builder() - .id(1) - .title(staticResourcesUtil.getData("MAIN_TITLE")) - .subTitle(staticResourcesUtil.getData("MAIN_SUBTITLE")) - .imgUrl(staticResourcesUtil.getData("ioniq_video")) - .backgroundImgUrl(staticResourcesUtil.getData("main_background_image")) - .build(); + int totalDrawWinner = drawSettingManager.getWinnerNum1() + + drawSettingManager.getWinnerNum2() + drawSettingManager.getWinnerNum3(); - MainPageCarResponseDto.CarDetailInfo carDetailInfo2_1 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(1) - .title(staticResourcesUtil.getData("INTERIOR_OPENNESS_TITLE")) - .subTitle(staticResourcesUtil.getData("INTERIOR_OPENNESS_SUBTITLE")) - .content(staticResourcesUtil.getData("INTERIOR_OPENNESS_CONTENT")) - .imgUrl(staticResourcesUtil.getData("interior_openness_image")) - .build(); + int remainDrawCount = totalDrawWinner - (int)drawRepository.count(); - MainPageCarResponseDto.CarDetailInfo carDetailInfo2_2 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(2) - .title(staticResourcesUtil.getData("INTERIOR_WELLNESS_TITLE")) - .subTitle(staticResourcesUtil.getData("INTERIOR_WELLNESS_SUBTITLE")) - .content(staticResourcesUtil.getData("INTERIOR_WELLNESS_CONTENT")) - .imgUrl(staticResourcesUtil.getData("interior_wellness_image")) - .build(); - - MainPageCarResponseDto.CarInfo carInfo2 = MainPageCarResponseDto.CarInfo.builder() - .id(2) - .title(staticResourcesUtil.getData("INTERIOR_TITLE")) - .subTitle(staticResourcesUtil.getData("INTERIOR_SUBTITLE")) - .imgTitle(staticResourcesUtil.getData("INTERIOR_IMAGE_TITLE")) - .imgContent(staticResourcesUtil.getData("INTERIOR_IMAGE_CONTENT")) - .imgUrl(staticResourcesUtil.getData("interior_thumbnail_image")) - .backgroundImgUrl(staticResourcesUtil.getData("interior_background_image")) - .carDetailInfoList(Arrays.asList(carDetailInfo2_1, carDetailInfo2_2)) + return MainPageEventInfoResponseDto.builder() + .startDate(drawSettingManager.getStartDate().format(eventTimeFormatter)) + .endDate(drawSettingManager.getEndDate().format(eventTimeFormatter)) + .fcfsInfo(staticResourceUtil.format(textContentMap.get(StaticTextName.FCFS_INFO.name()), + staticResourceUtil.getKoreanDayOfWeek(firstFcfsSetting.getStartTime().getDayOfWeek()), + staticResourceUtil.getKoreanDayOfWeek(secondFcfsSetting.getStartTime().getDayOfWeek()), + firstFcfsSetting.getStartTime().format(fcfsTimeFormatter), + firstFcfsSetting.getWinnerNum())) + .totalDrawWinner(staticResourceUtil.format( + textContentMap.get(StaticTextName.TOTAL_DRAW_WINNER.name()), decimalFormat.format(totalDrawWinner))) + .remainDrawCount(staticResourceUtil.format( + textContentMap.get(StaticTextName.REMAIN_DRAW_COUNT.name()), decimalFormat.format(remainDrawCount))) + .fcfsStartTime(fcfsSettingManager.getNextFcfsTime(LocalDateTime.now())) .build(); + } - MainPageCarResponseDto.CarDetailInfo carDetailInfo3_1 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(1) - .title(staticResourcesUtil.getData("PERFORMANCE_BRAKING_TITLE")) - .subTitle(staticResourcesUtil.getData("PERFORMANCE_BRAKING_SUBTITLE")) - .content(staticResourcesUtil.getData("PERFORMANCE_BRAKING_CONTENT")) - .imgUrl(staticResourcesUtil.getData("performance_braking_image")) - .build(); + // 이벤트 기간이면 redis에 사이트 방문자 수 +1 하기 + public void setTotalVisitorsCount(){ - MainPageCarResponseDto.CarDetailInfo carDetailInfo3_2 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(2) - .title(staticResourcesUtil.getData("PERFORMANCE_DRIVING_TITLE")) - .subTitle(staticResourcesUtil.getData("PERFORMANCE_DRIVING_SUBTITLE")) - .content(staticResourcesUtil.getData("PERFORMANCE_DRIVING_CONTENT")) - .imgUrl(staticResourcesUtil.getData("performance_driving_image")) - .build(); + LocalDate now = LocalDate.now(); - MainPageCarResponseDto.CarInfo carInfo3 = MainPageCarResponseDto.CarInfo.builder() - .id(3) - .title(staticResourcesUtil.getData("PERFORMANCE_TITLE")) - .subTitle(staticResourcesUtil.getData("PERFORMANCE_SUBTITLE")) - .imgTitle(staticResourcesUtil.getData("PERFORMANCE_IMAGE_TITLE")) - .imgContent(staticResourcesUtil.getData("PERFORMANCE_IMAGE_CONTENT")) - .imgUrl(staticResourcesUtil.getData("performance_thumbnail_image")) - .backgroundImgUrl(staticResourcesUtil.getData("performance_background_image")) - .carDetailInfoList(Arrays.asList(carDetailInfo3_1, carDetailInfo3_2)) - .build(); + if (!now.isBefore(drawSettingManager.getStartDate()) && !now.isAfter(drawSettingManager.getEndDate())) { + eventLockRedisUtil.incrementData(RedisKeyPrefix.TOTAL_VISITORS_COUNT_PREFIX.getPrefix()); + } - MainPageCarResponseDto.CarDetailInfo carDetailInfo4_1 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(1) - .title(staticResourcesUtil.getData("CHARGING_FAST_TITLE")) - .subTitle(staticResourcesUtil.getData("CHARGING_FAST_SUBTITLE")) - .content(staticResourcesUtil.getData("CHARGING_FAST_CONTENT")) - .imgUrl(staticResourcesUtil.getData("charging_fast_image")) - .build(); + } - MainPageCarResponseDto.CarDetailInfo carDetailInfo4_2 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(2) - .title(staticResourcesUtil.getData("CHARGING_V2L_TITLE")) - .subTitle(staticResourcesUtil.getData("CHARGING_V2L_SUBTITLE")) - .content(staticResourcesUtil.getData("CHARGING_V2L_CONTENT")) - .imgUrl(staticResourcesUtil.getData("charging_v2l_image")) - .build(); + @Transactional(readOnly = true) + @Cacheable(value = "staticResources", key = "'car'") + public MainPageCarResponseDto getCarPage() { + Map textContentMap = staticResourceUtil.getTextContentMap(); + Map s3ContentMap = staticResourceUtil.getS3ContentMap(); - MainPageCarResponseDto.CarInfo carInfo4 = MainPageCarResponseDto.CarInfo.builder() - .id(4) - .title(staticResourcesUtil.getData("CHARGING_TITLE")) - .subTitle(staticResourcesUtil.getData("CHARGING_SUBTITLE")) - .imgTitle(staticResourcesUtil.getData("CHARGING_IMAGE_TITLE")) - .imgContent(staticResourcesUtil.getData("CHARGING_IMAGE_CONTENT")) - .imgUrl(staticResourcesUtil.getData("charging_thumbnail_image")) - .backgroundImgUrl(staticResourcesUtil.getData("charging_background_image")) - .carDetailInfoList(Arrays.asList(carDetailInfo4_1, carDetailInfo4_2)) - .build(); + List carInfoList = List.of( + createCarInfo(1, + StaticTextName.MAIN_TITLE, + StaticTextName.MAIN_SUBTITLE, + S3FileName.IONIQ_VIDEO, + S3FileName.MAIN_BACKGROUND_IMAGE, + textContentMap, + s3ContentMap), + createCarInfoWithDetails(2, + StaticTextName.INTERIOR_TITLE, + StaticTextName.INTERIOR_SUBTITLE, + StaticTextName.INTERIOR_IMAGE_TITLE, + StaticTextName.INTERIOR_IMAGE_CONTENT, + S3FileName.INTERIOR_THUMBNAIL_IMAGE, + S3FileName.INTERIOR_BACKGROUND_IMAGE, + List.of( + createCarDetailInfo(1, + StaticTextName.INTERIOR_OPENNESS_TITLE, + StaticTextName.INTERIOR_OPENNESS_SUBTITLE, + StaticTextName.INTERIOR_OPENNESS_CONTENT, + S3FileName.INTERIOR_OPENNESS_IMAGE, + textContentMap, + s3ContentMap), + createCarDetailInfo(2, + StaticTextName.INTERIOR_WELLNESS_TITLE, + StaticTextName.INTERIOR_WELLNESS_SUBTITLE, + StaticTextName.INTERIOR_WELLNESS_CONTENT, + S3FileName.INTERIOR_WELLNESS_IMAGE, + textContentMap, + s3ContentMap) + ), + textContentMap, + s3ContentMap + ), + createCarInfoWithDetails(3, + StaticTextName.PERFORMANCE_TITLE, + StaticTextName.PERFORMANCE_SUBTITLE, + StaticTextName.PERFORMANCE_IMAGE_TITLE, + StaticTextName.PERFORMANCE_IMAGE_CONTENT, + S3FileName.PERFORMANCE_THUMBNAIL_IMAGE, + S3FileName.PERFORMANCE_BACKGROUND_IMAGE, + List.of( + createCarDetailInfo(1, + StaticTextName.PERFORMANCE_BRAKING_TITLE, + StaticTextName.PERFORMANCE_BRAKING_SUBTITLE, + StaticTextName.PERFORMANCE_BRAKING_CONTENT, + S3FileName.PERFORMANCE_BRAKING_IMAGE, + textContentMap, + s3ContentMap), + createCarDetailInfo(2, + StaticTextName.PERFORMANCE_DRIVING_TITLE, + StaticTextName.PERFORMANCE_DRIVING_SUBTITLE, + StaticTextName.PERFORMANCE_DRIVING_CONTENT, + S3FileName.PERFORMANCE_DRIVING_IMAGE, + textContentMap, + s3ContentMap) + ), + textContentMap, + s3ContentMap + ), + createCarInfoWithDetails(4, StaticTextName.CHARGING_TITLE, + StaticTextName.CHARGING_SUBTITLE, + StaticTextName.CHARGING_IMAGE_TITLE, + StaticTextName.CHARGING_IMAGE_CONTENT, + S3FileName.CHARGING_THUMBNAIL_IMAGE, + S3FileName.CHARGING_BACKGROUND_IMAGE, + List.of( + createCarDetailInfo(1, + StaticTextName.CHARGING_FAST_TITLE, + StaticTextName.CHARGING_FAST_SUBTITLE, + StaticTextName.CHARGING_FAST_CONTENT, + S3FileName.CHARGING_FAST_IMAGE, + textContentMap, + s3ContentMap), + createCarDetailInfo(2, + StaticTextName.CHARGING_V2L_TITLE, + StaticTextName.CHARGING_V2L_SUBTITLE, + StaticTextName.CHARGING_V2L_CONTENT, + S3FileName.CHARGING_V2L_IMAGE, + textContentMap, + s3ContentMap) + ), + textContentMap, + s3ContentMap + ), + createCarInfoWithDetails(5, + StaticTextName.SAFE_TITLE, + StaticTextName.SAFE_SUBTITLE, + StaticTextName.SAFE_IMAGE_TITLE, + StaticTextName.SAFE_IMAGE_CONTENT, + S3FileName.SAFE_THUMBNAIL_IMAGE, + S3FileName.SAFE_BACKGROUND_IMAGE, + List.of( + createCarDetailInfo(1, + StaticTextName.SAFE_DRIVING_TITLE, + StaticTextName.SAFE_DRIVING_SUBTITLE, + StaticTextName.SAFE_DRIVING_CONTENT, + S3FileName.SAFE_DRIVING_IMAGE, + textContentMap, + s3ContentMap), + createCarDetailInfo(2, + StaticTextName.SAFE_ADVANCED_TITLE, + StaticTextName.SAFE_ADVANCED_SUBTITLE, + StaticTextName.SAFE_ADVANCED_CONTENT, + S3FileName.SAFE_ADVANCED_IMAGE, + textContentMap, + s3ContentMap) + ), + textContentMap, + s3ContentMap + ) + ); - MainPageCarResponseDto.CarDetailInfo carDetailInfo5_1 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(1) - .title(staticResourcesUtil.getData("SAFE_DRIVING_TITLE")) - .subTitle(staticResourcesUtil.getData("SAFE_DRIVING_SUBTITLE")) - .content(staticResourcesUtil.getData("SAFE_DRIVING_CONTENT")) - .imgUrl(staticResourcesUtil.getData("safe_driving_image")) + return MainPageCarResponseDto.builder() + .carInfoList(carInfoList) .build(); + } - MainPageCarResponseDto.CarDetailInfo carDetailInfo5_2 = MainPageCarResponseDto.CarDetailInfo.builder() - .id(2) - .title(staticResourcesUtil.getData("SAFE_ADVANCED_TITLE")) - .subTitle(staticResourcesUtil.getData("SAFE_ADVANCED_SUBTITLE")) - .content(staticResourcesUtil.getData("SAFE_ADVANCED_CONTENT")) - .imgUrl(staticResourcesUtil.getData("safe_advanced_image")) + private MainPageCarResponseDto.CarInfo createCarInfo(int id, + StaticTextName titleKey, + StaticTextName subTitleKey, + S3FileName imgUrlKey, + S3FileName backgroundImgUrlKey, + Map textContentMap, + Map s3ContentMap) { + return MainPageCarResponseDto.CarInfo.builder() + .id(id) + .title(textContentMap.get(titleKey.name())) + .subTitle(textContentMap.get(subTitleKey.name())) + .imgUrl(s3ContentMap.get(imgUrlKey.name())) + .backgroundImgUrl(s3ContentMap.get(backgroundImgUrlKey.name())) .build(); + } - MainPageCarResponseDto.CarInfo carInfo5 = MainPageCarResponseDto.CarInfo.builder() - .id(5) - .title(staticResourcesUtil.getData("SAFE_TITLE")) - .subTitle(staticResourcesUtil.getData("SAFE_SUBTITLE")) - .imgTitle(staticResourcesUtil.getData("SAFE_IMAGE_TITLE")) - .imgContent(staticResourcesUtil.getData("SAFE_IMAGE_CONTENT")) - .imgUrl(staticResourcesUtil.getData("safe_thumbnail_image")) - .backgroundImgUrl(staticResourcesUtil.getData("safe_background_image")) - .carDetailInfoList(Arrays.asList(carDetailInfo5_1, carDetailInfo5_2)) + private MainPageCarResponseDto.CarDetailInfo createCarDetailInfo(int id, + StaticTextName titleKey, + StaticTextName subTitleKey, + StaticTextName contentKey, + S3FileName imgUrlKey, + Map textContentMap, + Map s3ContentMap) { + return MainPageCarResponseDto.CarDetailInfo.builder() + .id(id) + .title(textContentMap.get(titleKey.name())) + .subTitle(textContentMap.get(subTitleKey.name())) + .content(textContentMap.get(contentKey.name())) + .imgUrl(s3ContentMap.get(imgUrlKey.name())) .build(); + } - return MainPageCarResponseDto.builder() - .carInfoList(Arrays.asList(carInfo1, carInfo2, carInfo3, carInfo4, carInfo5)) + private MainPageCarResponseDto.CarInfo createCarInfoWithDetails(int id, + StaticTextName titleKey, + StaticTextName subTitleKey, + StaticTextName imgTitleKey, + StaticTextName imgContentKey, + S3FileName imgUrlKey, + S3FileName backgroundImgUrlKey, + List carDetailInfoList, + Map textContentMap, + Map s3ContentMap) { + return MainPageCarResponseDto.CarInfo.builder() + .id(id) + .title(textContentMap.get(titleKey.name())) + .subTitle(textContentMap.get(subTitleKey.name())) + .imgTitle(textContentMap.get(imgTitleKey.name())) + .imgContent(textContentMap.get(imgContentKey.name())) + .imgUrl(s3ContentMap.get(imgUrlKey.name())) + .backgroundImgUrl(s3ContentMap.get(backgroundImgUrlKey.name())) + .carDetailInfoList(carDetailInfoList) .build(); } } diff --git a/src/main/java/com/softeer/backend/fo_domain/share/service/ShareUrlInfoService.java b/src/main/java/com/softeer/backend/fo_domain/share/service/ShareUrlInfoService.java index 4820df64..5aa9e0be 100644 --- a/src/main/java/com/softeer/backend/fo_domain/share/service/ShareUrlInfoService.java +++ b/src/main/java/com/softeer/backend/fo_domain/share/service/ShareUrlInfoService.java @@ -10,13 +10,16 @@ @Service @RequiredArgsConstructor public class ShareUrlInfoService { + public static final String NON_USER_SHARE_URL = "https://softeer.site"; + public static final String BASE_URL = "https://softeer.site/share/"; + private final ShareUrlInfoRepository shareUrlInfoRepository; public ShareUrlInfoResponseDto getShortenShareUrl(Integer userId) { if (userId == null) { // 로그인하지 않은 사용자 return ShareUrlInfoResponseDto.builder() - .shareUrl("https://softeer.site") + .shareUrl(NON_USER_SHARE_URL) .build(); } else { // 로그인한 사용자 @@ -26,7 +29,7 @@ public ShareUrlInfoResponseDto getShortenShareUrl(Integer userId) { // DB에 이미 생성된 단축 url 코드 반환 return ShareUrlInfoResponseDto.builder() - .shareUrl("https://softeer.site/" + shareCode) + .shareUrl(BASE_URL + shareCode) .build(); } } diff --git a/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java b/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java index d19af667..ee1cdd31 100644 --- a/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java +++ b/src/main/java/com/softeer/backend/global/common/constant/RedisKeyPrefix.java @@ -8,7 +8,7 @@ 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_"), + FCFS_PARTICIPANT_COUNT_PREFIX("FCFS_PARTICIPANT_COUNT"), // 추첨 DRAW_LOCK_PREFIX("LOCK:DRAW_WINNER"), diff --git a/src/main/java/com/softeer/backend/global/config/cache/CacheConfig.java b/src/main/java/com/softeer/backend/global/config/cache/CacheConfig.java new file mode 100644 index 00000000..1e32de61 --- /dev/null +++ b/src/main/java/com/softeer/backend/global/config/cache/CacheConfig.java @@ -0,0 +1,34 @@ +package com.softeer.backend.global.config.cache; + +import com.github.benmanes.caffeine.cache.Caffeine; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.caffeine.CaffeineCacheManager; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Configuration +@EnableCaching +public class CacheConfig { + + @Bean + public CacheManager cacheManager() { + CaffeineCacheManager cacheManager = new CaffeineCacheManager(); + cacheManager.setCaffeine( + Caffeine.newBuilder() + .expireAfterAccess(1, TimeUnit.DAYS) //첫 번재 접근 후 1일 경과 후, 제거 + .initialCapacity(200) //초기 크기 설정 + .softValues() // 값 객체에 대한 부드러움 참조: 메모리가 부족할 때만 GC가 일어남. GC가 수집 대상으로 판단하더라도 GC가 일어나지 않음 + .maximumSize(1000) // 최대 크기 설정 + .recordStats() // 캐시 지표 기록 + .removalListener((key ,value, cause) -> log.debug("key: {}, value: {}가 제거 되었습니다. cause: {}", key, value, cause)) + ); + return cacheManager; + } +} diff --git a/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java b/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java index 887813b2..4645b84a 100644 --- a/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java +++ b/src/main/java/com/softeer/backend/global/config/web/WebMvcConfig.java @@ -14,6 +14,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @@ -108,4 +109,12 @@ public FilterRegistrationBean jwtAuthorizationFilter() { return registrationBean; } + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean filterRegistrationBean + = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); + filterRegistrationBean.addUrlPatterns("/main/event/static", "/main/car"); + return filterRegistrationBean; + } + } diff --git a/src/main/java/com/softeer/backend/global/filter/JwtAuthenticationFilter.java b/src/main/java/com/softeer/backend/global/filter/JwtAuthenticationFilter.java index 6a741c65..2e5698d9 100644 --- a/src/main/java/com/softeer/backend/global/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/softeer/backend/global/filter/JwtAuthenticationFilter.java @@ -37,7 +37,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/swagger-ui/**", "/swagger", "/v3/**", "/error/**", "/verification/send", "/verification/confirm", "/login", - "/main/event", "/main/car", + "/main/event/static", "/main/event/info", "/main/car", "/admin/login", "/admin/signup", "/share/**" }; diff --git a/src/main/java/com/softeer/backend/global/staticresources/constant/S3FileName.java b/src/main/java/com/softeer/backend/global/staticresources/constant/S3FileName.java new file mode 100644 index 00000000..6a118133 --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/constant/S3FileName.java @@ -0,0 +1,37 @@ +package com.softeer.backend.global.staticresources.constant; + +public enum S3FileName { + CHARGING_BACKGROUND_IMAGE, + CHARGING_FAST_IMAGE, + CHARGING_THUMBNAIL_IMAGE, + CHARGING_V2L_IMAGE, + DRAW_REWARD_IMAGE_1, + DRAW_REWARD_IMAGE_2, + DRAW_REWARD_IMAGE_3, + FCFS_REWARD_IMAGE_1, + FCFS_REWARD_IMAGE_2, + INTERIOR_BACKGROUND_IMAGE, + INTERIOR_OPENNESS_IMAGE, + INTERIOR_THUMBNAIL_IMAGE, + INTERIOR_WELLNESS_IMAGE, + IONIQ_VIDEO, + MAIN_BACKGROUND_IMAGE, + MAIN_THUMBNAIL_IMAGE, + PERFORMANCE_BACKGROUND_IMAGE, + PERFORMANCE_BRAKING_IMAGE, + PERFORMANCE_DRIVING_IMAGE, + PERFORMANCE_THUMBNAIL_IMAGE, + SAFE_ADVANCED_IMAGE, + SAFE_BACKGROUND_IMAGE, + SAFE_DRIVING_IMAGE, + SAFE_THUMBNAIL_IMAGE, + BARCODE_IMAGE, + SEVENTH_COMPLETE_IMAGE, + SEVENTH_NOT_YET_IMAGE, + ATTENDANCE_REWARD_IMAGE, + DRAW_BLOCK_DOWN_IMAGE, + DRAW_BLOCK_LEFT_IMAGE, + DRAW_BLOCK_RIGHT_IMAGE, + DRAW_BLOCK_UP_IMAGE, + DRAW_REWARD_IMAGE_2_3 +} diff --git a/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java b/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java deleted file mode 100644 index fc1fb6d8..00000000 --- a/src/main/java/com/softeer/backend/global/staticresources/constant/StaticText.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.softeer.backend.global.staticresources.constant; - -import lombok.Getter; - -@Getter -public enum StaticText { - EVENT_TITLE("신차 출시 기념 EVENT"), - EVENT_DESCRIPTION("현대자동차의 The new IONIQ 5 출시 기념 이벤트로 여러분을 초대합니다.\n" + - "24시간 무료 렌트, 신차 할인 쿠폰 및 다양한 경품을 받아보세요."), - - FCFS_INFO("매주 %s, %s %s시 선착순 %s명"), - FCFS_TITLE("'24시 내 차' 이벤트"), - FCFS_CONTENT("하단의 The new IONIQ 5 정보를 바탕으로 빠르게 문장 퀴즈를 맞춰\n" + - "24시간 렌트권과 신차 할인권을 얻을 수 있어요."), - - TOTAL_DRAW_WINNER("추첨 %s명"), - REMAIN_DRAW_COUNT("남은 경품 %s개"), - DRAW_TITLE("매일 복권 긁고 경품 받기"), - DRAW_CONTENT("이벤트 기간 동안 추첨을 통해 아이패드 pro 11인치, 현대백화점 10만원권, 1만원권을 드려요.\n" + - "일주일 연속 참여 시, 스타벅스 쿠폰을 무조건 받을 수 있어요."), - - MAIN_TITLE("The new IONIQ 5"), - MAIN_SUBTITLE("새롭게 돌아온 The new IONIQ 5를 소개합니다"), - - INTERIOR_TITLE("Interior"), - INTERIOR_SUBTITLE("내부 인테리어"), - INTERIOR_IMAGE_TITLE("Living Space"), - INTERIOR_IMAGE_CONTENT("편안한 거주 공간 (Living Space) 테마를 반영하여 더 넓은 실내 공간을 즐길 수 있도록 연출합니다."), - INTERIOR_OPENNESS_TITLE("개방감"), - INTERIOR_OPENNESS_SUBTITLE("개방감과 와이드한 이미지 제공"), - INTERIOR_OPENNESS_CONTENT("심리스 스타일의 12.3인치 LCD 클러스터는 탁월한 개방감으로 즐거운 드라이빙 환경을 제공합니다.\n" + - "클러스터와 인포테인먼트 시스템에 일체형 커버글래스를 적용하여 와이드한 이미지를 제공합니다."), - - INTERIOR_WELLNESS_TITLE("웰니스"), - INTERIOR_WELLNESS_SUBTITLE("웰니스와 친환경"), - INTERIOR_WELLNESS_CONTENT("혼커버, 스위치, 스티어링 휠, 도어 등에 유채꽃과 옥수수에서 추출한 성분 약 10%가 함유된 바이오 페인트를 이용했습니다.\n" + - "시트와 도어 트림에는 재활용 투명 PET병을 재활용한 원사 약 20%의 섬유가 사용됐습니다."), - - PERFORMANCE_TITLE("Performance"), - PERFORMANCE_SUBTITLE("주행성능"), - PERFORMANCE_IMAGE_TITLE("Large Capacity Battery"), - PERFORMANCE_IMAGE_CONTENT("항속형 대용량 배터리를 적용하여 주행 가능 거리를 높였습니다."), - PERFORMANCE_BRAKING_TITLE("에너지 효율"), - PERFORMANCE_BRAKING_SUBTITLE("회생 제동 시스템"), - PERFORMANCE_BRAKING_CONTENT("스티어링 휠의 패들쉬프트를 통해 회생제동 수준을 단계별로 조작할 수 있어\n" + - "브레이크 및 가족 페달 작동을 최소화하여 에너지 효율을 높일 수 있습니다."), - - PERFORMANCE_DRIVING_TITLE("주행성능"), - PERFORMANCE_DRIVING_SUBTITLE("주행 성능"), - PERFORMANCE_DRIVING_CONTENT("1회 충전 주행 가능 거리: 485km (2WD, 19인치, 빌트인 캠 미적용 기준)\n" + - "최고 출력 / 최대 토크: 239 kW (325 PS) / 605 Nm\n" + - "84.0 kWh 대용량 배터리를 장착하여 보다 여유 있는 장거리 주행이 가능합니다."), - - CHARGING_TITLE("Charging"), - CHARGING_SUBTITLE("급속 충전"), - CHARGING_IMAGE_TITLE("V2L/Charging"), - CHARGING_IMAGE_CONTENT("차량 외부로 전력을 공급할 수 있는 V2L 기능과 쉽고 빠르게 충전 관련 서비스는 사용자에게 새로운 경험을 제공합니다."), - CHARGING_FAST_TITLE("초급속 충전"), - CHARGING_FAST_SUBTITLE("18분 초급속 충전 경험"), - CHARGING_FAST_CONTENT("400V/800V 멀티 급속 충전 시스템으로 다양한 충전 인프라를 사용할 수 있으며,\n" + - "급속 충전기(350kW) 사용 시 18분 이내에 배터리 용량의 10%에서 80%까지 충전이 가능합니다."), - - CHARGING_V2L_TITLE("실외/실내\n" + - "V2L"), - CHARGING_V2L_SUBTITLE("실외/실내 V2L"), - CHARGING_V2L_CONTENT("차량 외부에서도 실외 V2L 기능을 통해 다양한 전자기기 사용이 가능합니다.\n" + - "2열 시트 하단의 실내 V2L을 사용하여 차량 내부에서 배터리 걱정 없이 전자기기 사용이 가능합니다."), - - SAFE_TITLE("Safe, Convenient"), - SAFE_SUBTITLE("안전성과 편리함"), - SAFE_IMAGE_TITLE("Safe & Convenient Environment"), - SAFE_IMAGE_CONTENT("다양한 안전, 편의 기술로 편리하고 안전한 드라이빙 환경을 제공합니다."), - SAFE_DRIVING_TITLE("주행 안전"), - SAFE_DRIVING_SUBTITLE("도로 주행 중 안전"), - SAFE_DRIVING_CONTENT("고속도로 및 자동차 전용도로 주행 시 도로 상황에 맞춰 안전한 속도로 주행하도록 도와주며,\n" + - "안전속도 구간, 곡선 구간, 진출입로 진입 전에 자동으로 속도를 줄이고 해당 구간을 지나면 원래 설정한 속도로 복귀합니다.\n" + - "일정 속도 이상으로 주행 시, 스티어링 휠을 잡은 상태에서 방향지시등 스위치를 변경하고자 하는 차로 방향으로 자동으로 움직입니다."), - - SAFE_ADVANCED_TITLE("후석 승객 알림"), - SAFE_ADVANCED_SUBTITLE("어드밴스드 후석 승객 알림"), - SAFE_ADVANCED_CONTENT("정밀한 레이더 센서가 실내의 승객을 감지하여, 운전자가 후석에 탑승한 유아를 인지하지 못하고 차를 떠나면\n" + - "알림을 주어 안전사고를 예방합니다."), - - // 7일 연속 출석 모달 - FULL_ATTEND_MODAL_TITLE("7일 연속 출석하셨네요!"), - FULL_ATTEND_MODAL_SUBTITLE("등록된 번호로 스타벅스 기프티콘을 보내드려요."), - FULL_ATTEND_MODAL_DESCRIPTION("본 이벤트는 The new IONIQ 5 출시 이벤트 기간 내 한 회선당 1회만 참여 가능합니다.\n" + - "이벤트 경품 수령을 위해 등록된 전화번호로 영업일 기준 3~5일 내 개별 안내가 진행될 예정입니다.\n" + - "이벤트 당첨 이후 개인정보 제공을 거부하거나 개별 안내를 거부하는 경우, 당첨이 취소될 수 있습니다.\n"), - - // 추첨 당첨 모달 - DRAW_WINNER_MODAL_TITLE("축하합니다!"), - DRAW_FIRST_WINNER_SUBTITLE("아이패드에 당첨됐어요!"), - DRAW_SECOND_WINNER_SUBTITLE("현대백화점 쿠폰 10만원퀀에 당첨됐어요!"), - DRAW_THIRD_WINNER_SUBTITLE("현대백화점 쿠폰 1만원퀀에 당첨됐어요!"), - DRAW_WINNER_MODAL_DESCRIPTION("이벤트 경품 수령을 위해 등록된 전화번호로 영업일 기준 3~5일 내 개별 안내가 진행될 예정입니다.\n" + - "이벤트 당첨 이후 개인정보 제공을 거부하거나 개별 안내를 거부하는 경우, 당첨이 취소될 수 있습니다."), - - // 공유 url - BASE_URL("https://softeer.shop/share/"), - NON_USER_SHARE_URL("https://softeer.site"), - - // 선착순 - FCFS_QUIZ_DESCRIPTION("선착순 %s명에게 The new IONIQ 5 24시간 무료 렌트권 증정"), - - FCFS_WINNER_TITLE("선착순 %s명 안에 들었어요!"), - FCFS_WINNER_SUBTITLE("[ 더뉴 아이오닉 5 24시간 렌트 이용권 + 신차 구입 10% 할인권 ]"), - FCFS_WINNER_CODE_WORD("코드"), - FCFS_WINNER_EXPIRY_DATE("사용기한 : %s년 %s ~ %s"), - FCFS_WINNER_CAUTION("본 이벤트는 (주)쏘카와 함께하며, 쏘카 회원가입 및 로그인 후 이용 가능합니다.\n" + - "이벤트 참여를 위해 쏘카 어플리케이션에서 추가적인 절차가 요구될 수 있습니다.\n" + - "이벤트 경품 수령을 위해 등록된 전화번호로 영업일 기준 3~5일 내 안내가 진행될 예정입니다."), - - FCFS_LOSER_TITLE("다음 주에 다시 도전해보세요"), - FCFS_LOSER_SUBTITLE("아쉽게도 선착순 순위에 들지 못했어요"), - FCFS_LOSER_CAUTION("본 이벤트는 (주)쏘카와 함께하며, 쏘카 회원가입 및 로그인 후 이용 가능합니다.\n" + - "이벤트 참여를 위해 쏘카 어플리케이션에서 추가적인 절차가 요구될 수 있습니다."); - - - - private final String text; - - StaticText(String text) { - this.text = text; - } - - public String format(Object... args) { - return String.format(text, args); - } -} diff --git a/src/main/java/com/softeer/backend/global/staticresources/constant/StaticTextName.java b/src/main/java/com/softeer/backend/global/staticresources/constant/StaticTextName.java new file mode 100644 index 00000000..13d2e116 --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/constant/StaticTextName.java @@ -0,0 +1,98 @@ +package com.softeer.backend.global.staticresources.constant; + +import lombok.Getter; + +public enum StaticTextName { + EVENT_TITLE, + EVENT_DESCRIPTION, + + FCFS_INFO, + FCFS_TITLE, + FCFS_CONTENT, + + TOTAL_DRAW_WINNER, + REMAIN_DRAW_COUNT, + DRAW_TITLE, + DRAW_CONTENT, + + MAIN_TITLE, + MAIN_SUBTITLE, + + INTERIOR_TITLE, + INTERIOR_SUBTITLE, + INTERIOR_IMAGE_TITLE, + INTERIOR_IMAGE_CONTENT, + INTERIOR_OPENNESS_TITLE, + INTERIOR_OPENNESS_SUBTITLE, + INTERIOR_OPENNESS_CONTENT, + + INTERIOR_WELLNESS_TITLE, + INTERIOR_WELLNESS_SUBTITLE, + INTERIOR_WELLNESS_CONTENT, + + PERFORMANCE_TITLE, + PERFORMANCE_SUBTITLE, + PERFORMANCE_IMAGE_TITLE, + PERFORMANCE_IMAGE_CONTENT, + PERFORMANCE_BRAKING_TITLE, + PERFORMANCE_BRAKING_SUBTITLE, + PERFORMANCE_BRAKING_CONTENT, + + PERFORMANCE_DRIVING_TITLE, + PERFORMANCE_DRIVING_SUBTITLE, + PERFORMANCE_DRIVING_CONTENT, + + CHARGING_TITLE, + CHARGING_SUBTITLE, + CHARGING_IMAGE_TITLE, + CHARGING_IMAGE_CONTENT, + CHARGING_FAST_TITLE, + CHARGING_FAST_SUBTITLE, + CHARGING_FAST_CONTENT, + + CHARGING_V2L_TITLE, + CHARGING_V2L_SUBTITLE, + CHARGING_V2L_CONTENT, + + SAFE_TITLE, + SAFE_SUBTITLE, + SAFE_IMAGE_TITLE, + SAFE_IMAGE_CONTENT, + SAFE_DRIVING_TITLE, + SAFE_DRIVING_SUBTITLE, + SAFE_DRIVING_CONTENT, + + SAFE_ADVANCED_TITLE, + SAFE_ADVANCED_SUBTITLE, + SAFE_ADVANCED_CONTENT, + + // 7일 연속 출석 모달 + FULL_ATTEND_MODAL_TITLE, + FULL_ATTEND_MODAL_SUBTITLE, + FULL_ATTEND_MODAL_DESCRIPTION, + + // 추첨 당첨 모달 + DRAW_WINNER_MODAL_TITLE, + DRAW_FIRST_WINNER_SUBTITLE, + DRAW_SECOND_WINNER_SUBTITLE, + DRAW_THIRD_WINNER_SUBTITLE, + DRAW_WINNER_MODAL_DESCRIPTION, + + // 공유 url + BASE_URL, + NON_USER_SHARE_URL, + + // 선착순 + FCFS_QUIZ_DESCRIPTION, + + FCFS_WINNER_TITLE, + FCFS_WINNER_SUBTITLE, + FCFS_WINNER_CODE_WORD, + FCFS_WINNER_EXPIRY_DATE, + FCFS_WINNER_CAUTION, + + FCFS_LOSER_TITLE, + FCFS_LOSER_SUBTITLE, + FCFS_LOSER_CAUTION; + +} diff --git a/src/main/java/com/softeer/backend/global/staticresources/domain/StaticResources.java b/src/main/java/com/softeer/backend/global/staticresources/domain/S3Content.java similarity index 73% rename from src/main/java/com/softeer/backend/global/staticresources/domain/StaticResources.java rename to src/main/java/com/softeer/backend/global/staticresources/domain/S3Content.java index 5c36b4af..bc53a3cf 100644 --- a/src/main/java/com/softeer/backend/global/staticresources/domain/StaticResources.java +++ b/src/main/java/com/softeer/backend/global/staticresources/domain/S3Content.java @@ -4,18 +4,17 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @NoArgsConstructor @AllArgsConstructor @Getter @Builder -@Table(name = "static_resources") -public class StaticResources { +@Table(name = "s3_content") +public class S3Content { @Id - @Column(name = "static_resources_id") + @Column(name = "s3_content_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; diff --git a/src/main/java/com/softeer/backend/global/staticresources/domain/TextContent.java b/src/main/java/com/softeer/backend/global/staticresources/domain/TextContent.java new file mode 100644 index 00000000..a802775e --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/domain/TextContent.java @@ -0,0 +1,26 @@ +package com.softeer.backend.global.staticresources.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Builder +@Table(name = "text_content") +public class TextContent { + @Id + @Column(name = "text_content_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "text_name", nullable = false) + private String textName; + + @Column(name = "content", nullable = false) + private String content; +} diff --git a/src/main/java/com/softeer/backend/global/staticresources/repository/S3ContentRepository.java b/src/main/java/com/softeer/backend/global/staticresources/repository/S3ContentRepository.java new file mode 100644 index 00000000..9b10e2c3 --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/repository/S3ContentRepository.java @@ -0,0 +1,8 @@ +package com.softeer.backend.global.staticresources.repository; + +import com.softeer.backend.global.staticresources.domain.S3Content; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface S3ContentRepository extends JpaRepository { +} + diff --git a/src/main/java/com/softeer/backend/global/staticresources/repository/StaticResourcesRepository.java b/src/main/java/com/softeer/backend/global/staticresources/repository/StaticResourcesRepository.java deleted file mode 100644 index 57932b85..00000000 --- a/src/main/java/com/softeer/backend/global/staticresources/repository/StaticResourcesRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.softeer.backend.global.staticresources.repository; - -import com.softeer.backend.global.staticresources.domain.StaticResources; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface StaticResourcesRepository extends JpaRepository { -} diff --git a/src/main/java/com/softeer/backend/global/staticresources/repository/TextContentRepository.java b/src/main/java/com/softeer/backend/global/staticresources/repository/TextContentRepository.java new file mode 100644 index 00000000..56e91592 --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/repository/TextContentRepository.java @@ -0,0 +1,7 @@ +package com.softeer.backend.global.staticresources.repository; + +import com.softeer.backend.global.staticresources.domain.TextContent; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TextContentRepository extends JpaRepository { +} diff --git a/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourceUtil.java b/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourceUtil.java new file mode 100644 index 00000000..8cb54a7d --- /dev/null +++ b/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourceUtil.java @@ -0,0 +1,60 @@ +package com.softeer.backend.global.staticresources.util; + +import com.softeer.backend.global.common.code.status.ErrorStatus; +import com.softeer.backend.global.common.exception.GeneralException; +import com.softeer.backend.global.staticresources.domain.S3Content; +import com.softeer.backend.global.staticresources.domain.TextContent; +import com.softeer.backend.global.staticresources.repository.S3ContentRepository; +import com.softeer.backend.global.staticresources.repository.TextContentRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.DayOfWeek; +import java.util.Map; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class StaticResourceUtil { + + private final TextContentRepository textContentRepository; + private final S3ContentRepository s3ContentRepository; + + public Map getTextContentMap() { + return textContentRepository.findAll().stream() + .collect(Collectors.toMap(TextContent::getTextName, TextContent::getContent)); + } + + public Map getS3ContentMap() { + return s3ContentRepository.findAll().stream() + .collect(Collectors.toMap(S3Content::getFileName, S3Content::getFileUrl)); + } + + public String format(String text, Object... args) { + return String.format(text, args); + } + + public String getKoreanDayOfWeek(DayOfWeek dayOfWeek) { + switch (dayOfWeek) { + case MONDAY: + return "월"; + case TUESDAY: + return "화"; + case WEDNESDAY: + return "수"; + case THURSDAY: + return "목"; + case FRIDAY: + return "금"; + case SATURDAY: + return "토"; + case SUNDAY: + return "일"; + default: + log.error("Korean day of week is not supported"); + throw new GeneralException(ErrorStatus._INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java b/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java deleted file mode 100644 index 8dfd5ace..00000000 --- a/src/main/java/com/softeer/backend/global/staticresources/util/StaticResourcesUtil.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.softeer.backend.global.staticresources.util; - -import com.softeer.backend.fo_domain.draw.repository.DrawRepository; -import com.softeer.backend.fo_domain.draw.service.DrawSettingManager; -import com.softeer.backend.fo_domain.fcfs.dto.FcfsSettingDto; -import com.softeer.backend.fo_domain.fcfs.service.FcfsSettingManager; -import com.softeer.backend.global.common.code.status.ErrorStatus; -import com.softeer.backend.global.common.exception.GeneralException; -import com.softeer.backend.global.staticresources.constant.StaticText; -import com.softeer.backend.global.staticresources.domain.StaticResources; -import com.softeer.backend.global.staticresources.repository.StaticResourcesRepository; -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.text.DecimalFormat; -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.stream.Collectors; - -@Slf4j -@Component -@RequiredArgsConstructor -public class StaticResourcesUtil { - - private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("a h", Locale.KOREAN); - private final DecimalFormat decimalFormat = new DecimalFormat("#,###"); - DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M월 d일"); - - private final StaticResourcesRepository staticResourcesRepository; - private final DrawSettingManager drawSettingManager; - private final FcfsSettingManager fcfsSettingManager; - private final DrawRepository drawRepository; - - private final Map staticResourcesMap = new HashMap<>(); - - @PostConstruct - public void init() { - loadInitialData(); - } - - public void loadInitialData() { - List staticResourcesList = staticResourcesRepository.findAll(); - - staticResourcesMap.putAll( - staticResourcesList.stream() - .collect(Collectors.toMap( - StaticResources::getFileName, - StaticResources::getFileUrl - )) - ); - - - FcfsSettingDto firstFcfsSetting = fcfsSettingManager.getFcfsSettingByRound(1); - FcfsSettingDto secondFcfsSetting = fcfsSettingManager.getFcfsSettingByRound(2); - - int totalDrawWinner = drawSettingManager.getWinnerNum1() - + drawSettingManager.getWinnerNum2() + drawSettingManager.getWinnerNum3(); - int remainDrawCount = totalDrawWinner - (int)drawRepository.count(); - - Map formattedTexts = Arrays.stream(StaticText.values()) - .collect(Collectors.toMap( - Enum::name, - enumValue -> { - switch (enumValue) { - case FCFS_INFO: - return enumValue.format(getKoreanDayOfWeek(firstFcfsSetting.getStartTime().getDayOfWeek()), - getKoreanDayOfWeek(secondFcfsSetting.getStartTime().getDayOfWeek()), - firstFcfsSetting.getStartTime().format(timeFormatter), - firstFcfsSetting.getWinnerNum()); - case TOTAL_DRAW_WINNER: - return enumValue.format(decimalFormat.format(totalDrawWinner)); - case REMAIN_DRAW_COUNT: - return enumValue.format(decimalFormat.format(remainDrawCount)); - case FCFS_QUIZ_DESCRIPTION, FCFS_WINNER_TITLE: - return enumValue.format(fcfsSettingManager.getFcfsWinnerNum()); - case FCFS_WINNER_EXPIRY_DATE: - return enumValue.format(firstFcfsSetting.getStartTime().getYear(), - firstFcfsSetting.getStartTime().format(dateFormatter), - drawSettingManager.getEndDate().plusDays(14).format(dateFormatter)); - - default: - return enumValue.getText(); - } - } - )); - - staticResourcesMap.putAll(formattedTexts); - } - - private static String getKoreanDayOfWeek(DayOfWeek dayOfWeek) { - switch (dayOfWeek) { - case MONDAY: - return "월"; - case TUESDAY: - return "화"; - case WEDNESDAY: - return "수"; - case THURSDAY: - return "목"; - case FRIDAY: - return "금"; - case SATURDAY: - return "토"; - case SUNDAY: - return "일"; - default: - log.error("Korean day of week is not supported"); - throw new GeneralException(ErrorStatus._INTERNAL_SERVER_ERROR); - } - } - - public String getData(String resourceKey) { - return staticResourcesMap.get(resourceKey); - } -}