Skip to content

Commit 64be8e2

Browse files
KoSeonJeclaude
andcommitted
feat: 기존 피드 조회 API 4종에 카운트 필드 추가 (#388)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> (cherry picked from commit c7dfa5a)
1 parent 8c54baf commit 64be8e2

20 files changed

+553
-39
lines changed

src/main/java/ddingdong/ddingdongBE/domain/feed/controller/dto/response/ClubFeedPageResponse.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ record ClubFeedListResponse(
2929
String thumbnailCdnUrl,
3030
@Schema(description = "피드 썸네일 S3 URL", example = "https://%s.s3.%s.amazonaws.com/%s/%s/%s")
3131
String thumbnailOriginUrl,
32-
@Schema(description = "피드 썸네일 파일 이름", example = "filename.jpg")
33-
String thumbnailFilename,
3432
@Schema(description = "피드 타입", example = "IMAGE")
35-
String feedType
33+
String feedType,
34+
@Schema(description = "조회수", example = "150")
35+
long viewCount,
36+
@Schema(description = "좋아요 수", example = "10")
37+
long likeCount,
38+
@Schema(description = "댓글 수", example = "5")
39+
long commentCount
3640
) {
3741

3842
public static ClubFeedListResponse from(FeedListQuery feedListQuery) {
@@ -41,6 +45,9 @@ public static ClubFeedListResponse from(FeedListQuery feedListQuery) {
4145
.thumbnailCdnUrl(feedListQuery.thumbnailCdnUrl())
4246
.thumbnailOriginUrl(feedListQuery.thumbnailOriginUrl())
4347
.feedType(feedListQuery.feedType())
48+
.viewCount(feedListQuery.viewCount())
49+
.likeCount(feedListQuery.likeCount())
50+
.commentCount(feedListQuery.commentCount())
4451
.build();
4552
}
4653
}

src/main/java/ddingdong/ddingdongBE/domain/feed/controller/dto/response/FeedPageResponse.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,13 @@ public record FeedListResponse(
3535
@Schema(description = "피드 썸네일 파일 이름", example = "filename.jpg")
3636
String thumbnailFilename,
3737
@Schema(description = "피드 타입", example = "IMAGE")
38-
String feedType
38+
String feedType,
39+
@Schema(description = "조회수", example = "150")
40+
long viewCount,
41+
@Schema(description = "좋아요 수", example = "10")
42+
long likeCount,
43+
@Schema(description = "댓글 수", example = "5")
44+
long commentCount
3945
) {
4046

4147
public static FeedListResponse from(FeedListQuery query) {
@@ -45,6 +51,9 @@ public static FeedListResponse from(FeedListQuery query) {
4551
.thumbnailCdnUrl(query.thumbnailCdnUrl())
4652
.thumbnailFilename(query.thumbnailFileName())
4753
.feedType(query.feedType())
54+
.viewCount(query.viewCount())
55+
.likeCount(query.likeCount())
56+
.commentCount(query.commentCount())
4857
.build();
4958
}
5059
}

src/main/java/ddingdong/ddingdongBE/domain/feed/controller/dto/response/FeedResponse.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package ddingdong.ddingdongBE.domain.feed.controller.dto.response;
22

3+
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedCommentQuery;
34
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedQuery;
45
import ddingdong.ddingdongBE.domain.feed.service.dto.query.ClubProfileQuery;
56
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedFileInfoQuery;
7+
import io.swagger.v3.oas.annotations.media.ArraySchema;
68
import io.swagger.v3.oas.annotations.media.Schema;
79
import java.time.LocalDate;
10+
import java.time.LocalDateTime;
11+
import java.util.List;
812
import lombok.Builder;
913

1014
@Builder
@@ -17,12 +21,18 @@ public record FeedResponse(
1721
String feedType,
1822
@Schema(description = "조회수", example = "150")
1923
long viewCount,
24+
@Schema(description = "좋아요 수", example = "10")
25+
long likeCount,
26+
@Schema(description = "댓글 수", example = "5")
27+
long commentCount,
2028
@Schema(description = "생성 날짜", example = "2024-08-31")
2129
LocalDate createdDate,
2230
@Schema(description = "URL 정보", implementation = FileUrlResponse.class)
2331
FileUrlResponse fileUrls,
2432
@Schema(description = "동아리 정보")
25-
ClubProfileResponse clubProfile
33+
ClubProfileResponse clubProfile,
34+
@ArraySchema(schema = @Schema(description = "댓글 목록", implementation = CommentResponse.class))
35+
List<CommentResponse> comments
2636
) {
2737

2838
@Builder
@@ -73,15 +83,43 @@ public static FileUrlResponse from(FeedFileInfoQuery feedFileInfoQuery) {
7383
}
7484
}
7585

86+
@Builder
87+
public record CommentResponse(
88+
@Schema(description = "댓글 ID", example = "1")
89+
Long id,
90+
@Schema(description = "댓글 내용", example = "좋은 활동이네요!")
91+
String content,
92+
@Schema(description = "익명 이름", example = "익명1")
93+
String anonymousName,
94+
@Schema(description = "작성 일시")
95+
LocalDateTime createdAt
96+
) {
97+
98+
public static CommentResponse from(FeedCommentQuery query) {
99+
return CommentResponse.builder()
100+
.id(query.id())
101+
.content(query.content())
102+
.anonymousName(query.anonymousName())
103+
.createdAt(query.createdAt())
104+
.build();
105+
}
106+
}
107+
76108
public static FeedResponse from(FeedQuery query) {
109+
List<CommentResponse> commentResponses = query.comments() != null
110+
? query.comments().stream().map(CommentResponse::from).toList()
111+
: List.of();
77112
return FeedResponse.builder()
78113
.id(query.id())
79114
.clubProfile(ClubProfileResponse.from(query.clubProfileQuery()))
80115
.activityContent(query.activityContent())
81116
.fileUrls(FileUrlResponse.from(query.feedFileInfoQuery()))
82117
.feedType(query.feedType())
83118
.viewCount(query.viewCount())
119+
.likeCount(query.likeCount())
120+
.commentCount(query.commentCount())
84121
.createdDate(query.createdDate())
122+
.comments(commentResponses)
85123
.build();
86124
}
87125
}

src/main/java/ddingdong/ddingdongBE/domain/feed/controller/dto/response/MyFeedPageResponse.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
import java.util.List;
88
import lombok.Builder;
99

10+
@Builder
1011
public record MyFeedPageResponse(
12+
@Schema(description = "총 피드 수", example = "15")
13+
long feedCount,
14+
@Schema(description = "총 조회수", example = "1200")
15+
long totalViewCount,
1116
@ArraySchema(schema = @Schema(name = "동아리 피드 정보", implementation = MyFeedListResponse.class))
1217
List<MyFeedListResponse> clubFeeds,
1318
@Schema(name = "피드 페이지 정보", implementation = PagingResponse.class)
@@ -18,8 +23,12 @@ public static MyFeedPageResponse from(MyFeedPageQuery myFeedPageQuery) {
1823
List<MyFeedListResponse> clubFeeds = myFeedPageQuery.feedListQueries().stream()
1924
.map(MyFeedListResponse::from)
2025
.toList();
21-
return new MyFeedPageResponse(clubFeeds,
22-
PagingResponse.from(myFeedPageQuery.pagingQuery()));
26+
return MyFeedPageResponse.builder()
27+
.feedCount(myFeedPageQuery.feedCount())
28+
.totalViewCount(myFeedPageQuery.totalViewCount())
29+
.clubFeeds(clubFeeds)
30+
.pagingInfo(PagingResponse.from(myFeedPageQuery.pagingQuery()))
31+
.build();
2332
}
2433

2534
@Builder

src/main/java/ddingdong/ddingdongBE/domain/feed/repository/FeedCommentRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ddingdong.ddingdongBE.domain.feed.repository;
22

33
import ddingdong.ddingdongBE.domain.feed.entity.FeedComment;
4+
import ddingdong.ddingdongBE.domain.feed.repository.dto.FeedCountDto;
45
import java.util.List;
56
import java.util.Optional;
67
import org.springframework.data.jpa.repository.JpaRepository;
@@ -25,4 +26,13 @@ Optional<Integer> findAnonymousNumberByFeedIdAndUuid(
2526
List<FeedComment> findAllByFeedIdOrderByCreatedAtAsc(Long feedId);
2627

2728
long countByFeedId(Long feedId);
29+
30+
@Query(value = """
31+
SELECT fc.feed_id AS feedId, COUNT(*) AS cnt
32+
FROM feed_comment fc
33+
WHERE fc.feed_id IN (:feedIds)
34+
AND fc.deleted_at IS NULL
35+
GROUP BY fc.feed_id
36+
""", nativeQuery = true)
37+
List<FeedCountDto> countsByFeedIds(@Param("feedIds") List<Long> feedIds);
2838
}

src/main/java/ddingdong/ddingdongBE/domain/feed/repository/FeedLikeRepository.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package ddingdong.ddingdongBE.domain.feed.repository;
22

33
import ddingdong.ddingdongBE.domain.feed.entity.FeedLike;
4+
import ddingdong.ddingdongBE.domain.feed.repository.dto.FeedCountDto;
5+
import java.util.List;
46
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
59

610
public interface FeedLikeRepository extends JpaRepository<FeedLike, Long> {
711

@@ -10,4 +14,12 @@ public interface FeedLikeRepository extends JpaRepository<FeedLike, Long> {
1014
void deleteByFeedIdAndUuid(Long feedId, String uuid);
1115

1216
long countByFeedId(Long feedId);
17+
18+
@Query(value = """
19+
SELECT fl.feed_id AS feedId, COUNT(*) AS cnt
20+
FROM feed_like fl
21+
WHERE fl.feed_id IN (:feedIds)
22+
GROUP BY fl.feed_id
23+
""", nativeQuery = true)
24+
List<FeedCountDto> countsByFeedIds(@Param("feedIds") List<Long> feedIds);
1325
}

src/main/java/ddingdong/ddingdongBE/domain/feed/repository/FeedRepository.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import ddingdong.ddingdongBE.domain.feed.entity.Feed;
44
import ddingdong.ddingdongBE.domain.feed.repository.dto.MonthlyFeedRankingDto;
5+
import ddingdong.ddingdongBE.domain.feed.repository.dto.MyFeedStatDto;
56
import java.util.List;
67
import org.springframework.data.domain.Slice;
78
import org.springframework.data.jpa.repository.JpaRepository;
@@ -99,4 +100,15 @@ List<MonthlyFeedRankingDto> findMonthlyRankingByClub(
99100
@Param("month") int month
100101
);
101102

103+
@Query(value = """
104+
SELECT COUNT(f.id) AS feedCount,
105+
COALESCE(SUM(f.view_count), 0) AS totalViewCount,
106+
COALESCE(SUM(CASE WHEN f.feed_type = 'IMAGE' THEN 1 ELSE 0 END), 0) AS imageCount,
107+
COALESCE(SUM(CASE WHEN f.feed_type = 'VIDEO' THEN 1 ELSE 0 END), 0) AS videoCount
108+
FROM feed f
109+
WHERE f.deleted_at IS NULL
110+
AND f.club_id = :clubId
111+
""", nativeQuery = true)
112+
MyFeedStatDto findMyFeedStat(@Param("clubId") Long clubId);
113+
102114
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ddingdong.ddingdongBE.domain.feed.repository.dto;
2+
3+
public interface FeedCountDto {
4+
5+
Long getFeedId();
6+
7+
Long getCnt();
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ddingdong.ddingdongBE.domain.feed.repository.dto;
2+
3+
public interface MyFeedStatDto {
4+
5+
Long getFeedCount();
6+
7+
Long getTotalViewCount();
8+
9+
Long getImageCount();
10+
11+
Long getVideoCount();
12+
}

src/main/java/ddingdong/ddingdongBE/domain/feed/service/FacadeClubFeedServiceImpl.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import ddingdong.ddingdongBE.domain.club.entity.Club;
44
import ddingdong.ddingdongBE.domain.club.service.ClubService;
55
import ddingdong.ddingdongBE.domain.feed.entity.Feed;
6+
import ddingdong.ddingdongBE.domain.feed.repository.FeedRepository;
7+
import ddingdong.ddingdongBE.domain.feed.repository.dto.MyFeedStatDto;
68
import ddingdong.ddingdongBE.domain.feed.service.dto.command.CreateFeedCommand;
79
import ddingdong.ddingdongBE.domain.feed.service.dto.command.UpdateFeedCommand;
810
import ddingdong.ddingdongBE.domain.feed.service.dto.query.FeedListQuery;
@@ -17,6 +19,7 @@
1719
import ddingdong.ddingdongBE.sse.service.dto.SseEvent;
1820
import ddingdong.ddingdongBE.sse.service.dto.SseVodProcessingNotificationDto;
1921
import java.time.LocalDateTime;
22+
import java.util.Collections;
2023
import java.util.List;
2124
import lombok.RequiredArgsConstructor;
2225
import lombok.extern.slf4j.Slf4j;
@@ -36,6 +39,7 @@ public class FacadeClubFeedServiceImpl implements FacadeClubFeedService {
3639
private final VodProcessingJobService vodProcessingJobService;
3740
private final SseConnectionService sseConnectionService;
3841
private final FeedFileService feedFileService;
42+
private final FeedRepository feedRepository;
3943

4044
@Override
4145
@Transactional
@@ -74,17 +78,18 @@ public void delete(Long feedId) {
7478
@Override
7579
public MyFeedPageQuery getMyFeedPage(User user, int size, Long currentCursorId) {
7680
Club club = clubService.getByUserId(user.getId());
81+
MyFeedStatDto stat = feedRepository.findMyFeedStat(club.getId());
7782
Slice<Feed> feedPage = feedService.getFeedPageByClubId(club.getId(), size, currentCursorId);
7883
if (feedPage == null) {
79-
return MyFeedPageQuery.createEmpty();
84+
return MyFeedPageQuery.of(stat, Collections.emptyList(), PagingQuery.createEmpty());
8085
}
8186
List<Feed> completeFeeds = feedPage.getContent();
8287
List<FeedListQuery> feedListQueries = completeFeeds.stream()
8388
.map(feedFileService::extractFeedThumbnailInfo)
8489
.toList();
8590
PagingQuery pagingQuery = PagingQuery.of(currentCursorId, completeFeeds, feedPage.hasNext());
8691

87-
return MyFeedPageQuery.of(feedListQueries, pagingQuery);
92+
return MyFeedPageQuery.of(stat, feedListQueries, pagingQuery);
8893
}
8994

9095
private void checkVodProcessingJobAndNotify(Feed feed) {

0 commit comments

Comments
 (0)