diff --git a/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostSearchRepositoryImpl.java b/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostSearchRepositoryImpl.java index f255113a..e6423581 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostSearchRepositoryImpl.java +++ b/main/src/main/java/org/sopt/makers/crew/main/entity/post/PostSearchRepositoryImpl.java @@ -13,12 +13,15 @@ import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; + import lombok.RequiredArgsConstructor; + import org.sopt.makers.crew.main.common.exception.BadRequestException; import org.sopt.makers.crew.main.post.v2.dto.query.PostGetPostsCommand; import org.sopt.makers.crew.main.post.v2.dto.response.CommenterThumbnails; @@ -36,141 +39,113 @@ @Repository @RequiredArgsConstructor public class PostSearchRepositoryImpl implements PostSearchRepository { - private final JPAQueryFactory queryFactory; - - @Override - public Page findPostList(PostGetPostsCommand queryCommand, Pageable pageable, - Integer userId) { - Integer meetingId = queryCommand.getMeetingId().orElse(null); - - List content = getContentList(pageable, meetingId, userId); - JPAQuery countQuery = getCount(meetingId); - - return PageableExecutionUtils.getPage(content, - PageRequest.of(pageable.getPageNumber(), pageable.getPageSize()), countQuery::fetchFirst); - } - - @Override - public PostDetailBaseDto findPost(Integer userId, Integer postId) { - PostDetailBaseDto postDetail = queryFactory - .select(new QPostDetailBaseDto( - post.id, - post.title, - post.contents, - post.createdDate, - post.images, - new QPostWriterInfoDto( - post.user.id, - post.user.orgId, - post.user.name, - post.user.profileImage - ), - post.likeCount, - ExpressionUtils.as( - JPAExpressions.selectFrom(like) - .where(like.postId.eq(post.id).and(like.userId.eq(userId))) - .exists() - , "isLiked" - ), - post.viewCount, - post.commentCount, - new QPostMeetingDto( - post.meeting.id, - post.meeting.title, - post.meeting.category, - post.meeting.imageURL - ) - )) - .from(post) - .innerJoin(post.meeting, meeting) - .innerJoin(post.user, user) - .where(post.id.eq(postId)) - .fetchFirst(); - - if (postDetail == null) { - throw new BadRequestException(NOT_FOUND_POST.getErrorCode()); - } - - return postDetail; - } - - private List getContentList(Pageable pageable, Integer meetingId, - Integer userId) { - List responseDtos = new ArrayList<>(); - - List postDetailList = queryFactory - .select(new QPostDetailBaseDto( - post.id, - post.title, - post.contents, - post.createdDate, - post.images, - new QPostWriterInfoDto( - post.user.id, - post.user.orgId, - post.user.name, - post.user.profileImage - ), - post.likeCount, - ExpressionUtils.as( - JPAExpressions.selectFrom(like) - .where(like.postId.eq(post.id).and(like.userId.eq(userId))) - .exists() - , "isLiked" - ), - post.viewCount, - post.commentCount, - new QPostMeetingDto( - post.meeting.id, - post.meeting.title, - post.meeting.category, - post.meeting.imageURL - ) - )) - .from(post) - .innerJoin(post.user, user) - .innerJoin(post.meeting, meeting) - .where(meetingIdEq(meetingId)) - .orderBy(post.id.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); - - // 모든 게시글 ID를 추출 - List postIds = postDetailList.stream() - .map(PostDetailBaseDto::getId) - .collect(Collectors.toList()); - - // 게시글 ID 리스트를 사용하여 한 번에 모든 댓글 작성자의 프로필 이미지를 조회 - Map> commenterThumbnailsMap = queryFactory - .select(comment.post.id, comment.user.profileImage) - .from(comment) - .where(comment.post.id.in(postIds)) - .groupBy(comment.post.id, comment.user.id, comment.user.profileImage) - .orderBy(comment.post.id.asc(), comment.user.id.asc()) - .limit(3) - .transform(GroupBy.groupBy(comment.post.id).as(GroupBy.list(comment.user.profileImage))); - - // 각 게시글별로 댓글 작성자의 프로필 이미지 리스트를 설정 - for (PostDetailBaseDto postDetail : postDetailList) { - CommenterThumbnails commenterThumbnails = new CommenterThumbnails( - commenterThumbnailsMap.getOrDefault(postDetail.getId(), - Collections.emptyList())); - responseDtos.add(PostDetailResponseDto.of(postDetail, commenterThumbnails)); - } - - return responseDtos; - } - - private JPAQuery getCount(Integer meetingId) { - return queryFactory - .select(post.count()) - .from(post) - .where(meetingIdEq(meetingId)); - } - - private BooleanExpression meetingIdEq(Integer meetingId) { - return meetingId == null ? null : post.meetingId.eq(meetingId); - } + private final JPAQueryFactory queryFactory; + + @Override + public Page findPostList(PostGetPostsCommand queryCommand, Pageable pageable, + Integer userId) { + Integer meetingId = queryCommand.getMeetingId().orElse(null); + + List content = getContentList(pageable, meetingId, userId); + JPAQuery countQuery = getCount(meetingId); + + return PageableExecutionUtils.getPage(content, + PageRequest.of(pageable.getPageNumber(), pageable.getPageSize()), countQuery::fetchFirst); + } + + @Override + public PostDetailBaseDto findPost(Integer userId, Integer postId) { + PostDetailBaseDto postDetail = queryFactory + .select(new QPostDetailBaseDto( + post.id, post.title, post.contents, post.createdDate, post.images, + new QPostWriterInfoDto(post.user.id, post.user.orgId, post.user.name, post.user.profileImage), + post.likeCount, + ExpressionUtils.as( + JPAExpressions.selectFrom(like) + .where(like.postId.eq(post.id).and(like.userId.eq(userId))) + .exists() + , "isLiked" + ), + post.viewCount, post.commentCount, + new QPostMeetingDto(post.meeting.id, post.meeting.title, post.meeting.category, post.meeting.imageURL, + post.meeting.desc) + )) + .from(post) + .innerJoin(post.meeting, meeting) + .innerJoin(post.user, user) + .where(post.id.eq(postId)) + .fetchFirst(); + + if (postDetail == null) { + throw new BadRequestException(NOT_FOUND_POST.getErrorCode()); + } + + return postDetail; + } + + private List getContentList(Pageable pageable, Integer meetingId, + Integer userId) { + List responseDtos = new ArrayList<>(); + + List postDetailList = queryFactory + .select(new QPostDetailBaseDto( + post.id, post.title, post.contents, post.createdDate, post.images, + new QPostWriterInfoDto(post.user.id, post.user.orgId, post.user.name, post.user.profileImage), + post.likeCount, + ExpressionUtils.as( + JPAExpressions.selectFrom(like) + .where(like.postId.eq(post.id).and(like.userId.eq(userId))) + .exists() + , "isLiked" + ), + post.viewCount, post.commentCount, + new QPostMeetingDto(post.meeting.id, post.meeting.title, post.meeting.category, post.meeting.imageURL, + post.meeting.desc) + )) + .from(post) + .innerJoin(post.user, user) + .innerJoin(post.meeting, meeting) + .where(meetingIdEq(meetingId)) + .orderBy(post.id.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + // 모든 게시글 ID를 추출 + List postIds = postDetailList.stream() + .map(PostDetailBaseDto::getId) + .collect(Collectors.toList()); + + // 게시글 ID 리스트를 사용하여 한 번에 모든 댓글 작성자의 프로필 이미지를 조회 + Map> commenterThumbnailsMap = queryFactory + .select(comment.post.id, comment.user.profileImage) + .from(comment) + .where(comment.post.id.in(postIds)) + .groupBy(comment.post.id, comment.user.id, comment.user.profileImage) + .orderBy(comment.post.id.asc(), comment.user.id.asc()) + .limit(3) + .transform(GroupBy.groupBy(comment.post.id).as(GroupBy.list(comment.user.profileImage))); + + // 각 게시글별로 댓글 작성자의 프로필 이미지 리스트를 설정 + for (PostDetailBaseDto postDetail : postDetailList) { + CommenterThumbnails commenterThumbnails = new CommenterThumbnails( + commenterThumbnailsMap.getOrDefault(postDetail.getId(), + Collections.emptyList())); + responseDtos.add(PostDetailResponseDto.of(postDetail, commenterThumbnails)); + } + + return responseDtos; + } + + private JPAQuery getCount(Integer meetingId) { + return queryFactory + .select(post.count()) + .from(post) + .where(meetingIdEq(meetingId)); + } + + private BooleanExpression meetingIdEq(Integer meetingId) { + return meetingId == null ? null : post.meetingId.eq(meetingId); + } } diff --git a/main/src/main/java/org/sopt/makers/crew/main/post/v2/dto/response/PostMeetingDto.java b/main/src/main/java/org/sopt/makers/crew/main/post/v2/dto/response/PostMeetingDto.java index c833bab3..44c3d103 100644 --- a/main/src/main/java/org/sopt/makers/crew/main/post/v2/dto/response/PostMeetingDto.java +++ b/main/src/main/java/org/sopt/makers/crew/main/post/v2/dto/response/PostMeetingDto.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotNull; import lombok.Getter; + import org.sopt.makers.crew.main.entity.meeting.enums.MeetingCategory; import org.sopt.makers.crew.main.entity.meeting.vo.ImageUrlVO; @@ -15,27 +16,32 @@ @Schema(name = "PostMeetingDto", description = "게시글에 대한 모임 Dto") public class PostMeetingDto { - @Schema(description = "모임 id", example = "1") - @NotNull - private final Integer id; - - @Schema(description = "모임 제목", example = "모임 제목입니다.") - @NotNull - private final String title; - - @Schema(description = "모임 카테고리", example = "스터디") - @NotNull - private final String category; - - @Schema(description = "모임 이미지 url", example = "[url 형식]") - @NotNull - private final List imageURL; - - @QueryProjection - public PostMeetingDto(Integer id, String title, MeetingCategory category, List imageURL) { - this.id = id; - this.title = title; - this.category = category.getValue(); - this.imageURL = imageURL; - } + @Schema(description = "모임 id", example = "1") + @NotNull + private final Integer id; + + @Schema(description = "모임 제목", example = "모임 제목입니다.") + @NotNull + private final String title; + + @Schema(description = "모임 카테고리", example = "스터디") + @NotNull + private final String category; + + @Schema(description = "모임 이미지 url", example = "[url 형식]") + @NotNull + private final List imageURL; + + @Schema(description = "모임 설명", example = "모임 설명입니다.") + @NotNull + private final String desc; + + @QueryProjection + public PostMeetingDto(Integer id, String title, MeetingCategory category, List imageURL, String desc) { + this.id = id; + this.title = title; + this.category = category.getValue(); + this.imageURL = imageURL; + this.desc = desc; + } }