From 43134d23b3bf9be2eebdee598fa9794354637952 Mon Sep 17 00:00:00 2001 From: heeone1 Date: Wed, 21 Jan 2026 17:35:22 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=B5=9C=EB=8C=80=2010=EB=AA=85=EB=A7=8C?= =?UTF-8?q?=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/controller/FriendController.java | 8 +++---- .../domain/friend/dto/FriendListResDto.java | 12 ++++++++++ .../friend/exception/FriendErrorCode.java | 1 + .../friend/repository/FriendRepository.java | 2 ++ .../domain/friend/service/FriendService.java | 22 ++++++++++++++----- 5 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/example/egobook_be/domain/friend/dto/FriendListResDto.java diff --git a/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java b/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java index 219e029..5ad85b8 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java +++ b/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java @@ -1,9 +1,6 @@ package com.example.egobook_be.domain.friend.controller; -import com.example.egobook_be.domain.friend.dto.FriendRequestCreateReqDto; -import com.example.egobook_be.domain.friend.dto.FriendRequestListResDto; -import com.example.egobook_be.domain.friend.dto.FriendResDto; -import com.example.egobook_be.domain.friend.dto.FriendSearchResDto; +import com.example.egobook_be.domain.friend.dto.*; import com.example.egobook_be.domain.friend.service.FriendService; import com.example.egobook_be.global.response.GlobalResponse; import io.swagger.v3.oas.annotations.Operation; @@ -52,6 +49,7 @@ public ResponseEntity> requestFriend( 받은 친구 신청을 수락합니다. - 수락 시 양방향 친구 관계가 생성됩니다. + - 친구는 최대 10명까지만 추가할 수 있으며, 초과 시 수락이 실패합니다. """ ) @PostMapping("/requests/{requestId}/accept") @@ -168,7 +166,7 @@ public ResponseEntity>> getOutgoing """ ) @GetMapping - public ResponseEntity>> getFriends( + public ResponseEntity> getFriends( @AuthenticationPrincipal(expression = "userAuthDto.userId") @Parameter(hidden = true) Long userId ) { diff --git a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendListResDto.java b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendListResDto.java new file mode 100644 index 0000000..2bb2e75 --- /dev/null +++ b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendListResDto.java @@ -0,0 +1,12 @@ +package com.example.egobook_be.domain.friend.dto; + +import lombok.Builder; + +import java.util.List; + +@Builder +public record FriendListResDto( + int count, + List friends +) { +} diff --git a/src/main/java/com/example/egobook_be/domain/friend/exception/FriendErrorCode.java b/src/main/java/com/example/egobook_be/domain/friend/exception/FriendErrorCode.java index cacde59..4ae6bef 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/exception/FriendErrorCode.java +++ b/src/main/java/com/example/egobook_be/domain/friend/exception/FriendErrorCode.java @@ -20,6 +20,7 @@ public enum FriendErrorCode implements BaseErrorCode { */ ALREADY_FRIEND(HttpStatus.CONFLICT, "이미 친구 관계입니다."), ALREADY_REQUESTED(HttpStatus.CONFLICT, "이미 친구 신청을 보낸 상태입니다."), + FRIEND_LIMIT_EXCEEDED(HttpStatus.CONFLICT, "친구는 최대 10명까지만 추가할 수 있습니다."), /** * 400 BAD_REQUEST diff --git a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java index 0631010..ff4b9a1 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java +++ b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java @@ -17,6 +17,8 @@ public interface FriendRepository extends JpaRepository { List findByUser(User user); + long countByUser(User user); + @Query(""" select f.friend.id from Friend f diff --git a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java index d2b0a07..966c6ee 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java +++ b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java @@ -1,9 +1,6 @@ package com.example.egobook_be.domain.friend.service; -import com.example.egobook_be.domain.friend.dto.FriendRequestCreateReqDto; -import com.example.egobook_be.domain.friend.dto.FriendRequestListResDto; -import com.example.egobook_be.domain.friend.dto.FriendResDto; -import com.example.egobook_be.domain.friend.dto.FriendSearchResDto; +import com.example.egobook_be.domain.friend.dto.*; import com.example.egobook_be.domain.friend.entity.Friend; import com.example.egobook_be.domain.friend.entity.FriendRequest; import com.example.egobook_be.domain.friend.enums.FriendRequestStatus; @@ -87,6 +84,14 @@ public void acceptRequest(Long receiverId, Long requestId) { .findByIdAndReceiver(requestId, receiver) .orElseThrow(() -> new CustomException(FriendErrorCode.FRIEND_REQUEST_NOT_FOUND)); + User sender = request.getSender(); + + // 친구 수 제한 체크 (양쪽 모두) + if (friendRepository.countByUser(receiver) >= 10 + || friendRepository.countByUser(sender) >= 10) { + throw new CustomException(FriendErrorCode.FRIEND_LIMIT_EXCEEDED); + } + request.accept(); // 양방향 친구 관계 생성 @@ -189,12 +194,12 @@ public List getOutgoingRequests(Long userId) { /** 친구 리스트 **/ @Transactional(readOnly = true) - public List getFriends(Long userId) { + public FriendListResDto getFriends(Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); - return friendRepository.findByUser(user) + List friends = friendRepository.findByUser(user) .stream() .map(friend -> FriendResDto.builder() .friendId(friend.getFriend().getId()) @@ -202,6 +207,11 @@ public List getFriends(Long userId) { .build() ) .toList(); + + return FriendListResDto.builder() + .count(friends.size()) + .friends(friends) + .build(); } /** 친구 검색 **/ From 58303f103e965e9e9952e5a0786d40974d552801 Mon Sep 17 00:00:00 2001 From: heeone1 Date: Wed, 21 Jan 2026 17:41:56 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=A8=20Feat:=20=EB=82=98=EC=97=90?= =?UTF-8?q?=EA=B2=8C=20=EC=98=A8=20=EC=B9=9C=EA=B5=AC=20=EC=8B=A0=EC=B2=AD?= =?UTF-8?q?=20=EC=88=98=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/controller/FriendController.java | 2 +- .../dto/FriendRequestListWithCountResDto.java | 12 ++++++ .../repository/FriendRequestRepository.java | 5 +++ .../domain/friend/service/FriendService.java | 40 +++++++++++++++++-- 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListWithCountResDto.java diff --git a/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java b/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java index 5ad85b8..8230d8b 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java +++ b/src/main/java/com/example/egobook_be/domain/friend/controller/FriendController.java @@ -127,7 +127,7 @@ public ResponseEntity> deleteFriend( """ ) @GetMapping("/requests/incoming") - public ResponseEntity>> getIncomingRequests( + public ResponseEntity> getIncomingRequests( @AuthenticationPrincipal(expression = "userAuthDto.userId") Long userId ) { return ResponseEntity.ok( diff --git a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListWithCountResDto.java b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListWithCountResDto.java new file mode 100644 index 0000000..6c5c215 --- /dev/null +++ b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListWithCountResDto.java @@ -0,0 +1,12 @@ +package com.example.egobook_be.domain.friend.dto; + +import lombok.Builder; + +import java.util.List; + +@Builder +public record FriendRequestListWithCountResDto( + int totalCount, + List requests +) { +} diff --git a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java index f0dfeaa..b5565e0 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java +++ b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java @@ -25,4 +25,9 @@ boolean existsBySenderAndReceiverAndStatus( List findByReceiverAndStatus(User receiver, FriendRequestStatus status); List findBySenderAndStatus(User sender, FriendRequestStatus status); + + long countByReceiverAndStatus( + User receiver, + FriendRequestStatus status + ); } diff --git a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java index 966c6ee..afc68f0 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java +++ b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java @@ -153,15 +153,42 @@ public void deleteFriend(Long userId, Long friendId) { /** 내가 받은 친구 신청 목록 (승인 대기) **/ +// @Transactional(readOnly = true) +// public List getIncomingRequests(Long userId) { +// +// User receiver = userRepository.findById(userId) +// .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); +// +// return friendRequestRepository +// .findByReceiverAndStatus(receiver, FriendRequestStatus.PENDING) +// .stream() +// .map(req -> FriendRequestListResDto.builder() +// .requestId(req.getId()) +// .userId(req.getSender().getId()) +// .nickname(req.getSender().getNickname()) +// .requestedAt(req.getCreatedAt()) +// .build() +// ) +// .toList(); +// } @Transactional(readOnly = true) - public List getIncomingRequests(Long userId) { + public FriendRequestListWithCountResDto getIncomingRequests(Long userId) { User receiver = userRepository.findById(userId) .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); - return friendRequestRepository - .findByReceiverAndStatus(receiver, FriendRequestStatus.PENDING) - .stream() + List requests = + friendRequestRepository.findByReceiverAndStatus( + receiver, + FriendRequestStatus.PENDING + ); + + int totalCount = (int) friendRequestRepository.countByReceiverAndStatus( + receiver, + FriendRequestStatus.PENDING + ); + + List list = requests.stream() .map(req -> FriendRequestListResDto.builder() .requestId(req.getId()) .userId(req.getSender().getId()) @@ -170,6 +197,11 @@ public List getIncomingRequests(Long userId) { .build() ) .toList(); + + return FriendRequestListWithCountResDto.builder() + .totalCount(totalCount) + .requests(list) + .build(); } /** 내가 보낸 친구 신청 목록 **/ From 45bd117991d403b80498b106a722ff96067f0d67 Mon Sep 17 00:00:00 2001 From: heeone1 Date: Wed, 21 Jan 2026 17:52:41 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C=20=EB=A0=88=EB=B2=A8=EB=8F=84=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../egobook_be/domain/friend/dto/FriendResDto.java | 3 ++- .../domain/friend/service/FriendService.java | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendResDto.java b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendResDto.java index 7cbff6b..aca0096 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendResDto.java +++ b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendResDto.java @@ -5,6 +5,7 @@ @Builder public record FriendResDto( Long friendId, - String nickname + String nickname, + Integer level ) { } diff --git a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java index afc68f0..aa245b4 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java +++ b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java @@ -233,11 +233,15 @@ public FriendListResDto getFriends(Long userId) { List friends = friendRepository.findByUser(user) .stream() - .map(friend -> FriendResDto.builder() - .friendId(friend.getFriend().getId()) - .nickname(friend.getFriend().getNickname()) - .build() - ) + .map(friend -> { + var friendUser = friend.getFriend(); + + return FriendResDto.builder() + .friendId(friendUser.getId()) + .nickname(friendUser.getNickname()) + .level(friendUser.getLevel()) + .build(); + }) .toList(); return FriendListResDto.builder() From d16b3b9b8585378a22fdc1df6dc529f4c2b5b1df Mon Sep 17 00:00:00 2001 From: heeone1 Date: Wed, 21 Jan 2026 18:57:22 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20=EC=B9=9C?= =?UTF-8?q?=EA=B5=AC=20=EC=8B=A0=EC=B2=AD=20=EB=B0=9B=EC=9D=80=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D,=20=EB=B3=B4=EB=82=B8=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=ED=95=A0=20=EB=95=8C=20=EB=A0=88=EB=B2=A8?= =?UTF-8?q?=EB=8F=84=20=EC=A1=B0=ED=9A=8C=EB=90=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/dto/FriendRequestListResDto.java | 1 + .../domain/friend/service/FriendService.java | 54 ++++++++----------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListResDto.java b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListResDto.java index 93a02a8..609f91f 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListResDto.java +++ b/src/main/java/com/example/egobook_be/domain/friend/dto/FriendRequestListResDto.java @@ -9,6 +9,7 @@ public record FriendRequestListResDto( Long requestId, Long userId, String nickname, + Integer level, LocalDateTime requestedAt ) { } diff --git a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java index aa245b4..8978e69 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java +++ b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java @@ -153,24 +153,6 @@ public void deleteFriend(Long userId, Long friendId) { /** 내가 받은 친구 신청 목록 (승인 대기) **/ -// @Transactional(readOnly = true) -// public List getIncomingRequests(Long userId) { -// -// User receiver = userRepository.findById(userId) -// .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); -// -// return friendRequestRepository -// .findByReceiverAndStatus(receiver, FriendRequestStatus.PENDING) -// .stream() -// .map(req -> FriendRequestListResDto.builder() -// .requestId(req.getId()) -// .userId(req.getSender().getId()) -// .nickname(req.getSender().getNickname()) -// .requestedAt(req.getCreatedAt()) -// .build() -// ) -// .toList(); -// } @Transactional(readOnly = true) public FriendRequestListWithCountResDto getIncomingRequests(Long userId) { @@ -189,13 +171,17 @@ public FriendRequestListWithCountResDto getIncomingRequests(Long userId) { ); List list = requests.stream() - .map(req -> FriendRequestListResDto.builder() - .requestId(req.getId()) - .userId(req.getSender().getId()) - .nickname(req.getSender().getNickname()) - .requestedAt(req.getCreatedAt()) - .build() - ) + .map(req -> { + User sender = req.getSender(); + + return FriendRequestListResDto.builder() + .requestId(req.getId()) + .userId(sender.getId()) + .nickname(sender.getNickname()) + .level(sender.getLevel()) + .requestedAt(req.getCreatedAt()) + .build(); + }) .toList(); return FriendRequestListWithCountResDto.builder() @@ -214,13 +200,17 @@ public List getOutgoingRequests(Long userId) { return friendRequestRepository .findBySenderAndStatus(sender, FriendRequestStatus.PENDING) .stream() - .map(req -> FriendRequestListResDto.builder() - .requestId(req.getId()) - .userId(req.getReceiver().getId()) - .nickname(req.getReceiver().getNickname()) - .requestedAt(req.getCreatedAt()) - .build() - ) + .map(req -> { + User receiver = req.getReceiver(); + + return FriendRequestListResDto.builder() + .requestId(req.getId()) + .userId(receiver.getId()) + .nickname(receiver.getNickname()) + .level(receiver.getLevel()) + .requestedAt(req.getCreatedAt()) + .build(); + }) .toList(); } From b5c18bcbd2bec32a40d95c1399becb1aa37d3d0a Mon Sep 17 00:00:00 2001 From: heeone1 Date: Mon, 26 Jan 2026 01:22:31 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20N+1=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/repository/FriendRepository.java | 10 ++++++++++ .../friend/repository/FriendRequestRepository.java | 14 ++++++++++++++ .../domain/friend/service/FriendService.java | 6 +++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java index ff4b9a1..43d540e 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java +++ b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRepository.java @@ -25,4 +25,14 @@ public interface FriendRepository extends JpaRepository { where f.user = :user """) List findFriendIdsByUser(@Param("user") User user); + + @Query(""" + select f + from Friend f + join fetch f.friend u + where f.user = :user + """) + List findByUserWithFriend( + @Param("user") User user + ); } diff --git a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java index b5565e0..3f68f18 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java +++ b/src/main/java/com/example/egobook_be/domain/friend/repository/FriendRequestRepository.java @@ -4,6 +4,8 @@ import com.example.egobook_be.domain.friend.enums.FriendRequestStatus; import com.example.egobook_be.domain.user.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import java.util.List; import java.util.Optional; @@ -30,4 +32,16 @@ long countByReceiverAndStatus( User receiver, FriendRequestStatus status ); + + @Query(""" + select fr + from FriendRequest fr + join fetch fr.receiver r + where fr.sender = :sender + and fr.status = :status + """) + List findBySenderAndStatusWithReceiver( + @Param("sender") User sender, + @Param("status") FriendRequestStatus status + ); } diff --git a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java index 8978e69..b49a886 100644 --- a/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java +++ b/src/main/java/com/example/egobook_be/domain/friend/service/FriendService.java @@ -198,7 +198,7 @@ public List getOutgoingRequests(Long userId) { .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); return friendRequestRepository - .findBySenderAndStatus(sender, FriendRequestStatus.PENDING) + .findBySenderAndStatusWithReceiver(sender, FriendRequestStatus.PENDING) .stream() .map(req -> { User receiver = req.getReceiver(); @@ -221,10 +221,10 @@ public FriendListResDto getFriends(Long userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(FriendErrorCode.USER_NOT_FOUND)); - List friends = friendRepository.findByUser(user) + List friends = friendRepository.findByUserWithFriend(user) .stream() .map(friend -> { - var friendUser = friend.getFriend(); + User friendUser = friend.getFriend(); return FriendResDto.builder() .friendId(friendUser.getId())