-
Notifications
You must be signed in to change notification settings - Fork 1
[Feat] 독서메이트 조회 api 개발 #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0f283a3
6de3b78
13e89ee
be4eb77
8f28789
9041b22
f05874a
5f5fa87
802fc6b
7702387
5f8ac0c
e1d1d06
7f1eab3
ab1478b
09a4324
24051bd
1077995
4572dea
04be116
59991ff
7598586
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package konkuk.thip.room.adapter.in.web.response; | ||
|
|
||
| import lombok.Builder; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Builder | ||
| public record RoomGetMemberListResponse( | ||
|
|
||
| List<MemberSearchResult> userList | ||
| ){ | ||
| @Builder | ||
| public record MemberSearchResult( | ||
| Long userId, | ||
| String nickname, | ||
| String imageUrl, | ||
| String alias, | ||
| int subscriberCount | ||
| ) {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package konkuk.thip.room.application.port.in; | ||
|
|
||
| import konkuk.thip.room.adapter.in.web.response.RoomGetMemberListResponse; | ||
|
|
||
| public interface RoomGetMemberListUseCase { | ||
| RoomGetMemberListResponse getRoomMemberList(Long roomId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package konkuk.thip.room.application.service; | ||
|
|
||
| import konkuk.thip.room.adapter.in.web.response.RoomGetMemberListResponse; | ||
| import konkuk.thip.room.application.port.in.RoomGetMemberListUseCase; | ||
| import konkuk.thip.room.application.port.out.RoomCommandPort; | ||
| import konkuk.thip.room.domain.Room; | ||
| import konkuk.thip.user.application.port.out.FollowingQueryPort; | ||
| import konkuk.thip.user.application.port.out.UserCommandPort; | ||
| import konkuk.thip.user.application.port.out.UserRoomCommandPort; | ||
| import konkuk.thip.user.domain.User; | ||
| import konkuk.thip.user.domain.UserRoom; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class RoomGetMemberListService implements RoomGetMemberListUseCase { | ||
|
|
||
| private final RoomCommandPort roomCommandPort; | ||
| private final UserRoomCommandPort userRoomCommandPort; | ||
| private final UserCommandPort userCommandPort; | ||
| private final FollowingQueryPort followingQueryPort; | ||
|
|
||
| @Override | ||
| @Transactional(readOnly = true) | ||
| public RoomGetMemberListResponse getRoomMemberList(Long roomId) { | ||
|
|
||
| // 1. 방 검증 및 방 조회 | ||
| Room room = roomCommandPort.findById(roomId); | ||
|
|
||
| // 2. 방 참여자(UserRoom) 전체 조회 | ||
| List<UserRoom> userRooms = userRoomCommandPort.findAllByRoomId(room.getId()); | ||
|
|
||
|
|
||
| // 3. 참여자 userId 목록 추출 | ||
| List<Long> userIds = userRooms.stream() | ||
| .map(UserRoom::getUserId) | ||
| .toList(); | ||
|
|
||
| // 4. 배치 쿼리로 유저 정보, 팔로워 수 조회 | ||
| Map<Long, User> userMap = userCommandPort.findByIds(userIds); | ||
| Map<Long, Integer> subscriberCountMap = followingQueryPort.countByFollowingUserIds(userIds); | ||
|
|
||
| // 5. 각 userRoom에 대해 DTO 조립 | ||
| List<RoomGetMemberListResponse.MemberSearchResult> userList = userRooms.stream() | ||
| .map(userRoom -> { | ||
| Long userId = userRoom.getUserId(); | ||
| User user = userMap.get(userId); | ||
| int subscriberCount = subscriberCountMap.getOrDefault(userId, 0); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
|
|
||
| return RoomGetMemberListResponse.MemberSearchResult.builder() | ||
| .userId(userId) | ||
| .nickname(user.getNickname()) | ||
| .imageUrl(user.getAlias().getImageUrl()) | ||
| .alias(user.getAlias().getValue()) | ||
| .subscriberCount(subscriberCount) | ||
| .build(); | ||
| }) | ||
| .toList(); | ||
|
|
||
| // 6. DTO 반환 | ||
| return RoomGetMemberListResponse.builder() | ||
| .userList(userList) | ||
| .build(); | ||
| } | ||
|
|
||
|
|
||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package konkuk.thip.user.adapter.out.persistence; | ||
|
|
||
| import konkuk.thip.user.adapter.out.jpa.FollowingJpaEntity; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| public interface FollowingJpaRepository extends JpaRepository<FollowingJpaEntity, Long>,FollowingQueryRepository { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package konkuk.thip.user.adapter.out.persistence; | ||
|
|
||
| import konkuk.thip.user.adapter.out.mapper.FollowingMapper; | ||
| import konkuk.thip.user.application.port.out.FollowingQueryPort; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| @Repository | ||
| @RequiredArgsConstructor | ||
| public class FollowingQueryPersistenceAdapter implements FollowingQueryPort { | ||
|
|
||
| private final FollowingJpaRepository followingJpaRepository; | ||
| private final FollowingMapper followingMapper; | ||
|
|
||
| @Override | ||
| public Map<Long, Integer> countByFollowingUserIds(List<Long> userIds) { | ||
| return followingJpaRepository.countByFollowingUserIds(userIds); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package konkuk.thip.user.adapter.out.persistence; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public interface FollowingQueryRepository { | ||
| Map<Long, Integer> countByFollowingUserIds(List<Long> userIds); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package konkuk.thip.user.adapter.out.persistence; | ||
|
|
||
| import com.querydsl.core.Tuple; | ||
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||
| import konkuk.thip.user.adapter.out.jpa.QFollowingJpaEntity; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| @Repository | ||
| @RequiredArgsConstructor | ||
| public class FollowingQueryRepositoryImpl implements FollowingQueryRepository { | ||
|
|
||
| private final JPAQueryFactory jpaQueryFactory; | ||
|
|
||
| // 주어진 userId 리스트에 대해 각 userId의 팔로워(구독자) 수를 집계하여 Map으로 반환 | ||
| public Map<Long, Integer> countByFollowingUserIds(List<Long> userIds) { | ||
|
|
||
| QFollowingJpaEntity following = QFollowingJpaEntity.followingJpaEntity; | ||
|
|
||
| List<Tuple> results = jpaQueryFactory | ||
| .select(following.followingUserJpaEntity.userId, following.count()) | ||
| .from(following) | ||
| .where(following.followingUserJpaEntity.userId.in(userIds)) | ||
| .groupBy(following.followingUserJpaEntity.userId) | ||
| .fetch(); | ||
|
|
||
| // 결과를 Map<Long, Integer>로 변환 | ||
| return results.stream() | ||
| .collect(Collectors.toMap( | ||
| tuple -> tuple.get(following.followingUserJpaEntity.userId), | ||
| tuple -> tuple.get(following.count()).intValue() | ||
| )); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Repository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.function.Function; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.stream.Collectors; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static konkuk.thip.common.exception.code.ErrorCode.ALIAS_NOT_FOUND; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static konkuk.thip.common.exception.code.ErrorCode.USER_NOT_FOUND; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -37,4 +42,12 @@ public User findById(Long userId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return userMapper.toDomainEntity(userJpaEntity); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Map<Long, User> findByIds(List<Long> userIds) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<UserJpaEntity> entities = userJpaRepository.findAllById(userIds); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return entities.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(userMapper::toDomainEntity) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .collect(Collectors.toMap(User::getId, Function.identity())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 구현 로직은 올바르나 예외 처리와 입력 검증을 강화해야 합니다. 현재 구현은 기본적인 기능은 수행하지만 몇 가지 중요한 개선사항이 필요합니다:
다음과 같은 개선된 구현을 제안합니다: @Override
public Map<Long, User> findByIds(List<Long> userIds) {
+ if (userIds == null || userIds.isEmpty()) {
+ return Map.of();
+ }
+
List<UserJpaEntity> entities = userJpaRepository.findAllById(userIds);
+
+ // 존재하지 않는 사용자 ID 검증 (선택사항)
+ if (entities.size() != userIds.size()) {
+ Set<Long> foundIds = entities.stream()
+ .map(UserJpaEntity::getUserId)
+ .collect(Collectors.toSet());
+ List<Long> missingIds = userIds.stream()
+ .filter(id -> !foundIds.contains(id))
+ .collect(Collectors.toList());
+ // 로깅 또는 예외 처리 고려
+ }
+
return entities.stream()
.map(userMapper::toDomainEntity)
.collect(Collectors.toMap(User::getId, Function.identity()));
}또는 더 간단한 방식으로 null 체크만 추가할 수도 있습니다: @Override
public Map<Long, User> findByIds(List<Long> userIds) {
+ if (userIds == null || userIds.isEmpty()) {
+ return Map.of();
+ }
+
List<UserJpaEntity> entities = userJpaRepository.findAllById(userIds);
return entities.stream()
.map(userMapper::toDomainEntity)
.collect(Collectors.toMap(User::getId, Function.identity()));
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package konkuk.thip.user.application.port.out; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public interface FollowingQueryPort { | ||
| Map<Long, Integer> countByFollowingUserIds(List<Long> userIds); | ||
| } | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.