diff --git a/src/main/java/com/jiwon/mylog/domain/comment/controller/CommentController.java b/src/main/java/com/jiwon/mylog/domain/comment/controller/CommentController.java index 004ad06..c192bbc 100644 --- a/src/main/java/com/jiwon/mylog/domain/comment/controller/CommentController.java +++ b/src/main/java/com/jiwon/mylog/domain/comment/controller/CommentController.java @@ -1,6 +1,7 @@ package com.jiwon.mylog.domain.comment.controller; import com.jiwon.mylog.domain.comment.service.CommentService; +import com.jiwon.mylog.global.common.entity.PageResponse; import com.jiwon.mylog.global.security.auth.annotation.LoginUser; import com.jiwon.mylog.domain.comment.dto.request.CommentCreateRequest; import com.jiwon.mylog.domain.comment.dto.request.CommentUpdateRequest; @@ -10,9 +11,12 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -78,4 +82,15 @@ public ResponseEntity deleteComment( commentService.deleteComment(userId, postId, commentId); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } + + @GetMapping("/posts/{postId}/comments") + @Operation( + summary = "게시글에 해당하는 댓글 목록 조회 (페이징)" + ) + public ResponseEntity getComments( + @PathVariable("postId") Long postId, + @PageableDefault(size = 10, page = 0) Pageable pageable) { + PageResponse response = commentService.getComments(postId, pageable); + return ResponseEntity.ok(response); + } } \ No newline at end of file diff --git a/src/main/java/com/jiwon/mylog/domain/comment/dto/request/CommentCreateRequest.java b/src/main/java/com/jiwon/mylog/domain/comment/dto/request/CommentCreateRequest.java index 2892967..3d9541c 100644 --- a/src/main/java/com/jiwon/mylog/domain/comment/dto/request/CommentCreateRequest.java +++ b/src/main/java/com/jiwon/mylog/domain/comment/dto/request/CommentCreateRequest.java @@ -18,6 +18,6 @@ public class CommentCreateRequest { @Size(max = 500, message = "댓글은 최대 500자까지 입력할 수 있습니다.") private String content; - @NotNull(message = "게시글 공개 범위를 지정해주세요.") + @NotNull(message = "공개 범위를 지정해주세요.") private String visibility; } diff --git a/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepository.java b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepository.java index bd2c683..e82431d 100644 --- a/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepository.java +++ b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepository.java @@ -9,7 +9,7 @@ import java.util.Optional; @Repository -public interface CommentRepository extends JpaRepository { +public interface CommentRepository extends JpaRepository, CommentRepositoryCustom { @Query("select c from Comment c join fetch c.user u where c.id = :commentId") Optional findById(@Param("commentId") Long commentId); } diff --git a/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryCustom.java b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryCustom.java new file mode 100644 index 0000000..86652d4 --- /dev/null +++ b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryCustom.java @@ -0,0 +1,9 @@ +package com.jiwon.mylog.domain.comment.repository; + +import com.jiwon.mylog.domain.comment.dto.response.CommentResponse; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface CommentRepositoryCustom { + Page findByPostId(Long postId, Pageable pageable); +} diff --git a/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryImpl.java b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryImpl.java new file mode 100644 index 0000000..6918ab9 --- /dev/null +++ b/src/main/java/com/jiwon/mylog/domain/comment/repository/CommentRepositoryImpl.java @@ -0,0 +1,82 @@ +package com.jiwon.mylog.domain.comment.repository; + +import com.jiwon.mylog.domain.comment.dto.response.CommentResponse; +import com.jiwon.mylog.domain.comment.entity.QComment; +import com.jiwon.mylog.domain.image.entity.QProfileImage; +import com.jiwon.mylog.domain.user.dto.response.UserResponse; +import com.jiwon.mylog.domain.user.entity.QUser; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@RequiredArgsConstructor +@Repository +public class CommentRepositoryImpl implements CommentRepositoryCustom { + + private static final QComment COMMENT = QComment.comment; + private static final QUser USER = QUser.user; + private static final QProfileImage PROFILE_IMAGE = QProfileImage.profileImage; + private final JPAQueryFactory jpaQueryFactory; + + @Override + public Page findByPostId(Long postId, Pageable pageable) { + BooleanBuilder conditions = new BooleanBuilder() + .and(postIdEq(postId)); + + List comments = jpaQueryFactory + .select(Projections.constructor(CommentResponse.class, + COMMENT.id, + COMMENT.parent.id, + COMMENT.depth, + COMMENT.visibility, + COMMENT.commentStatus, + Expressions.cases() + .when(COMMENT.deletedAt.isNotNull()).then("삭제된 댓글입니다.") + .otherwise(COMMENT.content), + Projections.constructor(UserResponse.class, + USER.id, + USER.username, + USER.bio, + PROFILE_IMAGE.fileKey.coalesce(""), + USER.status + ), + COMMENT.createdAt, + COMMENT.updatedAt, + COMMENT.deletedAt + ) + ) + .from(COMMENT) + .leftJoin(COMMENT.user, USER) + .leftJoin(USER.profileImage, PROFILE_IMAGE) + .where(conditions) + .orderBy(COMMENT.createdAt.desc(), COMMENT.id.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + Long total = createCountQuery(conditions); + return new PageImpl<>(comments, pageable, total); + } + + private Long createCountQuery(BooleanBuilder builder) { + Long count = jpaQueryFactory + .select(COMMENT.count()) + .from(COMMENT) + .where(builder) + .fetchOne(); + + return count != null ? count : 0L; + } + + private BooleanExpression postIdEq(Long postId) { + return postId != null ? COMMENT.post.id.eq(postId) : null; + } +} diff --git a/src/main/java/com/jiwon/mylog/domain/comment/service/CommentService.java b/src/main/java/com/jiwon/mylog/domain/comment/service/CommentService.java index b949ae5..1056959 100644 --- a/src/main/java/com/jiwon/mylog/domain/comment/service/CommentService.java +++ b/src/main/java/com/jiwon/mylog/domain/comment/service/CommentService.java @@ -9,6 +9,7 @@ import com.jiwon.mylog.domain.event.dto.comment.CommentDeletedEvent; import com.jiwon.mylog.domain.post.entity.Post; import com.jiwon.mylog.domain.user.entity.User; +import com.jiwon.mylog.global.common.entity.PageResponse; import com.jiwon.mylog.global.common.error.ErrorCode; import com.jiwon.mylog.global.common.error.exception.ForbiddenException; import com.jiwon.mylog.global.common.error.exception.NotFoundException; @@ -16,8 +17,9 @@ import com.jiwon.mylog.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.cache.annotation.CacheEvict; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,7 +33,6 @@ public class CommentService { private final PostRepository postRepository; private final CommentRepository commentRepository; - @CacheEvict(value = "post::detail", key = "#postId") @Transactional public CommentResponse createComment(Long userId, Long postId, CommentCreateRequest request) { @@ -64,7 +65,6 @@ public CommentResponse createComment(Long userId, Long postId, CommentCreateRequ return CommentResponse.fromComment(savedComment); } - @CacheEvict(value = "post::detail", key = "#postId") @Transactional public CommentResponse updateComment(Long userId, Long postId, Long commentId, CommentUpdateRequest request) { Comment comment = getComment(commentId); @@ -73,7 +73,6 @@ public CommentResponse updateComment(Long userId, Long postId, Long commentId, C return CommentResponse.fromComment(comment); } - @CacheEvict(value = "post::detail", key = "#postId") @Transactional public void deleteComment(Long userId, Long postId, Long commentId) { Comment comment = getComment(commentId); @@ -94,6 +93,18 @@ public void deleteComment(Long userId, Long postId, Long commentId) { comment.delete(); } + @Transactional(readOnly = true) + public PageResponse getComments(Long postId, Pageable pageable) { + Page commentPage = commentRepository.findByPostId(postId, pageable); + return PageResponse.from( + commentPage.getContent(), + commentPage.getNumber(), + commentPage.getSize(), + commentPage.getTotalPages(), + commentPage.getTotalElements() + ); + } + private Comment getComment(Long commentId) { return commentRepository.findById(commentId) .orElseThrow(() -> new NotFoundException(ErrorCode.NOT_FOUND_COMMENT)); diff --git a/src/main/java/com/jiwon/mylog/domain/post/controller/PostController.java b/src/main/java/com/jiwon/mylog/domain/post/controller/PostController.java index 40b2e4a..4811d75 100644 --- a/src/main/java/com/jiwon/mylog/domain/post/controller/PostController.java +++ b/src/main/java/com/jiwon/mylog/domain/post/controller/PostController.java @@ -1,6 +1,5 @@ package com.jiwon.mylog.domain.post.controller; -import com.jiwon.mylog.domain.post.dto.response.PostNavigationResponse; import com.jiwon.mylog.domain.post.service.PostService; import com.jiwon.mylog.domain.post.service.PostViewService; import com.jiwon.mylog.global.security.auth.annotation.AllUser; @@ -115,6 +114,18 @@ public ResponseEntity getPost( return new ResponseEntity<>(response, HttpStatus.OK); } + @GetMapping("/posts/{postId}/related-post") + @Operation( + summary = "postId와 동일한 카테고리에 해당하는 게시글 목록 조회" + ) + public ResponseEntity getRelatedPosts( + @PathVariable("postId") Long postId, + @RequestParam(required = false) Integer page, + @RequestParam(defaultValue = "5") int size) { + PageResponse response = postService.getRelatedPosts(postId, page, size); + return ResponseEntity.ok(response); + } + @GetMapping("/posts") public ResponseEntity getPosts( @PageableDefault(size = 10, page = 0, @@ -123,23 +134,6 @@ public ResponseEntity getPosts( return new ResponseEntity<>(response, HttpStatus.OK); } - @GetMapping("/posts/{postId}/navigation") - @Operation( - summary = "현재 게시글의 정보(카테고리 ID, 카테고리 내에서의 현재 page, offset)를 획득한다." - ) - public ResponseEntity getPostNavigation(@PathVariable("postId") Long postId) { - PostNavigationResponse response = postService.getPostNavigation(postId); - return ResponseEntity.ok(response); - } - - @GetMapping("/categories/{categoryId}/posts") - public ResponseEntity getCategorizedPosts( - @PathVariable("categoryId") Long categoryId, - @RequestParam Long userId, - @PageableDefault(size = 5, sort = "createdAt", direction = Direction.DESC) Pageable pageable) { - PageResponse response = postService.getCategorizedPosts(categoryId, userId, pageable); - return ResponseEntity.ok(response); - } @GetMapping("/users/{userId}/categories/{categoryId}/posts") @Operation( diff --git a/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostDetailResponse.java b/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostDetailResponse.java index ae1429a..697ed84 100644 --- a/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostDetailResponse.java +++ b/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostDetailResponse.java @@ -5,7 +5,6 @@ import com.jiwon.mylog.domain.post.entity.PostType; import com.jiwon.mylog.global.common.enums.Visibility; import com.jiwon.mylog.domain.category.dto.response.CategoryResponse; -import com.jiwon.mylog.domain.comment.dto.response.CommentResponse; import com.jiwon.mylog.domain.post.entity.PostStatus; import com.jiwon.mylog.domain.tag.dto.response.TagResponse; import com.jiwon.mylog.domain.user.dto.response.UserResponse; @@ -35,7 +34,6 @@ public class PostDetailResponse { private UserResponse user; private CategoryResponse category; private List tags; - private List comments; private RelatedPostResponse previousPost; private RelatedPostResponse nextPost; @@ -71,9 +69,6 @@ public static PostDetailResponse fromPost(Post post) { .createdAt(post.getCreatedAt()) .pinned(post.isPinned()) .type(post.getType()) - .comments(post.getComments().stream() - .map(comment -> CommentResponse.fromComment(comment)) - .toList()) .build(); } @@ -86,8 +81,7 @@ public void setViews(int views) { this.views = views; } - public void setTagsAndComments(List tags, List comments) { + public void setTags(List tags) { this.tags = tags; - this.comments = comments; } } diff --git a/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostNavigationResponse.java b/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostNavigationResponse.java deleted file mode 100644 index ca7fcf8..0000000 --- a/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostNavigationResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.jiwon.mylog.domain.post.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; - -@Builder -@AllArgsConstructor -@Getter -public class PostNavigationResponse { - private final Long postId; - private final Long userId; - private final Long categoryId; - private final Long currentOffset; - private final Long currentPage; - private final Long totalPosts; -} diff --git a/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostRelationData.java b/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostRelationData.java new file mode 100644 index 0000000..9037a55 --- /dev/null +++ b/src/main/java/com/jiwon/mylog/domain/post/dto/response/PostRelationData.java @@ -0,0 +1,12 @@ +package com.jiwon.mylog.domain.post.dto.response; + +import java.time.LocalDateTime; +import lombok.Builder; + +@Builder +public record PostRelationData( + Long userId, + Long categoryId, + LocalDateTime createdAt +) { +} diff --git a/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryCustom.java b/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryCustom.java index e657372..a6545cf 100644 --- a/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryCustom.java +++ b/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryCustom.java @@ -2,7 +2,6 @@ import com.jiwon.mylog.domain.post.dto.response.MainPostResponse; import com.jiwon.mylog.domain.post.dto.response.PostDetailResponse; -import com.jiwon.mylog.domain.post.dto.response.PostNavigationResponse; import com.jiwon.mylog.domain.post.dto.response.PostSummaryResponse; import com.jiwon.mylog.domain.post.dto.response.RelatedPostResponse; import com.jiwon.mylog.domain.user.dto.response.UserActivityResponse; @@ -24,7 +23,5 @@ public interface PostRepositoryCustom { List findUserActivities(Long userId, LocalDate start, LocalDate end); - PostNavigationResponse findPostNavigation(Long postId); - - Page findCategorizedPosts(Long categoryId, Long userId, Pageable pageable); + Page findRelatedPosts(Long postId, Integer page, int size); } diff --git a/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryImpl.java b/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryImpl.java index e69fdf8..6d09982 100644 --- a/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryImpl.java +++ b/src/main/java/com/jiwon/mylog/domain/post/repository/PostRepositoryImpl.java @@ -2,13 +2,12 @@ import com.jiwon.mylog.domain.category.dto.response.CategoryResponse; import com.jiwon.mylog.domain.category.entity.QCategory; -import com.jiwon.mylog.domain.comment.dto.response.CommentResponse; import com.jiwon.mylog.domain.comment.entity.QComment; import com.jiwon.mylog.domain.image.entity.QProfileImage; import com.jiwon.mylog.domain.like.entity.QPostLike; import com.jiwon.mylog.domain.post.dto.response.MainPostResponse; import com.jiwon.mylog.domain.post.dto.response.PostDetailResponse; -import com.jiwon.mylog.domain.post.dto.response.PostNavigationResponse; +import com.jiwon.mylog.domain.post.dto.response.PostRelationData; import com.jiwon.mylog.domain.post.dto.response.PostSummaryResponse; import com.jiwon.mylog.domain.post.dto.response.RelatedPostResponse; import com.jiwon.mylog.domain.post.entity.PostType; @@ -21,8 +20,9 @@ import com.jiwon.mylog.domain.user.dto.response.UserSummaryResponse; import com.jiwon.mylog.domain.user.entity.QUser; import com.jiwon.mylog.global.common.enums.Visibility; +import com.jiwon.mylog.global.common.error.ErrorCode; +import com.jiwon.mylog.global.common.error.exception.NotFoundException; import com.querydsl.core.BooleanBuilder; -import com.querydsl.core.Tuple; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.DateTemplate; @@ -33,6 +33,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -233,16 +234,15 @@ public Optional findPostDetail(Long postId) { return Optional.empty(); } - loadCommentsAndTags(postId, postDetailResponse); + loadTags(postId, postDetailResponse); loadAdjacentPosts(postId, postDetailResponse); return Optional.of(postDetailResponse); } - private void loadCommentsAndTags(Long postId, PostDetailResponse postDetailResponse) { + private void loadTags(Long postId, PostDetailResponse postDetailResponse) { List tags = getTagsByPostId(postId); - List comments = getCommentsByPostId(postId); - postDetailResponse.setTagsAndComments(tags, comments); + postDetailResponse.setTags(tags); } private List getTagsByPostId(Long postId) { @@ -258,43 +258,14 @@ private List getTagsByPostId(Long postId) { .fetch(); } - private List getCommentsByPostId(Long postId) { - return jpaQueryFactory - .select(Projections.constructor(CommentResponse.class, - COMMENT.id, - COMMENT.parent.id, - COMMENT.depth, - COMMENT.visibility, - COMMENT.commentStatus, - COMMENT.content, - Projections.constructor(UserResponse.class, - USER.id, - USER.username, - USER.bio, - PROFILE_IMAGE.fileKey.coalesce(""), - USER.status - ), - COMMENT.createdAt, - COMMENT.updatedAt, - COMMENT.deletedAt - ) - ) - .from(COMMENT) - .join(COMMENT.user, USER) - .leftJoin(COMMENT.user.profileImage, PROFILE_IMAGE) - .where(COMMENT.post.id.eq(postId)) - .orderBy(COMMENT.createdAt.desc()) - .fetch(); - } - private void loadAdjacentPosts(Long postId, PostDetailResponse postDetailResponse) { - Tuple postData = getPostData(postId); + PostRelationData postData = getPostData(postId); if (postData == null) { postDetailResponse.setRelatedPosts(null, null); } else { - Long userId = postData.get(0, Long.class); - Long categoryId = postData.get(1, Long.class); - LocalDateTime createdAt = postData.get(2, LocalDateTime.class); + Long userId = postData.userId(); + Long categoryId = postData.categoryId(); + LocalDateTime createdAt = postData.createdAt(); RelatedPostResponse previousPost = getPreviousPost(userId, categoryId, createdAt); RelatedPostResponse nextPost = getNextPost(userId, categoryId, createdAt); @@ -336,56 +307,47 @@ private RelatedPostResponse getNextPost(Long userId, Long categoryId, LocalDateT .fetchOne(); } - private Tuple getPostData(Long postId) { - Tuple currentPost = jpaQueryFactory - .select(POST.user.id, + private PostRelationData getPostData(Long postId) { + return jpaQueryFactory + .select(Projections.constructor(PostRelationData.class, + POST.user.id, POST.category.id.coalesce(-1L), POST.createdAt - ) + )) .from(POST) .where(postIdEq(postId)) .fetchOne(); - return currentPost; } @Override - public PostNavigationResponse findPostNavigation(Long postId) { + public Page findRelatedPosts(Long postId, Integer page, int size) { - Tuple postData = getPostData(postId); + PostRelationData postData = getPostData(postId); if (postData == null) { - return null; + throw new NotFoundException(ErrorCode.NOT_FOUND_POST); } - Long defaultPageSize = 5L; + Long categoryId = postData.categoryId(); + Long userId = postData.userId(); + LocalDateTime createdAt = postData.createdAt(); - Long userId = postData.get(0, Long.class); - Long categoryId = postData.get(1, Long.class); - LocalDateTime createdAt = postData.get(2, LocalDateTime.class); + Integer currentPage = page; - BooleanBuilder conditions = - buildCategoryPostConditions(userId, categoryId) - .and(createdAtGt(createdAt)); - Long offset = createCountQuery(conditions); - - long currentPage = offset / defaultPageSize; - long currentPageOffset = offset - (offset % defaultPageSize); - - return PostNavigationResponse.builder() - .postId(postId) - .userId(userId) - .categoryId(categoryId) - .currentOffset(currentPageOffset) - .currentPage(currentPage) - .build(); - } + if (page == null) { + BooleanBuilder newerPostConditions = + buildCategoryPostConditions(userId, categoryId) + .and(createdAtGt(createdAt)); + + Long newerPostCount = createCountQuery(newerPostConditions); + currentPage = newerPostCount.intValue() / size; + } - @Override - public Page findCategorizedPosts(Long categoryId, Long userId, Pageable pageable) { BooleanBuilder conditions = buildCategoryPostConditions(userId, categoryId); List categoryPosts = - createCategoryPostQuery(conditions, pageable); + createCategoryPostQuery(conditions, currentPage, size); Long total = createCountQuery(conditions); - return new PageImpl<>(categoryPosts, pageable, total); + + return new PageImpl<>(categoryPosts, PageRequest.of(currentPage, size), total); } private BooleanBuilder buildCategoryPostConditions(Long userId, Long categoryId) { @@ -395,7 +357,7 @@ private BooleanBuilder buildCategoryPostConditions(Long userId, Long categoryId) .and(categoryIdEq(categoryId)); } - private List createCategoryPostQuery(BooleanBuilder conditions, Pageable pageable) { + private List createCategoryPostQuery(BooleanBuilder conditions, int page, int size) { return jpaQueryFactory .select(Projections.constructor(RelatedPostResponse.class, POST.id, POST.title, POST.createdAt @@ -404,8 +366,8 @@ private List createCategoryPostQuery(BooleanBuilder conditi .from(POST) .where(conditions) .orderBy(POST.createdAt.desc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) + .offset(page * size) + .limit(size) .fetch(); } @@ -439,11 +401,13 @@ public List findUserActivities(Long userId, LocalDate star } private Long createCountQuery(BooleanBuilder builder) { - return jpaQueryFactory + Long count = jpaQueryFactory .select(POST.count()) .from(POST) .where(builder) .fetchOne(); + + return count != null ? count : 0L; } private void setTagsToPosts(List posts) { diff --git a/src/main/java/com/jiwon/mylog/domain/post/service/PostService.java b/src/main/java/com/jiwon/mylog/domain/post/service/PostService.java index ce6d567..16be5eb 100644 --- a/src/main/java/com/jiwon/mylog/domain/post/service/PostService.java +++ b/src/main/java/com/jiwon/mylog/domain/post/service/PostService.java @@ -8,7 +8,6 @@ import com.jiwon.mylog.domain.post.dto.response.MainPostResponse; import com.jiwon.mylog.domain.post.dto.response.NoticePostResponse; import com.jiwon.mylog.domain.post.dto.response.PostDetailResponse; -import com.jiwon.mylog.domain.post.dto.response.PostNavigationResponse; import com.jiwon.mylog.domain.post.dto.response.RelatedPostResponse; import com.jiwon.mylog.domain.tag.entity.PostTag; import com.jiwon.mylog.domain.tag.repository.posttag.PostTagJdbcRepository; @@ -59,7 +58,6 @@ public class PostService { evict = { @CacheEvict(value = "post::notice", allEntries = true, condition = "#postRequest.type.equals('공지')"), @CacheEvict(value = "post::main", allEntries = true, condition = "#postRequest.type.equals('일반 글')"), - @CacheEvict(value = "post::filter", allEntries = true, condition = "#postRequest.type.equals('일반 글')"), @CacheEvict(value = "blog::home", key = "#userId", condition = "#userId != null") } @@ -90,7 +88,6 @@ public PostDetailResponse createPost(Long userId, PostRequest postRequest) { evict = { @CacheEvict(value = "post::notice", allEntries = true, condition = "#postRequest.type.equals('공지')"), @CacheEvict(value = "post::main", allEntries = true, condition = "#postRequest.type.equals('일반 글')"), - @CacheEvict(value = "post::filter", allEntries = true, condition = "#postRequest.type.equals('일반 글')"), @CacheEvict(value = "blog::home", key = "#userId", condition = "#userId != null") } @@ -115,7 +112,6 @@ public PostDetailResponse updatePost(Long userId, Long postId, PostRequest postR @Caching(evict = { @CacheEvict(value = "post::detail", key = "#postId"), @CacheEvict(value = "post::main", allEntries = true), - @CacheEvict(value = "post::filter", allEntries = true), @CacheEvict(value = "blog::home", key = "#userId", condition = "#userId != null") }) @@ -176,7 +172,7 @@ private void deleteRelatedPostInfo(Post post) { } @Cacheable(value = "post::notice", - key = "'page:' + #pageable.pageNumber + ':size:' + #pageable.pageSize", + key = "'page:' + #pageable.pageNumber", condition = "#pageable != null" ) @Transactional(readOnly = true) @@ -205,7 +201,7 @@ public PostDetailResponse getPost(Long postId) { } @Cacheable(value = "post::main", - key = "'page:' + #pageable.pageNumber + ':size:' + #pageable.pageSize", + key = "'page:' + #pageable.pageNumber", condition = "#pageable != null") @Transactional(readOnly = true) public PageResponse getPosts(Pageable pageable) { @@ -220,13 +216,8 @@ public PageResponse getPosts(Pageable pageable) { } @Transactional(readOnly = true) - public PostNavigationResponse getPostNavigation(Long postId) { - return postRepository.findPostNavigation(postId); - } - - @Transactional(readOnly = true) - public PageResponse getCategorizedPosts(Long categoryId, Long userId, Pageable pageable) { - Page postPage = postRepository.findCategorizedPosts(categoryId, userId, pageable); + public PageResponse getRelatedPosts(Long postId, Integer page, int size) { + Page postPage = postRepository.findRelatedPosts(postId, page, size); return PageResponse.from( postPage.getContent(), postPage.getNumber(), @@ -236,7 +227,6 @@ public PageResponse getCategorizedPosts(Long categoryId, Long userId, Pageable p ); } - @Cacheable(value = "post::filter", keyGenerator = "postCacheKeyGenerator") @Transactional(readOnly = true) public PageResponse getFilteredPosts( Long userId, diff --git a/src/main/java/com/jiwon/mylog/domain/statistic/UserStatsService.java b/src/main/java/com/jiwon/mylog/domain/statistic/UserStatsService.java index cf830ef..04dd3db 100644 --- a/src/main/java/com/jiwon/mylog/domain/statistic/UserStatsService.java +++ b/src/main/java/com/jiwon/mylog/domain/statistic/UserStatsService.java @@ -33,14 +33,7 @@ public class UserStatsService { @Cacheable(value = "stat::ranker") @Transactional(readOnly = true) public List getRanker() { - Optional latest = userWeeklyRankerRepository.findLatestWeekStartDate(); - - if (latest.isEmpty()) { - return Collections.emptyList(); - } - - List rankers = - userWeeklyRankerRepository.findAllByWeekStart(latest.get()); + List rankers = userWeeklyRankerRepository.findAllByWeekStart(); return rankers.stream() .map(UserRankResponse::fromRanker) diff --git a/src/main/java/com/jiwon/mylog/domain/statistic/repository/UserWeeklyRankerRepository.java b/src/main/java/com/jiwon/mylog/domain/statistic/repository/UserWeeklyRankerRepository.java index 30d50ca..e1ee451 100644 --- a/src/main/java/com/jiwon/mylog/domain/statistic/repository/UserWeeklyRankerRepository.java +++ b/src/main/java/com/jiwon/mylog/domain/statistic/repository/UserWeeklyRankerRepository.java @@ -14,13 +14,10 @@ public interface UserWeeklyRankerRepository extends JpaRepository findLatestWeekStartDate(); - @Query("select uwr from UserWeeklyRanker uwr " + "join fetch uwr.user u " + "left join fetch u.profileImage " - + "where uwr.weekStart = :weekStart " - + "order by uwr.rankOrder asc ") - List findAllByWeekStart(@Param("weekStart") LocalDate weekStart); + + "where uwr.weekStart = (select max(uwr2.weekStart) from UserWeeklyRanker uwr2) " + + "order by uwr.rankOrder asc") + List findAllByWeekStart(); } diff --git a/src/main/java/com/jiwon/mylog/global/common/config/CacheConfig.java b/src/main/java/com/jiwon/mylog/global/common/config/CacheConfig.java index 62f48cd..0febb74 100644 --- a/src/main/java/com/jiwon/mylog/global/common/config/CacheConfig.java +++ b/src/main/java/com/jiwon/mylog/global/common/config/CacheConfig.java @@ -17,7 +17,7 @@ public CacheManager cacheManager() { cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000) - .expireAfterWrite(Duration.ofHours(1))); + .expireAfterWrite(Duration.ofMinutes(30))); cacheManager.registerCustomCache("dailyFortune", Caffeine.newBuilder()