-
Notifications
You must be signed in to change notification settings - Fork 0
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
[✨ feat] 그룹 정보 보기 API 구현 #58
Conversation
QueryDSL을 활용하기 위해 `querydsl-jpa` 및 관련 의존성을 추가하였습니다. - `querydsl-jpa:${queryDslVersion}:jakarta` 추가 - `querydsl-apt:${queryDslVersion}:jakarta` 추가 - `jakarta.annotation-api` 및 `jakarta.persistence-api` 추가
`GroupCreateResponse`의 패키지를 `org.noostak.group.dto.response`에서 `org.noostak.group.dto.response.create`로 이동하였습니다.
`GroupCreateInternalResponse`의 패키지를 `org.noostak.group.dto.response`에서 `org.noostak.group.dto.response.create`로 이동하였습니다.
`GroupInternalRetrieveResponse`의 패키지를 `org.noostak.group.dto.response`에서 `org.noostak.group.dto.response.retrieve`로 이동하였습니다.
`GroupRetrieveResponse`의 패키지를 `org.noostak.group.dto.response`에서 `org.noostak.group.dto.response.retrieve`로 이동하였습니다.
`GroupsRetrieveResponse`의 패키지를 `org.noostak.group.dto.response`에서 `org.noostak.group.dto.response.retrieve`로 이동하였습니다.
QueryDSL을 사용하기 위한 설정 클래스를 추가하였습니다. - `JPAQueryFactory`를 빈으로 등록하여 의존성 주입 가능하도록 구성 - `EntityManager`를 활용하여 `JPAQueryFactory` 인스턴스 생성
- `/api/v1/groups/{groupId}/members` 엔드포인트 추가 - `GroupService`를 활용하여 그룹 정보 조회 - `SuccessResponse<GroupInfoResponse>`를 반환하도록 구현
- `GroupCreateInternalResponse`의 패키지를 `org.noostak.group.dto.response.create`로 변경 - `GroupsRetrieveResponse`의 패키지를 `org.noostak.group.dto.response.retrieve`로 변경 - 관련 패키지 변경 사항을 `GroupService`, `GroupRetrieveService` 및 관련 클래스에 반영
- `GroupInfoService` 인터페이스 추가 - `getGroupInfo(Long memberId, Long groupId)` 메서드 정의 - 그룹 정보를 조회하는 기능을 제공하기 위한 서비스 인터페이스
- `GroupInfoService` 구현체 `GroupInfoServiceImpl` 추가 - 그룹 정보를 조회하고, 그룹장 및 그룹원 정보를 포함하는 `GroupInfoResponse` 반환 - 그룹 및 멤버 정보 조회 시 존재하지 않을 경우 예외 처리 (`GroupException` 활용) - `S3Service`를 이용하여 그룹 및 멤버 프로필 이미지 URL 조회
- `Groups` 및 `MemberGroups` 사용을 제거하고 `List<Group>`을 직접 활용하도록 변경 - `memberGroupRepository.findGroupsByMemberId(memberId)`를 통해 직접 `Group` 목록을 조회하도록 수정 - 그룹 목록 검증 로직을 `validateGroups(List<Group>)`로 단순화 - `GroupInternalRetrieveResponse`를 제거하고 `GroupRetrieveResponse`를 직접 사용하도록 변경 - DTO 패키지 변경 사항 반영 (`org.noostak.group.dto.response.retrieve`)
- `GroupInfoService`를 활용한 `getGroupInfo(Long memberId, Long groupId)` 메서드 추가 - DTO 패키지 변경 사항 반영 (`GroupCreateInternalResponse`, `GroupCreateResponse`, `GroupsRetrieveResponse`) - `groupInfoService`를 의존성으로 추가하여 그룹 정보 조회 기능 제공
- `MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "멤버를 찾을 수 없습니다.")` 추가 - 그룹 내 특정 멤버가 존재하지 않을 경우 예외 처리를 위해 추가
- `GROUP_INFO(HttpStatus.OK, "그룹 정보가 성공적으로 조회되었습니다.")` 추가 - 그룹 정보 조회 성공 시 사용할 응답 코드 추가
- `myInfo`(요청한 멤버의 정보)와 `groupInfo`(그룹 요약 정보) 포함 - 정적 팩토리 메서드 `of(GroupMemberInfoResponse, GroupSummaryResponse)` 추가
- `memberName`(멤버 이름)과 `memberProfileImageUrl`(멤버 프로필 이미지 URL) 포함 - 정적 팩토리 메서드 `of(String memberName, String memberProfileImageUrl)` 추가
- 그룹장 정보(`groupHostInfo`), 그룹명(`groupName`), 그룹 프로필 이미지 URL(`groupProfileImageUrl`) 포함 - 그룹 멤버 수(`groupMemberCount`), 초대 코드(`groupInvitationCode`), 그룹 멤버 목록(`groupMemberInfo`) 포함 - 정적 팩토리 메서드 `of(...)` 추가
- `MemberGroupRepositoryCustom` 인터페이스 확장 - 기존 JPA 메서드 `findByMemberId(Long memberId)` 유지
- 그룹 ID로 멤버 조회 메서드 `findMembersByGroupId(Long groupId)` 추가 - 그룹 ID로 그룹장 조회 메서드 `findGroupHostByGroupId(Long groupId)` 추가 - 멤버 ID로 그룹 목록 조회 메서드 `findGroupsByMemberId(Long memberId)` 추가
- `findMembersByGroupId(Long groupId)` : 그룹 ID로 멤버 목록 조회 - `findGroupHostByGroupId(Long groupId)` : 그룹 ID로 그룹장 조회 - `findGroupsByMemberId(Long memberId)` : 멤버 ID로 그룹 목록 조회 - `JPAQueryFactory`를 활용한 QueryDSL 기반 쿼리 구현
- `MemberGroupRepositoryCustom` 인터페이스 구현 추가 - `findMembersByGroupId(Long groupId)` : 그룹 ID로 멤버 조회 메서드 추가 - `findGroupHostByGroupId(Long groupId)` : 그룹 ID로 그룹장 조회 메서드 추가 - `findGroupsByMemberId(Long memberId)` : 멤버 ID로 그룹 목록 조회 메서드 추가 - 중복된 `saveAll` 메서드 제거 및 `save` 로직 개선
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생 많으셨어요. 요청하신 부분과 함께 궁금한 점 남기고 마치겠습니다.
네이밍은 적절하게 잘 변형된 것 같습니다. GroupInfo처럼, ~Info 접미사를 통해서 반환하고자 하는 도메인 정보의 최상단으로 명시하고, Summary는 바꾸신 것 처럼 중간 요소를 의미하는 것으로 규칙을 고정하면 될 것 같습니다.
QueryDSL은 쿼리 최적화에 뛰어난 것 같습니다. CRUD 기능 개발을 자주 하게 된다면 유지보수가 좋다는 장점도 부각될 것 같습니다
.filter(m -> m.getMemberId().equals(memberId)) | ||
.findFirst() | ||
.orElseThrow(() -> new GroupException(GroupErrorCode.MEMBER_NOT_FOUND)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
findMembersByGroupId
-> findMemberByGroupIdAndMemberId
처럼 WHERE 조건 절에 MemberId와 GroupId가 일치하는 확인하는 방법으로 해결할 수 없을까요?
조건부 연산을 DBMS에서 수행할 수 있으면, DBMS에서 넘어오는 데이터에 대한 Bandwidth의 부담을 줄일 수 있습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
피드백 감사합니다! 😊
현재 findMembersByGroupId(groupId)
를 호출한 후 Java 스트림을 이용해 memberId
를 필터링하고 있는데, QueryDSL으로 구현된 로직을 개선하면 해당 필터링을 DB에서 직접 수행할 수 있을 것 같습니다.
제안해주신 대로 findMemberByGroupIdAndMemberId(groupId, memberId)
와 같은 형태로 WHERE 조건을 적용하면, 불필요한 데이터를 애플리케이션으로 가져오지 않고 DBMS가 직접 필터링을 수행하여 네트워크 및 메모리 사용량을 줄일 수 있을 것 같습니다.
예를 들어, 현재 findMembersByGroupId(groupId)
는 다음과 같이 모든 멤버를 가져옵니다:
public List<Member> findMembersByGroupId(Long groupId) {
return queryFactory
.select(member)
.from(memberGroup)
.join(memberGroup.member, member)
.where(memberGroup.group.groupId.eq(groupId))
.fetch();
}
이후 Java 스트림을 사용하여 필터링하고 있는데, QueryDSL에서 직접 처리하는 방식으로 변경하면 더 효율적일 것입니다:
public Optional<Member> findMemberByGroupIdAndMemberId(Long groupId, Long memberId) {
return Optional.ofNullable(
queryFactory
.select(member)
.from(memberGroup)
.join(memberGroup.member, member)
.where(memberGroup.group.groupId.eq(groupId)
.and(member.memberId.eq(memberId)))
.fetchOne()
);
}
이렇게 하면 DB에서 직접 groupId
와 memberId
조건을 적용해 검색하므로 불필요한 데이터 전송을 방지할 수 있을 것 같아요!
따라서 findMemberInGroup
메서드를 다음과 같이 변경하는 것이 더 적절할 것 같습니다:
private Member findMemberInGroup(Long memberId, Long groupId) {
return memberGroupRepository.findMemberByGroupIdAndMemberId(groupId, memberId)
.orElseThrow(() -> new GroupException(GroupErrorCode.MEMBER_NOT_FOUND));
}
이렇게 하면 전체 데이터를 불러온 후 필터링하는 것이 아니라, DB에서 직접 원하는 데이터를 가져오기 때문에 성능상 더 유리겠어요!
이 부분은 이슈로 등록하고 개선하겠습니다!
좋은 피드백 감사합니다! 🙌 🚀
.join(memberGroup.member, member) | ||
.where(memberGroup.group.groupId.eq(groupId)) | ||
.fetch(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍👍
🚀 What’s this PR about?
🛠️ What’s been done?
🧪 Testing Details
👀 Checkpoints for Reviewers
groupInfo
가 API 네이밍과 중복될 가능성이 있어groupSummary
로 변경하였습니다.🎯 Related Issues