Skip to content

Commit 85f3934

Browse files
committed
✨ feat: 마이페이지 기능 구현
1 parent 2d23468 commit 85f3934

File tree

6 files changed

+85
-13
lines changed

6 files changed

+85
-13
lines changed

backend/src/main/java/io/f1/backend/domain/stat/dao/StatRedisRepository.java

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import io.f1.backend.domain.stat.dto.StatPageResponse;
66
import io.f1.backend.domain.stat.dto.StatResponse;
77
import io.f1.backend.domain.stat.dto.StatWithNicknameAndUserId;
8-
8+
import io.f1.backend.domain.user.dto.MyPage;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Set;
12+
import java.util.concurrent.atomic.AtomicInteger;
913
import lombok.RequiredArgsConstructor;
10-
1114
import org.springframework.data.domain.PageRequest;
1215
import org.springframework.data.domain.Pageable;
1316
import org.springframework.data.domain.Sort;
@@ -19,14 +22,10 @@
1922
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
2023
import org.springframework.stereotype.Repository;
2124

22-
import java.util.List;
23-
import java.util.Map;
24-
import java.util.Set;
25-
import java.util.concurrent.atomic.AtomicInteger;
26-
2725
@Repository
2826
@RequiredArgsConstructor
2927
public class StatRedisRepository {
28+
3029
private static final String STAT_RANK = "stat:rank";
3130
private static final String STAT_USER = "stat:user:%d";
3231
private static final String STAT_NICKNAME = "stat:%s";
@@ -149,4 +148,24 @@ private static String getStatNickname(String nickname) {
149148
private long getUserIdFromNickname(String nickname) {
150149
return ((Number) requireNonNull(valueOps.get(getStatNickname(nickname)))).longValue();
151150
}
151+
152+
public MyPage getStatByUserId(long userId) {
153+
String statUserKey = getStatUserKey(userId);
154+
155+
Long rank = zSetOps.reverseRank(STAT_RANK, userId);
156+
Double score = zSetOps.score(STAT_RANK, userId);
157+
Map<Object, Object> statMap = hashOps.entries(statUserKey);
158+
159+
if (rank == null || score == null || statMap.isEmpty()) {
160+
throw new IllegalStateException("User not found in Redis: " + userId);
161+
}
162+
163+
return new MyPage(
164+
(String) statMap.get("nickname"),
165+
rank + 1,
166+
(long) statMap.get("totalGames"),
167+
(long) statMap.get("winningGames"),
168+
score.longValue()
169+
);
170+
}
152171
}

backend/src/main/java/io/f1/backend/domain/stat/dao/StatRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.f1.backend.domain.stat.dto.StatPageResponse;
44

5+
import io.f1.backend.domain.user.dto.MyPage;
56
import org.springframework.data.domain.Pageable;
67

78
public interface StatRepository {
@@ -17,4 +18,6 @@ public interface StatRepository {
1718
void updateNickname(long userId, String nickname);
1819

1920
void removeUser(long userId);
21+
22+
MyPage getMyPageByUserId(long userId);
2023
}

backend/src/main/java/io/f1/backend/domain/stat/dao/StatRepositoryAdapter.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
import io.f1.backend.domain.stat.dto.StatPageResponse;
66
import io.f1.backend.domain.stat.dto.StatWithNickname;
77
import io.f1.backend.domain.stat.dto.StatWithNicknameAndUserId;
8+
import io.f1.backend.domain.user.dto.MyPage;
89
import io.f1.backend.global.exception.CustomException;
910
import io.f1.backend.global.exception.errorcode.RoomErrorCode;
10-
11+
import io.f1.backend.global.exception.errorcode.UserErrorCode;
1112
import jakarta.annotation.PostConstruct;
12-
1313
import lombok.RequiredArgsConstructor;
1414
import lombok.extern.slf4j.Slf4j;
15-
1615
import org.springframework.data.domain.Page;
1716
import org.springframework.data.domain.PageRequest;
1817
import org.springframework.data.domain.Pageable;
@@ -97,4 +96,32 @@ private Pageable getPageableFromNickname(String nickname, int pageSize) {
9796
int pageNumber = rowNum > 0 ? (int) (rowNum / pageSize) : 0;
9897
return PageRequest.of(pageNumber, pageSize, Sort.by(Direction.DESC, "score"));
9998
}
99+
100+
@Override
101+
public MyPage getMyPageByUserId(long userId) {
102+
try {
103+
return redisRepository.getStatByUserId(userId);
104+
} catch (Exception e) {
105+
log.error("Redis miss, fallback to MySQL for userId={}", userId, e);
106+
}
107+
108+
StatWithNicknameAndUserId stat = findFirstMatchingStat(userId);
109+
long rank = jpaRepository.countByScoreGreaterThan(stat.score()) + 1;
110+
111+
return new MyPage(
112+
stat.nickname(),
113+
rank,
114+
stat.totalGames(),
115+
stat.winningGames(),
116+
stat.score()
117+
);
118+
}
119+
120+
private StatWithNicknameAndUserId findFirstMatchingStat(long userId) {
121+
return jpaRepository.findAllStatWithNicknameAndUserId()
122+
.stream()
123+
.filter(stat -> stat.userId() == userId)
124+
.findFirst()
125+
.orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND));
126+
}
100127
}

backend/src/main/java/io/f1/backend/domain/user/api/UserController.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static io.f1.backend.global.util.SecurityUtils.logout;
44

55
import io.f1.backend.domain.user.app.UserService;
6+
import io.f1.backend.domain.user.dto.MyPage;
67
import io.f1.backend.domain.user.dto.SignupRequest;
78
import io.f1.backend.domain.user.dto.UserPrincipal;
89

@@ -13,6 +14,7 @@
1314
import org.springframework.http.ResponseEntity;
1415
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1516
import org.springframework.web.bind.annotation.DeleteMapping;
17+
import org.springframework.web.bind.annotation.GetMapping;
1618
import org.springframework.web.bind.annotation.PutMapping;
1719
import org.springframework.web.bind.annotation.RequestBody;
1820
import org.springframework.web.bind.annotation.RequestMapping;
@@ -42,4 +44,10 @@ public ResponseEntity<Void> updateNickname(
4244
userPrincipal.getUserId(), signupRequest.nickname(), httpSession);
4345
return ResponseEntity.noContent().build();
4446
}
47+
48+
@GetMapping
49+
public ResponseEntity<MyPage> getMyPage(@AuthenticationPrincipal UserPrincipal userPrincipal){
50+
MyPage response = userService.getMyPage(userPrincipal);
51+
return ResponseEntity.ok(response);
52+
}
4553
}

backend/src/main/java/io/f1/backend/domain/user/app/UserService.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import static io.f1.backend.global.util.RedisPublisher.USER_UPDATE;
88

99
import io.f1.backend.domain.auth.dto.CurrentUserAndAdminResponse;
10+
import io.f1.backend.domain.stat.dao.StatRepository;
1011
import io.f1.backend.domain.user.dao.UserRepository;
1112
import io.f1.backend.domain.user.dto.AuthenticationUser;
13+
import io.f1.backend.domain.user.dto.MyPage;
1214
import io.f1.backend.domain.user.dto.SignupRequest;
1315
import io.f1.backend.domain.user.dto.UserPrincipal;
1416
import io.f1.backend.domain.user.dto.UserSummary;
@@ -18,11 +20,8 @@
1820
import io.f1.backend.global.exception.errorcode.UserErrorCode;
1921
import io.f1.backend.global.util.RedisPublisher;
2022
import io.f1.backend.global.util.SecurityUtils;
21-
2223
import jakarta.servlet.http.HttpSession;
23-
2424
import lombok.RequiredArgsConstructor;
25-
2625
import org.springframework.stereotype.Service;
2726
import org.springframework.transaction.annotation.Transactional;
2827

@@ -32,6 +31,7 @@ public class UserService {
3231

3332
private final UserRepository userRepository;
3433
private final RedisPublisher redisPublisher;
34+
private final StatRepository statRepository;
3535

3636
@Transactional
3737
public CurrentUserAndAdminResponse signup(HttpSession session, SignupRequest signupRequest) {
@@ -122,4 +122,10 @@ public void checkNickname(String nickname) {
122122
validateNicknameFormat(nickname);
123123
validateNicknameDuplicate(nickname);
124124
}
125+
126+
@Transactional(readOnly = true)
127+
public MyPage getMyPage(UserPrincipal userPrincipal) {
128+
Long userId = userPrincipal.getUserId();
129+
return statRepository.getMyPageByUserId(userId);
130+
}
125131
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.f1.backend.domain.user.dto;
2+
3+
public record MyPage(
4+
String nickname,
5+
long rank,
6+
long score,
7+
long totalGames,
8+
long winningGames
9+
) {}

0 commit comments

Comments
 (0)