From 4e9c55ca4da28e6e8c5cd980b19b6835f69eabe2 Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:20:11 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=88=98=20=EA=B8=B0=EC=A4=80=20=EB=9E=AD=ED=82=B9=20Top3=20?= =?UTF-8?q?=EB=B6=80=EC=8A=A4=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8A=94=20API=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/booth/BoothQueryService.java | 27 ++++++++++++++++++- .../booth/BoothApiController.java | 8 ++++++ .../booth/dto/BoothTop3ResponseDto.java | 7 +++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java diff --git a/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java b/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java index b7b145c..ab1e711 100644 --- a/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java +++ b/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java @@ -17,6 +17,7 @@ import kr.co.knuserver.presentation.booth.dto.BoothInfoResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothListResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothRankingResponseDto; +import kr.co.knuserver.presentation.booth.dto.BoothTop3ResponseDto; import org.springframework.data.redis.core.ZSetOperations; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; @@ -96,7 +97,31 @@ public List getBoothRanking() { .toList(); } - + public List getTop3BoothRanking() { + Set> rawRanking = boothLikeService.getRanking(); + if (rawRanking == null || rawRanking.isEmpty()) { + return List.of(); + } + + BoothRanking boothRanking = new BoothRanking(rawRanking); + if (boothRanking.isEmpty()) { + return List.of(); + } + + List booths = boothRepository.findAllById(boothRanking.boothIds()); + + return booths.stream() + .map(booth -> new BoothTop3ResponseDto( + booth.getId(), + booth.getName(), + boothRanking.getLikeCount(booth.getId()) + )) + .sorted(Comparator.comparingLong(BoothTop3ResponseDto::likeCount).reversed() + .thenComparingLong(BoothTop3ResponseDto::boothId)) + .limit(3) + .toList(); + } + public CursorPaginationResponse searchBoothsByKeyword2(String keyword, Long lastId, int size) { Pageable pageable = PageRequest.of(0, size + 1); List booths; diff --git a/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java b/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java index e38e0c4..a816e51 100644 --- a/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java +++ b/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java @@ -11,6 +11,7 @@ import kr.co.knuserver.presentation.booth.dto.BoothInfoResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothListResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothRankingResponseDto; +import kr.co.knuserver.presentation.booth.dto.BoothTop3ResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothUpdateRequestDto; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -85,4 +86,11 @@ public ResponseEntity>> getBoothRankin List result = boothQueryService.getBoothRanking(); return ResponseEntity.ok(ApiResponse.success(result)); } + + @Override + @GetMapping("/ranking/top3") + public ResponseEntity>> getTop3BoothRanking() { + List result = boothQueryService.getTop3BoothRanking(); + return ResponseEntity.ok(ApiResponse.success(result)); + } } diff --git a/src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java b/src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java new file mode 100644 index 0000000..b8185bc --- /dev/null +++ b/src/main/java/kr/co/knuserver/presentation/booth/dto/BoothTop3ResponseDto.java @@ -0,0 +1,7 @@ +package kr.co.knuserver.presentation.booth.dto; + +public record BoothTop3ResponseDto( + Long boothId, + String boothName, + long likeCount +) {} From a2550d1833abc86ae7440c690b23e207c2e7c960 Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:20:19 +0900 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=88=98=20=EA=B8=B0=EC=A4=80=20=EB=9E=AD=ED=82=B9=20Top3=20?= =?UTF-8?q?=EB=B6=80=EC=8A=A4=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8A=94=20API=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/booth/docs/BoothApiControllerDocs.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java b/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java index ecbfbb3..364e546 100644 --- a/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java +++ b/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java @@ -11,6 +11,7 @@ import kr.co.knuserver.presentation.booth.dto.BoothCountResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothInfoResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothListResponseDto; +import kr.co.knuserver.presentation.booth.dto.BoothTop3ResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothUpdateRequestDto; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -60,4 +61,10 @@ ResponseEntity>> getTop3BoothRanking(); } From 829df2989505c8ff52415295820c30bdb08fd6de Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:40:00 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20TOP=203=20=EC=A2=8B=EC=95=84?= =?UTF-8?q?=EC=9A=94=20=EB=B6=80=EC=8A=A4=20=EB=9E=AD=ED=82=B9=20API=20?= =?UTF-8?q?=EC=8B=A0=EC=84=A4=20=EB=B0=8F=20Redis=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../co/knuserver/application/booth/BoothLikeService.java | 9 +++++++++ .../knuserver/application/booth/BoothQueryService.java | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java index 2c87d92..ae63c4c 100644 --- a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java +++ b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java @@ -71,6 +71,15 @@ public Set> getRanking() { } } + public Set> getTopRanking(int limit) { + try { + return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1); + } catch (DataAccessException e) { + log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e); + return Collections.emptySet(); + } + } + private void checkRateLimit(String clientIp, String deviceId, Long boothId) { String rateLimitKey = RATE_LIMIT_KEY.formatted(clientIp, deviceId, boothId); log.debug("[RateLimit] key={}", rateLimitKey); diff --git a/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java b/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java index ab1e711..90e632c 100644 --- a/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java +++ b/src/main/java/kr/co/knuserver/application/booth/BoothQueryService.java @@ -98,7 +98,7 @@ public List getBoothRanking() { } public List getTop3BoothRanking() { - Set> rawRanking = boothLikeService.getRanking(); + Set> rawRanking = boothLikeService.getTopRanking(10); if (rawRanking == null || rawRanking.isEmpty()) { return List.of(); } From a67e02af93b91d88cdae366826bdd233be5a0d83 Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:43:34 +0900 Subject: [PATCH 4/6] =?UTF-8?q?docs:=20=EB=88=84=EB=9D=BD=EB=90=9C=20swagg?= =?UTF-8?q?er=20=EB=AC=B8=EC=84=9C=20=EC=9E=91=EC=84=B1=20=EB=B0=8F=20over?= =?UTF-8?q?ride=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../knuserver/presentation/booth/BoothApiController.java | 1 + .../presentation/booth/docs/BoothApiControllerDocs.java | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java b/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java index a816e51..8d4f585 100644 --- a/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java +++ b/src/main/java/kr/co/knuserver/presentation/booth/BoothApiController.java @@ -81,6 +81,7 @@ public ResponseEntity .body(ApiResponse.success(result)); } + @Override @GetMapping("/ranking") public ResponseEntity>> getBoothRanking() { List result = boothQueryService.getBoothRanking(); diff --git a/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java b/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java index 364e546..2f9f9f7 100644 --- a/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java +++ b/src/main/java/kr/co/knuserver/presentation/booth/docs/BoothApiControllerDocs.java @@ -11,6 +11,7 @@ import kr.co.knuserver.presentation.booth.dto.BoothCountResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothInfoResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothListResponseDto; +import kr.co.knuserver.presentation.booth.dto.BoothRankingResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothTop3ResponseDto; import kr.co.knuserver.presentation.booth.dto.BoothUpdateRequestDto; import org.springframework.http.ResponseEntity; @@ -62,6 +63,12 @@ ResponseEntity>> getBoothRanking(); + @Operation(summary = "가두모집 부스 좋아요 TOP 3 조회", description = "좋아요 수 기준 상위 3개 부스를 반환합니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "TOP 3 랭킹 조회 성공") From a945f202ae6343457bc78348eb085133763b7850 Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:48:45 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20TOP=203=20=EC=A2=8B=EC=95=84?= =?UTF-8?q?=EC=9A=94=20=EB=B6=80=EC=8A=A4=20=EB=9E=AD=ED=82=B9=20API,=20Re?= =?UTF-8?q?dis=20=EC=A1=B0=ED=9A=8C=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java --- .../co/knuserver/application/booth/BoothLikeService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java index dd18541..bfbee34 100644 --- a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java +++ b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java @@ -106,6 +106,15 @@ private int getLikeMultiplier() { return isEventTime ? 2 : 1; } + public Set> getTopRanking(int limit) { + try { + return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1); + } catch (DataAccessException e) { + log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e); + return Collections.emptySet(); + } + } + private void checkRateLimit(String clientIp, String deviceId, Long boothId) { String rateLimitKey = RATE_LIMIT_KEY.formatted(clientIp, deviceId, boothId); log.debug("[RateLimit] key={}", rateLimitKey); From fa378afdec61f7b3fe9661914f67f084977577da Mon Sep 17 00:00:00 2001 From: milk-stone Date: Mon, 16 Mar 2026 17:51:50 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20git=20conflict=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/booth/BoothLikeService.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java index bfbee34..7e4a308 100644 --- a/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java +++ b/src/main/java/kr/co/knuserver/application/booth/BoothLikeService.java @@ -91,7 +91,8 @@ public Set> getTopRanking(int limit) { log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e); return Collections.emptySet(); } - + } + private int getLikeMultiplier() { if (!doubleEventEnabled) { return 1; @@ -106,15 +107,6 @@ private int getLikeMultiplier() { return isEventTime ? 2 : 1; } - public Set> getTopRanking(int limit) { - try { - return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, limit - 1); - } catch (DataAccessException e) { - log.warn("[Ranking] Redis 조회 실패, 빈 셋 반환", e); - return Collections.emptySet(); - } - } - private void checkRateLimit(String clientIp, String deviceId, Long boothId) { String rateLimitKey = RATE_LIMIT_KEY.formatted(clientIp, deviceId, boothId); log.debug("[RateLimit] key={}", rateLimitKey);