Skip to content

Commit 4849e9e

Browse files
committed
feat: 주간 및 월간 랭킹 조회 기능 추가
1 parent 15aece1 commit 4849e9e

1 file changed

Lines changed: 87 additions & 34 deletions

File tree

apps/commerce-api/src/main/java/com/loopers/domain/ranking/RankingService.java

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,25 @@
66
import org.springframework.data.redis.core.ZSetOperations;
77
import org.springframework.stereotype.Service;
88

9+
import java.time.DayOfWeek;
910
import java.time.LocalDate;
11+
import java.time.YearMonth;
12+
import java.time.format.DateTimeFormatter;
1013
import java.util.*;
1114

12-
/**
13-
* 랭킹 조회 서비스 (commerce-api용)
14-
*/
1515
@Slf4j
1616
@Service
1717
@RequiredArgsConstructor
1818
public class RankingService {
1919

2020
private final RedisTemplate<String, String> redisTemplate;
21+
private final RankingRepository rankingRepository;
22+
23+
private static final String KEY_PREFIX = "ranking:all:";
24+
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
2125

22-
/**
23-
* Top-N 랭킹 조회 (점수 포함)
24-
*/
2526
public List<RankingEntry> getTopNWithScores(LocalDate date, int n) {
26-
String key = RankingKey.daily(date);
27+
String key = KEY_PREFIX + date.format(DATE_FORMATTER);
2728

2829
try {
2930
Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet()
@@ -40,11 +41,8 @@ public List<RankingEntry> getTopNWithScores(LocalDate date, int n) {
4041
}
4142
}
4243

43-
/**
44-
* 페이지네이션 랭킹 조회
45-
*/
4644
public List<RankingEntry> getRankingPage(LocalDate date, int page, int size) {
47-
String key = RankingKey.daily(date);
45+
String key = KEY_PREFIX + date.format(DATE_FORMATTER);
4846
long start = (long) page * size;
4947
long end = start + size - 1;
5048

@@ -63,13 +61,8 @@ public List<RankingEntry> getRankingPage(LocalDate date, int page, int size) {
6361
}
6462
}
6563

66-
/**
67-
* 특정 상품의 순위 조회
68-
*
69-
* @return 순위 (1부터 시작), 랭킹에 없으면 null
70-
*/
7164
public Long getRank(Long productId, LocalDate date) {
72-
String key = RankingKey.daily(date);
65+
String key = KEY_PREFIX + date.format(DATE_FORMATTER);
7366
String member = productId.toString();
7467

7568
try {
@@ -81,36 +74,96 @@ public Long getRank(Long productId, LocalDate date) {
8174
}
8275
}
8376

84-
/**
85-
* 특정 상품의 점수 조회
86-
*/
87-
public Double getScore(Long productId, LocalDate date) {
88-
String key = RankingKey.daily(date);
89-
String member = productId.toString();
77+
public Long getRankingSize(LocalDate date) {
78+
String key = KEY_PREFIX + date.format(DATE_FORMATTER);
9079

9180
try {
92-
return redisTemplate.opsForZSet().score(key, member);
81+
Long size = redisTemplate.opsForZSet().zCard(key);
82+
return size != null ? size : 0L;
9383
} catch (Exception e) {
94-
log.error("점수 조회 실패: key={}, productId={}", key, productId, e);
84+
log.error("랭킹 사이즈 조회 실패: key={}", key, e);
85+
return 0L;
86+
}
87+
}
88+
89+
public List<RankingEntry> getWeeklyRankingPage(LocalDate date, int page, int size) {
90+
LocalDate weekStart = date.with(DayOfWeek.MONDAY);
91+
LocalDate weekEnd = date.with(DayOfWeek.SUNDAY);
92+
int offset = page * size;
93+
94+
try {
95+
List<WeeklyRanking> ranks = rankingRepository.findWeeklyByDateOrderByRank(weekStart, weekEnd, size, offset);
96+
return ranks.stream()
97+
.map(r -> new RankingEntry(r.getProductId(), r.getScore()))
98+
.toList();
99+
} catch (Exception e) {
100+
log.error("주간 랭킹 페이지 조회 실패: weekStart={}, weekEnd={}, page={}, size={}",
101+
weekStart, weekEnd, page, size, e);
102+
return Collections.emptyList();
103+
}
104+
}
105+
106+
public List<RankingEntry> getWeeklyTopN(LocalDate date, int n) {
107+
return getWeeklyRankingPage(date, 0, n);
108+
}
109+
110+
public Long getWeeklyRank(Long productId, LocalDate date) {
111+
LocalDate weekStart = date.with(DayOfWeek.MONDAY);
112+
LocalDate weekEnd = date.with(DayOfWeek.SUNDAY);
113+
114+
try {
115+
return rankingRepository.findWeeklyByProductIdAndDate(productId, weekStart, weekEnd)
116+
.map(r -> (long) r.getRank())
117+
.orElse(null);
118+
} catch (Exception e) {
119+
log.error("주간 순위 조회 실패: productId={}, weekStart={}, weekEnd={}", productId, weekStart, weekEnd, e);
95120
return null;
96121
}
97122
}
98123

99-
/**
100-
* 랭킹에 진입한 상품 수 조회
101-
*/
102-
public Long getRankingSize(LocalDate date) {
103-
String key = RankingKey.daily(date);
124+
public Long getWeeklyRankingSize(LocalDate date) {
125+
LocalDate weekStart = date.with(DayOfWeek.MONDAY);
126+
LocalDate weekEnd = date.with(DayOfWeek.SUNDAY);
127+
return rankingRepository.countWeeklyByDate(weekStart, weekEnd);
128+
}
129+
130+
public List<RankingEntry> getMonthlyRankingPage(LocalDate date, int page, int size) {
131+
YearMonth yearMonth = YearMonth.from(date);
132+
int offset = page * size;
104133

105134
try {
106-
Long size = redisTemplate.opsForZSet().zCard(key);
107-
return size != null ? size : 0L;
135+
List<MonthlyRanking> ranks = rankingRepository.findMonthlyByPeriodOrderByRank(yearMonth, size, offset);
136+
return ranks.stream()
137+
.map(r -> new RankingEntry(r.getProductId(), r.getScore()))
138+
.toList();
108139
} catch (Exception e) {
109-
log.error("랭킹 사이즈 조회 실패: key={}", key, e);
110-
return 0L;
140+
log.error("월간 랭킹 페이지 조회 실패: yearMonth={}, page={}, size={}", yearMonth, page, size, e);
141+
return Collections.emptyList();
142+
}
143+
}
144+
145+
public List<RankingEntry> getMonthlyTopN(LocalDate date, int n) {
146+
return getMonthlyRankingPage(date, 0, n);
147+
}
148+
149+
public Long getMonthlyRank(Long productId, LocalDate date) {
150+
YearMonth yearMonth = YearMonth.from(date);
151+
152+
try {
153+
return rankingRepository.findMonthlyByProductIdAndPeriod(productId, yearMonth)
154+
.map(r -> (long) r.getRank())
155+
.orElse(null);
156+
} catch (Exception e) {
157+
log.error("월간 순위 조회 실패: productId={}, yearMonth={}", productId, yearMonth, e);
158+
return null;
111159
}
112160
}
113161

162+
public Long getMonthlyRankingSize(LocalDate date) {
163+
YearMonth yearMonth = YearMonth.from(date);
164+
return rankingRepository.countMonthlyByPeriod(yearMonth);
165+
}
166+
114167
private List<RankingEntry> convertToRankingEntries(Set<ZSetOperations.TypedTuple<String>> tuples) {
115168
List<RankingEntry> entries = new ArrayList<>();
116169
for (ZSetOperations.TypedTuple<String> tuple : tuples) {

0 commit comments

Comments
 (0)