From 52673233bff08fa3f5493415d65c8a9272be5fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Sun, 24 Aug 2025 22:54:13 +0900 Subject: [PATCH 01/14] =?UTF-8?q?Feat:=20=EC=9C=A0=EC=A0=80=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/flipnote/user/repository/UserProfileRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/project/flipnote/user/repository/UserProfileRepository.java b/src/main/java/project/flipnote/user/repository/UserProfileRepository.java index 3fa1f30a..f26e0c9a 100644 --- a/src/main/java/project/flipnote/user/repository/UserProfileRepository.java +++ b/src/main/java/project/flipnote/user/repository/UserProfileRepository.java @@ -25,4 +25,6 @@ public interface UserProfileRepository extends JpaRepository @Query("SELECT up.nickname FROM UserProfile up WHERE up.id = :userId") Optional findNicknameById(@Param("userId") Long userId); + + boolean existsByIdAndStatus(Long aLong, UserStatus userStatus); } From a07151d0722efe1c38106f75740584debc9f30bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Sun, 24 Aug 2025 22:54:25 +0900 Subject: [PATCH 02/14] =?UTF-8?q?Feat:=20=EA=B7=B8=EB=A3=B9=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EC=A1=B0=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/controller/GroupController.java | 14 ++++++ .../group/exception/GroupErrorCode.java | 3 +- .../flipnote/group/service/GroupService.java | 46 ++++++++++++++++--- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main/java/project/flipnote/group/controller/GroupController.java b/src/main/java/project/flipnote/group/controller/GroupController.java index f9204460..63edc1e2 100644 --- a/src/main/java/project/flipnote/group/controller/GroupController.java +++ b/src/main/java/project/flipnote/group/controller/GroupController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import jakarta.validation.Valid; @@ -18,6 +19,7 @@ import project.flipnote.common.security.dto.AuthPrinciple; import project.flipnote.group.model.FindGroupMemberResponse; import project.flipnote.group.model.FindGroupMemberResponse; +import project.flipnote.group.model.FindGroupResponse; import project.flipnote.group.model.GroupCreateRequest; import project.flipnote.group.model.GroupCreateResponse; import project.flipnote.group.model.GroupDetailResponse; @@ -80,4 +82,16 @@ public ResponseEntity findGroupMembers( return ResponseEntity.ok(res); } + + //그룹 전체 조회 + @GetMapping + public ResponseEntity findGroup( + @AuthenticationPrincipal AuthPrinciple authPrinciple, + @RequestParam(name = "lastId", required = false) Long lastId, + @RequestParam(name = "category", required = false) String category + ) { + FindGroupResponse res = groupService.findGroup(authPrinciple, lastId, category); + + return ResponseEntity.ok(res); + } } diff --git a/src/main/java/project/flipnote/group/exception/GroupErrorCode.java b/src/main/java/project/flipnote/group/exception/GroupErrorCode.java index ff58248f..de2e296b 100644 --- a/src/main/java/project/flipnote/group/exception/GroupErrorCode.java +++ b/src/main/java/project/flipnote/group/exception/GroupErrorCode.java @@ -16,7 +16,8 @@ public enum GroupErrorCode implements ErrorCode { OTHER_USER_EXIST_IN_GROUP(HttpStatus.CONFLICT, "GROUP_005", "그룹내 오너 제외 유저가 존재합니다."), GROUP_IS_ALREADY_MAX_MEMBER(HttpStatus.CONFLICT, "GROUP_006", "그룹 정원이 가득 찼습니다."), ALREADY_GROUP_MEMBER(HttpStatus.CONFLICT, "GROUP_007", "이미 그룹 회원입니다."), - INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "그룹 내에 인원수보다 많게 수정해야합니다."); + INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "그룹 내에 인원수보다 많게 수정해야합니다."), + INVALID_CATEGORY(HttpStatus.BAD_REQUEST, "GROUP_009", "지원하지 않는 카테고리입니다." ); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index d964890e..e0455b0c 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -6,11 +6,11 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import project.flipnote.common.exception.BizException; import project.flipnote.common.security.dto.AuthPrinciple; +import project.flipnote.group.entity.Category; import project.flipnote.group.entity.Group; import project.flipnote.group.entity.GroupMember; import project.flipnote.group.entity.GroupMemberRole; @@ -19,6 +19,7 @@ import project.flipnote.group.entity.GroupRolePermission; import project.flipnote.group.exception.GroupErrorCode; import project.flipnote.group.model.FindGroupMemberResponse; +import project.flipnote.group.model.FindGroupResponse; import project.flipnote.group.model.GroupCreateRequest; import project.flipnote.group.model.GroupCreateResponse; import project.flipnote.group.model.GroupDetailResponse; @@ -51,12 +52,21 @@ public class GroupService { /* 유저 정보 조회 */ - public UserProfile validateUser(AuthPrinciple authPrinciple) { + public UserProfile getUser(AuthPrinciple authPrinciple) { return userProfileRepository.findByIdAndStatus(authPrinciple.userId(), UserStatus.ACTIVE).orElseThrow( () -> new BizException(UserErrorCode.USER_NOT_FOUND) ); } + /* + 유저 정보 조회 + */ + public void validateUser(AuthPrinciple authPrinciple) { + if(!userProfileRepository.existsByIdAndStatus(authPrinciple.userId(), UserStatus.ACTIVE)) { + throw new BizException(UserErrorCode.USER_NOT_FOUND); + } + } + /* 그룹 내 유저 검증 */ @@ -100,7 +110,7 @@ public Group getGroup(Long groupId) { public GroupCreateResponse create(AuthPrinciple authPrinciple, GroupCreateRequest req) { //1. 유저 조회 - UserProfile user = validateUser(authPrinciple); + UserProfile user = getUser(authPrinciple); //2. 인원수 검증 validateMaxMember(req.maxMember()); @@ -200,7 +210,7 @@ private void validateUserCount(Group group, int maxMember) { public GroupPutResponse changeGroup(AuthPrinciple authPrinciple, GroupPutRequest req, Long groupId) { //1. 유저 조회 - UserProfile user = validateUser(authPrinciple); + UserProfile user = getUser(authPrinciple); //2. 인원수 검증 validateMaxMember(req.maxMember()); @@ -249,7 +259,7 @@ public GroupDetailResponse findGroupDetail(AuthPrinciple authPrinciple, Long gro Group group = getGroup(groupId); //2. 유저 조회 - UserProfile user = validateUser(authPrinciple); + UserProfile user = getUser(authPrinciple); //3. 그룹 내 유저 조회 validateGroupInUser(user, groupId); @@ -264,7 +274,7 @@ public void deleteGroup(AuthPrinciple authPrinciple, Long groupId) { Group group = getGroup(groupId); //2. 유저 조회 - UserProfile user = validateUser(authPrinciple); + UserProfile user = getUser(authPrinciple); //3. 그룹 내 유저 조회 GroupMember groupMember = getGroupMember(user, groupId); @@ -295,7 +305,7 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon validateGroup(groupId); //2. 유저 조회 - UserProfile user = validateUser(authPrinciple); + UserProfile user = getUser(authPrinciple); //3. 그룹 내 유저 조회 validateGroupInUser(user, groupId); @@ -305,4 +315,26 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon return FindGroupMemberResponse.from(groupMembers); } + + public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, String rawCategory) { + //1. 유저 조회 + validateUser(authPrinciple); + + //2. 카테고리 변환 + Category category = convertCategory(rawCategory); + + return null; + } + + private Category convertCategory(String rawCategory) { + Category category = null; + if (rawCategory != null && !rawCategory.isBlank()) { + try { + category = Category.valueOf(rawCategory.trim().toUpperCase()); + } catch (IllegalArgumentException e) { + throw new BizException(GroupErrorCode.INVALID_CATEGORY); + } + } + return category; + } } From f0668e1e38066112c973710ab94be4cdd77bb50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Sun, 24 Aug 2025 23:21:04 +0900 Subject: [PATCH 03/14] =?UTF-8?q?Chore:=20override=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flipnote/group/repository/GroupMemberRepositoryImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java b/src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java index d45348c8..f042fdd2 100644 --- a/src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java +++ b/src/main/java/project/flipnote/group/repository/GroupMemberRepositoryImpl.java @@ -3,7 +3,6 @@ import java.util.List; import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -19,6 +18,7 @@ public class GroupMemberRepositoryImpl implements GroupMemberRepositoryCustom { QUserProfile userProfile = QUserProfile.userProfile; QGroupMember groupMember = QGroupMember.groupMember; + @Override public List findGroupMembers(Long groupId) { return queryFactory.select(Projections.constructor( GroupMemberInfo.class, @@ -32,5 +32,4 @@ public List findGroupMembers(Long groupId) { .where(groupMember.group.id.eq(groupId)) .fetch(); } - } From 9639bb734ba0a5934b814b6163c60c01ecb04b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Sun, 24 Aug 2025 23:21:37 +0900 Subject: [PATCH 04/14] =?UTF-8?q?Feat:=20=EC=BB=A4=EC=84=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EA=B7=B8=EB=A3=B9=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/model/FindGroupResponse.java | 12 +++++ .../flipnote/group/model/GroupInfo.java | 11 ++++ .../group/repository/GroupRepository.java | 2 +- .../repository/GroupRepositoryCustom.java | 10 ++++ .../group/repository/GroupRepositoryImpl.java | 51 +++++++++++++++++++ .../flipnote/group/service/GroupService.java | 7 ++- 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/main/java/project/flipnote/group/model/FindGroupResponse.java create mode 100644 src/main/java/project/flipnote/group/model/GroupInfo.java create mode 100644 src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java create mode 100644 src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java diff --git a/src/main/java/project/flipnote/group/model/FindGroupResponse.java b/src/main/java/project/flipnote/group/model/FindGroupResponse.java new file mode 100644 index 00000000..1ef215f0 --- /dev/null +++ b/src/main/java/project/flipnote/group/model/FindGroupResponse.java @@ -0,0 +1,12 @@ +package project.flipnote.group.model; + +import java.util.List; + +public record FindGroupResponse( + List groups, + Long next +) { + public static FindGroupResponse from(List groups, Long next) { + return new FindGroupResponse(groups, next); + } +} diff --git a/src/main/java/project/flipnote/group/model/GroupInfo.java b/src/main/java/project/flipnote/group/model/GroupInfo.java new file mode 100644 index 00000000..d4f4ad7d --- /dev/null +++ b/src/main/java/project/flipnote/group/model/GroupInfo.java @@ -0,0 +1,11 @@ +package project.flipnote.group.model; + +public record GroupInfo( + Long groupId, + String name, + String description +) { + public static GroupInfo from(Long groupId, String name, String description) { + return new GroupInfo(groupId, name, description); + } +} diff --git a/src/main/java/project/flipnote/group/repository/GroupRepository.java b/src/main/java/project/flipnote/group/repository/GroupRepository.java index 2ee8c2f4..a974d52d 100644 --- a/src/main/java/project/flipnote/group/repository/GroupRepository.java +++ b/src/main/java/project/flipnote/group/repository/GroupRepository.java @@ -12,7 +12,7 @@ import project.flipnote.group.entity.Group; @Repository -public interface GroupRepository extends JpaRepository { +public interface GroupRepository extends JpaRepository, GroupRepositoryCustom { Optional findByIdAndDeletedAtIsNull(Long groupId); diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java new file mode 100644 index 00000000..270f30ad --- /dev/null +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java @@ -0,0 +1,10 @@ +package project.flipnote.group.repository; + +import java.util.List; + +import project.flipnote.group.entity.Category; +import project.flipnote.group.model.GroupInfo; + +public interface GroupRepositoryCustom { + List findAllByCursor(Long lastId, Category category); +} diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java new file mode 100644 index 00000000..051cb5a2 --- /dev/null +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java @@ -0,0 +1,51 @@ +package project.flipnote.group.repository; + +import java.util.List; + + +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import lombok.RequiredArgsConstructor; +import project.flipnote.group.entity.Category; +import project.flipnote.group.entity.QGroup; +import project.flipnote.group.model.GroupInfo; + +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepositoryCustom { + + private static final int SIZE = 10; + + private final JPAQueryFactory queryFactory; + + QGroup group = QGroup.group; + + + @Override + public List findAllByCursor(Long lastId, Category category) { + BooleanBuilder where = new BooleanBuilder() + .and(group.deletedAt.isNull()); + + if (lastId != null) { + where.and(group.id.lt(lastId)); + } + + if (category != null) { + where.and(group.category.eq(category)); + } + + return queryFactory.select(Projections.constructor( + GroupInfo.class, + group.id, + group.name, + group.description + )) + .from(group) + .where(where) + .orderBy(group.id.desc()) + .limit(SIZE+1) + .fetch(); + } + +} diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index e0455b0c..01b15e4e 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -23,6 +23,7 @@ import project.flipnote.group.model.GroupCreateRequest; import project.flipnote.group.model.GroupCreateResponse; import project.flipnote.group.model.GroupDetailResponse; +import project.flipnote.group.model.GroupInfo; import project.flipnote.group.model.GroupMemberInfo; import project.flipnote.group.model.GroupPutRequest; import project.flipnote.group.model.GroupPutResponse; @@ -323,7 +324,11 @@ public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, Str //2. 카테고리 변환 Category category = convertCategory(rawCategory); - return null; + List groups = groupRepository.findAllByCursor(lastId, category); + + Long nextCursor = groups.isEmpty() ? null : groups.get(groups.size() - 1).groupId(); + + return FindGroupResponse.from(groups, nextCursor); } private Category convertCategory(String rawCategory) { From f2e237c0ae35bb01d9ce13474dd563fb5df42698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:15:24 +0900 Subject: [PATCH 05/14] =?UTF-8?q?Fix:=20=EA=B7=B8=EB=A3=B9=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/flipnote/group/service/GroupService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index 01b15e4e..6eb82997 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -235,8 +235,8 @@ public GroupPutResponse changeGroup(AuthPrinciple authPrinciple, GroupPutRequest /* 그룹 내 오너를 제외한 인원이 존재하는 경우 체크 */ - private boolean checkUserNotExistInGroup(UserProfile user, Long groupId) { - long count = groupMemberRepository.countByGroup_idAndUser_idNot(groupId, user.getId()); + private boolean checkUserNotExistInGroup(UserProfile user, Group group) { + long count = groupMemberRepository.countByGroup_idAndUser_idNot(group.getId(), user.getId()); if (count > 0) { return false; } @@ -286,10 +286,12 @@ public void deleteGroup(AuthPrinciple authPrinciple, Long groupId) { } //5. 오너를 제외한 모든 유저가 없어야 삭제 가능 - if (!checkUserNotExistInGroup(user, groupId)) { + if (!checkUserNotExistInGroup(user, group)) { throw new BizException(GroupErrorCode.OTHER_USER_EXIST_IN_GROUP); } + groupMemberRepository.delete(groupMember); + groupRepository.delete(group); } @@ -318,7 +320,7 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon } public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, String rawCategory) { - //1. 유저 조회 + //1. 유저 검증 validateUser(authPrinciple); //2. 카테고리 변환 From 942acd4efde64c67cf4a682264f27924a92b0cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:31:22 +0900 Subject: [PATCH 06/14] =?UTF-8?q?Refactor:=20=EA=B7=B8=EB=A3=B9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EC=8B=9C=20hasNext=20=EC=B6=94=EA=B0=80,=20c?= =?UTF-8?q?ategory=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flipnote/group/entity/GroupRolePermission.java | 4 ++-- .../project/flipnote/group/model/FindGroupResponse.java | 7 ++++--- .../java/project/flipnote/group/model/GroupInfo.java | 9 ++++++--- .../flipnote/group/repository/GroupRepositoryImpl.java | 5 +++-- .../project/flipnote/group/service/GroupService.java | 8 ++++++-- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/project/flipnote/group/entity/GroupRolePermission.java b/src/main/java/project/flipnote/group/entity/GroupRolePermission.java index 4baaba9b..01618968 100644 --- a/src/main/java/project/flipnote/group/entity/GroupRolePermission.java +++ b/src/main/java/project/flipnote/group/entity/GroupRolePermission.java @@ -20,11 +20,11 @@ public class GroupRolePermission { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "group_id", nullable = false) private Group group; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "group_permission_id", nullable = false) private GroupPermission groupPermission; diff --git a/src/main/java/project/flipnote/group/model/FindGroupResponse.java b/src/main/java/project/flipnote/group/model/FindGroupResponse.java index 1ef215f0..df6c0387 100644 --- a/src/main/java/project/flipnote/group/model/FindGroupResponse.java +++ b/src/main/java/project/flipnote/group/model/FindGroupResponse.java @@ -4,9 +4,10 @@ public record FindGroupResponse( List groups, - Long next + Long next, + Boolean hasNext ) { - public static FindGroupResponse from(List groups, Long next) { - return new FindGroupResponse(groups, next); + public static FindGroupResponse from(List groups, Long next, Boolean hasNext) { + return new FindGroupResponse(groups, next, hasNext); } } diff --git a/src/main/java/project/flipnote/group/model/GroupInfo.java b/src/main/java/project/flipnote/group/model/GroupInfo.java index d4f4ad7d..9ca194e2 100644 --- a/src/main/java/project/flipnote/group/model/GroupInfo.java +++ b/src/main/java/project/flipnote/group/model/GroupInfo.java @@ -1,11 +1,14 @@ package project.flipnote.group.model; +import project.flipnote.group.entity.Category; + public record GroupInfo( Long groupId, String name, - String description + String description, + Category category ) { - public static GroupInfo from(Long groupId, String name, String description) { - return new GroupInfo(groupId, name, description); + public static GroupInfo from(Long groupId, String name, String description, Category category) { + return new GroupInfo(groupId, name, description, category); } } diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java index 051cb5a2..c313557a 100644 --- a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java @@ -39,12 +39,13 @@ public List findAllByCursor(Long lastId, Category category) { GroupInfo.class, group.id, group.name, - group.description + group.description, + group.category )) .from(group) .where(where) .orderBy(group.id.desc()) - .limit(SIZE+1) + .limit(SIZE) .fetch(); } diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index 6eb82997..8dfb0bcc 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -43,6 +43,8 @@ @Transactional(readOnly = true) public class GroupService { + final int SIZE = 10; + private final GroupRepository groupRepository; private final GroupMemberRepository groupMemberRepository; private final GroupPermissionRepository groupPermissionRepository; @@ -328,9 +330,11 @@ public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, Str List groups = groupRepository.findAllByCursor(lastId, category); - Long nextCursor = groups.isEmpty() ? null : groups.get(groups.size() - 1).groupId(); + boolean hasNext = groups.size() == SIZE; + + Long nextCursor = hasNext ? groups.get(groups.size() - 1).groupId() : null; - return FindGroupResponse.from(groups, nextCursor); + return FindGroupResponse.from(groups, nextCursor, hasNext); } private Category convertCategory(String rawCategory) { From 8dfdcb17249c9b33fd890c327104d78dc09838c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:31:48 +0900 Subject: [PATCH 07/14] =?UTF-8?q?Refactor:=20=EC=9C=84=EC=B9=98=20common?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flipnote/{infra => common}/config/QuerydslConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/project/flipnote/{infra => common}/config/QuerydslConfig.java (92%) diff --git a/src/main/java/project/flipnote/infra/config/QuerydslConfig.java b/src/main/java/project/flipnote/common/config/QuerydslConfig.java similarity index 92% rename from src/main/java/project/flipnote/infra/config/QuerydslConfig.java rename to src/main/java/project/flipnote/common/config/QuerydslConfig.java index 075576d0..8b971d1f 100644 --- a/src/main/java/project/flipnote/infra/config/QuerydslConfig.java +++ b/src/main/java/project/flipnote/common/config/QuerydslConfig.java @@ -1,4 +1,4 @@ -package project.flipnote.infra.config; +package project.flipnote.common.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; From 8396deeef417acaf70b4fa734dc3e051c909b227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:32:10 +0900 Subject: [PATCH 08/14] =?UTF-8?q?Chore:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/flipnote/user/repository/UserProfileRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/project/flipnote/user/repository/UserProfileRepository.java b/src/main/java/project/flipnote/user/repository/UserProfileRepository.java index f26e0c9a..d88930e0 100644 --- a/src/main/java/project/flipnote/user/repository/UserProfileRepository.java +++ b/src/main/java/project/flipnote/user/repository/UserProfileRepository.java @@ -26,5 +26,5 @@ public interface UserProfileRepository extends JpaRepository @Query("SELECT up.nickname FROM UserProfile up WHERE up.id = :userId") Optional findNicknameById(@Param("userId") Long userId); - boolean existsByIdAndStatus(Long aLong, UserStatus userStatus); + boolean existsByIdAndStatus(Long userId, UserStatus userStatus); } From 2c40d1560b538cd8d0c491f7c823e968a0c5559d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:35:14 +0900 Subject: [PATCH 09/14] =?UTF-8?q?Feat:=20=EA=B7=B8=EB=A3=B9=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20url=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/project/flipnote/group/model/GroupInfo.java | 8 ++++---- .../flipnote/group/repository/GroupRepositoryImpl.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/project/flipnote/group/model/GroupInfo.java b/src/main/java/project/flipnote/group/model/GroupInfo.java index 9ca194e2..cee7a8ad 100644 --- a/src/main/java/project/flipnote/group/model/GroupInfo.java +++ b/src/main/java/project/flipnote/group/model/GroupInfo.java @@ -6,9 +6,9 @@ public record GroupInfo( Long groupId, String name, String description, - Category category -) { - public static GroupInfo from(Long groupId, String name, String description, Category category) { - return new GroupInfo(groupId, name, description, category); + Category category, + String imageUrl) { + public static GroupInfo from(Long groupId, String name, String description, Category category, String imageUrl) { + return new GroupInfo(groupId, name, description, category, imageUrl); } } diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java index c313557a..34bd32a6 100644 --- a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java @@ -40,7 +40,8 @@ public List findAllByCursor(Long lastId, Category category) { group.id, group.name, group.description, - group.category + group.category, + group.imageUrl )) .from(group) .where(where) From efb923d87650b0daf1390410c0c244857d02e2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 18:57:57 +0900 Subject: [PATCH 10/14] =?UTF-8?q?Chore:=20=EC=97=90=EB=9F=AC=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=A0=95=ED=99=95=ED=95=98=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/project/flipnote/group/exception/GroupErrorCode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/project/flipnote/group/exception/GroupErrorCode.java b/src/main/java/project/flipnote/group/exception/GroupErrorCode.java index de2e296b..4d581836 100644 --- a/src/main/java/project/flipnote/group/exception/GroupErrorCode.java +++ b/src/main/java/project/flipnote/group/exception/GroupErrorCode.java @@ -16,7 +16,7 @@ public enum GroupErrorCode implements ErrorCode { OTHER_USER_EXIST_IN_GROUP(HttpStatus.CONFLICT, "GROUP_005", "그룹내 오너 제외 유저가 존재합니다."), GROUP_IS_ALREADY_MAX_MEMBER(HttpStatus.CONFLICT, "GROUP_006", "그룹 정원이 가득 찼습니다."), ALREADY_GROUP_MEMBER(HttpStatus.CONFLICT, "GROUP_007", "이미 그룹 회원입니다."), - INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "그룹 내에 인원수보다 많게 수정해야합니다."), + INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "현재 그룹 인원수보다 작게 설정할 수 없습니다."), INVALID_CATEGORY(HttpStatus.BAD_REQUEST, "GROUP_009", "지원하지 않는 카테고리입니다." ); private final HttpStatus httpStatus; From 4896e29588cd0b274389200bafd5e4e5b48eaa87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 19:00:29 +0900 Subject: [PATCH 11/14] =?UTF-8?q?Fix:=20size=EA=B0=80=20=EC=A0=95=ED=99=95?= =?UTF-8?q?=ED=9E=88=2010=EA=B0=9C=EC=9D=BC=20=EB=95=8C=20next=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EC=A3=BC=EB=8A=94=20=EA=B2=BD=EC=9A=B0=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 --- .../group/repository/GroupRepositoryCustom.java | 2 +- .../group/repository/GroupRepositoryImpl.java | 7 ++----- .../project/flipnote/group/service/GroupService.java | 12 +++++++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java index 270f30ad..d410eb3b 100644 --- a/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryCustom.java @@ -6,5 +6,5 @@ import project.flipnote.group.model.GroupInfo; public interface GroupRepositoryCustom { - List findAllByCursor(Long lastId, Category category); + List findAllByCursor(Long lastId, Category category, int pageSize); } diff --git a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java index 34bd32a6..0865cf17 100644 --- a/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java +++ b/src/main/java/project/flipnote/group/repository/GroupRepositoryImpl.java @@ -15,15 +15,12 @@ @RequiredArgsConstructor public class GroupRepositoryImpl implements GroupRepositoryCustom { - private static final int SIZE = 10; - private final JPAQueryFactory queryFactory; QGroup group = QGroup.group; - @Override - public List findAllByCursor(Long lastId, Category category) { + public List findAllByCursor(Long lastId, Category category, int pageSize) { BooleanBuilder where = new BooleanBuilder() .and(group.deletedAt.isNull()); @@ -46,7 +43,7 @@ public List findAllByCursor(Long lastId, Category category) { .from(group) .where(where) .orderBy(group.id.desc()) - .limit(SIZE) + .limit(pageSize+1) .fetch(); } diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index 8dfb0bcc..7318d70c 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -43,7 +43,7 @@ @Transactional(readOnly = true) public class GroupService { - final int SIZE = 10; + private static final int SIZE = 10; private final GroupRepository groupRepository; private final GroupMemberRepository groupMemberRepository; @@ -328,9 +328,15 @@ public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, Str //2. 카테고리 변환 Category category = convertCategory(rawCategory); - List groups = groupRepository.findAllByCursor(lastId, category); + int pageSize = SIZE; - boolean hasNext = groups.size() == SIZE; + List groups = groupRepository.findAllByCursor(lastId, category, pageSize); + + boolean hasNext = groups.size() > SIZE; + + if (hasNext) { + groups = groups.subList(0, SIZE); + } Long nextCursor = hasNext ? groups.get(groups.size() - 1).groupId() : null; From 6365dbdcd0f0d9e28dc9fa63a9536b3db8deaabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 20:44:35 +0900 Subject: [PATCH 12/14] =?UTF-8?q?Refactor:=20PagingRequest,=20Response=20?= =?UTF-8?q?=EC=83=81=EC=86=8D=20=EB=B0=9B=EC=95=84=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flipnote/group/controller/GroupController.java | 12 +++++++----- .../flipnote/group/model/FindGroupResponse.java | 13 ------------- .../flipnote/group/service/GroupService.java | 13 ++++++------- 3 files changed, 13 insertions(+), 25 deletions(-) delete mode 100644 src/main/java/project/flipnote/group/model/FindGroupResponse.java diff --git a/src/main/java/project/flipnote/group/controller/GroupController.java b/src/main/java/project/flipnote/group/controller/GroupController.java index ef5415bd..403b5b39 100644 --- a/src/main/java/project/flipnote/group/controller/GroupController.java +++ b/src/main/java/project/flipnote/group/controller/GroupController.java @@ -5,6 +5,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -15,12 +16,14 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import project.flipnote.common.model.response.CursorPagingResponse; import project.flipnote.common.security.dto.AuthPrinciple; import project.flipnote.group.model.FindGroupMemberResponse; -import project.flipnote.group.model.FindGroupResponse; import project.flipnote.group.model.GroupCreateRequest; import project.flipnote.group.model.GroupCreateResponse; import project.flipnote.group.model.GroupDetailResponse; +import project.flipnote.group.model.GroupInfo; +import project.flipnote.group.model.GroupListRequest; import project.flipnote.group.model.GroupPutRequest; import project.flipnote.group.model.GroupPutResponse; import project.flipnote.group.service.GroupService; @@ -83,12 +86,11 @@ public ResponseEntity findGroupMembers( //그룹 전체 조회 @GetMapping - public ResponseEntity findGroup( + public ResponseEntity> findGroup( @AuthenticationPrincipal AuthPrinciple authPrinciple, - @RequestParam(name = "lastId", required = false) Long lastId, - @RequestParam(name = "category", required = false) String category + @Valid @ModelAttribute GroupListRequest req ) { - FindGroupResponse res = groupService.findGroup(authPrinciple, lastId, category); + CursorPagingResponse res = groupService.findGroup(authPrinciple, req); return ResponseEntity.ok(res); } diff --git a/src/main/java/project/flipnote/group/model/FindGroupResponse.java b/src/main/java/project/flipnote/group/model/FindGroupResponse.java deleted file mode 100644 index df6c0387..00000000 --- a/src/main/java/project/flipnote/group/model/FindGroupResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package project.flipnote.group.model; - -import java.util.List; - -public record FindGroupResponse( - List groups, - Long next, - Boolean hasNext -) { - public static FindGroupResponse from(List groups, Long next, Boolean hasNext) { - return new FindGroupResponse(groups, next, hasNext); - } -} diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index 0893525d..3660c77c 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import project.flipnote.common.exception.BizException; +import project.flipnote.common.model.response.CursorPagingResponse; import project.flipnote.common.security.dto.AuthPrinciple; import project.flipnote.group.entity.Category; import project.flipnote.group.entity.Group; @@ -19,11 +20,11 @@ import project.flipnote.group.entity.GroupRolePermission; import project.flipnote.group.exception.GroupErrorCode; import project.flipnote.group.model.FindGroupMemberResponse; -import project.flipnote.group.model.FindGroupResponse; import project.flipnote.group.model.GroupCreateRequest; import project.flipnote.group.model.GroupCreateResponse; import project.flipnote.group.model.GroupDetailResponse; import project.flipnote.group.model.GroupInfo; +import project.flipnote.group.model.GroupListRequest; import project.flipnote.group.model.GroupMemberInfo; import project.flipnote.group.model.GroupPutRequest; import project.flipnote.group.model.GroupPutResponse; @@ -321,16 +322,14 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon return FindGroupMemberResponse.from(groupMembers); } - public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, String rawCategory) { + public CursorPagingResponse findGroup(AuthPrinciple authPrinciple, GroupListRequest req) { //1. 유저 검증 validateUser(authPrinciple); //2. 카테고리 변환 - Category category = convertCategory(rawCategory); + Category category = convertCategory(req.getCategory()); - int pageSize = SIZE; - - List groups = groupRepository.findAllByCursor(lastId, category, pageSize); + List groups = groupRepository.findAllByCursor(req.getCursorId(), category, req.getSize()); boolean hasNext = groups.size() > SIZE; @@ -340,7 +339,7 @@ public FindGroupResponse findGroup(AuthPrinciple authPrinciple, Long lastId, Str Long nextCursor = hasNext ? groups.get(groups.size() - 1).groupId() : null; - return FindGroupResponse.from(groups, nextCursor, hasNext); + return CursorPagingResponse.of(groups, hasNext, nextCursor); } private Category convertCategory(String rawCategory) { From d083c35812ea29abd8d25d30393a816445604a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 20:44:41 +0900 Subject: [PATCH 13/14] =?UTF-8?q?Refactor:=20PagingRequest,=20Response=20?= =?UTF-8?q?=EC=83=81=EC=86=8D=20=EB=B0=9B=EC=95=84=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/model/GroupListRequest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/project/flipnote/group/model/GroupListRequest.java diff --git a/src/main/java/project/flipnote/group/model/GroupListRequest.java b/src/main/java/project/flipnote/group/model/GroupListRequest.java new file mode 100644 index 00000000..f1b73056 --- /dev/null +++ b/src/main/java/project/flipnote/group/model/GroupListRequest.java @@ -0,0 +1,20 @@ +package project.flipnote.group.model; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; + +import lombok.Getter; +import lombok.Setter; +import project.flipnote.common.model.request.CursorPagingRequest; + +@Setter +@Getter +public class GroupListRequest extends CursorPagingRequest { + + private String category; + + @Override + public PageRequest getPageRequest() { + return PageRequest.of(0, getSize(), Sort.by(Sort.Direction.DESC, "id")); + } +} From 1fca7e94de6ca8025e69ff7f1c07f379f316d097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=84=9D=EB=B2=94?= Date: Tue, 26 Aug 2025 20:56:13 +0900 Subject: [PATCH 14/14] =?UTF-8?q?Fix:=20size=EA=B0=92=20=EC=83=81=EC=88=98?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=B3=80=EC=88=98=EA=B0=92=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flipnote/common/security/config/SecurityConfig.java | 2 +- .../java/project/flipnote/group/service/GroupService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/project/flipnote/common/security/config/SecurityConfig.java b/src/main/java/project/flipnote/common/security/config/SecurityConfig.java index c4c8e97e..0465a9fc 100644 --- a/src/main/java/project/flipnote/common/security/config/SecurityConfig.java +++ b/src/main/java/project/flipnote/common/security/config/SecurityConfig.java @@ -58,7 +58,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authorizeHttpRequests(auth -> auth .requestMatchers( HttpMethod.POST, - "/*/users", "/*/auth/token/refresh", "/*/auth/password-resets", "/*/auth/register", + "/*/users", "/*/auth/token/refresh", "/*/auth/password-resets", "/*/auth/register", "/*/auth/email-verification/**", "/*/images/upload" ).permitAll() .requestMatchers(HttpMethod.PATCH, "/*/auth/password-resets").permitAll() diff --git a/src/main/java/project/flipnote/group/service/GroupService.java b/src/main/java/project/flipnote/group/service/GroupService.java index 3660c77c..decc06be 100644 --- a/src/main/java/project/flipnote/group/service/GroupService.java +++ b/src/main/java/project/flipnote/group/service/GroupService.java @@ -331,10 +331,10 @@ public CursorPagingResponse findGroup(AuthPrinciple authPrinciple, Gr List groups = groupRepository.findAllByCursor(req.getCursorId(), category, req.getSize()); - boolean hasNext = groups.size() > SIZE; + boolean hasNext = groups.size() > req.getSize(); if (hasNext) { - groups = groups.subList(0, SIZE); + groups = groups.subList(0, req.getSize()); } Long nextCursor = hasNext ? groups.get(groups.size() - 1).groupId() : null;