Skip to content

Commit b2d9b2b

Browse files
authored
[feat] 내가 추천한 게시글 목록 조회 기능 구현 #104 (#115)
* feat: 내가 '좋아요'한 게시글 목록을 위한 DTO 추가 * feat: 내가 '좋아요'한 게시글 목록 DTO 추가 * feat: 마이페이지 '좋아요' 게시글 리포지토리 추가 - 사용자가 '좋아요'한 게시글 목록을 조회하기 위한 리포지토리 구현 - `findMyLikedPostsFirstPage`: 첫 페이지 조회 쿼리 추가 - `findMyLikedPostsAfter`: 무한 스크롤을 위한 다음 페이지 조회 쿼리 추가 - '좋아요' 상태가 활성화되고 게시글이 삭제되지 않은 항목만 조회하도록 필터링 * feat: 마이페이지 '좋아요' 게시글 기능 추가 - 사용자가 '좋아요'를 누른 게시글 목록을 조회하는 `getMyLikedPosts` 메서드 추가 - 무한 스크롤(pagination)을 지원하기 위해 `lastCreatedAt` 및 `lastId` 파라미터 활용 - `MyHistoryLikedPostRepository`를 사용하여 데이터베이스에서 '좋아요' 기록을 조회 - `PostLike` 엔티티를 `MyHistoryLikedPostItemDto`로 변환하여 반환 - '좋아요' 기록이 없는 경우나 다음 페이지가 없는 경우를 처리하는 로직 포함 * feat: 마이페이지 '좋아요' 게시글 API 추가 * feat: '좋아요' 게시글 리포지토리 쿼리 추가 - 특정 게시글에 대한 사용자의 '좋아요' 기록을 찾는 `findByPostIdAndUserIdLike` 쿼리 추가 - 게시글 ID와 사용자 ID를 기준으로 '좋아요' 상태의 `PostLike` 엔티티를 조회 * feat: 내가 '좋아요'한 게시글 링크 기능 추가 - 사용자가 '좋아요'를 누른 게시글의 링크를 반환하는 `getPostLinkFromMyLikedPost` 메서드 추가 - `MyHistoryLikedPostRepository`를 사용하여 특정 게시글에 대한 사용자의 '좋아요' 기록을 조회 - '좋아요' 기록이 없거나 게시글이 삭제된 경우 예외 처리 * feat: 마이페이지 '좋아요' 게시글 링크 기능 API 추가
1 parent c399635 commit b2d9b2b

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

src/main/java/com/back/domain/myhistory/controller/MyHistoryController.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.myhistory.dto.MyHistoryCommentGoResponseDto;
44
import com.back.domain.myhistory.dto.MyHistoryCommentListDto;
55
import com.back.domain.myhistory.dto.MyHistoryPostListDto;
6+
import com.back.domain.myhistory.dto.MyHistoryLikedPostListDto;
67
import com.back.domain.myhistory.service.MyHistoryService;
78
import com.back.global.rsData.RsData;
89
import jakarta.validation.constraints.Max;
@@ -54,6 +55,17 @@ public RsData<MyHistoryCommentListDto> getMyComments(
5455
return RsData.successOf(body);
5556
}
5657

58+
@GetMapping("/likes")
59+
public RsData<MyHistoryLikedPostListDto> getMyLikedPosts(
60+
@AuthenticationPrincipal(expression = "id") Long userId,
61+
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime lastCreatedAt,
62+
@RequestParam(required = false) Long lastId,
63+
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int limit
64+
) {
65+
MyHistoryLikedPostListDto body = myHistoryService.getMyLikedPosts(userId, lastCreatedAt, lastId, limit);
66+
return RsData.successOf(body);
67+
}
68+
5769
@GetMapping("/comments/{id}")
5870
public RsData<MyHistoryCommentGoResponseDto> goFromComment(
5971
@AuthenticationPrincipal(expression = "id") Long userId,
@@ -62,5 +74,14 @@ public RsData<MyHistoryCommentGoResponseDto> goFromComment(
6274
var body = myHistoryService.getPostLinkFromMyComment(userId, commentId);
6375
return RsData.successOf(body);
6476
}
77+
78+
@GetMapping("/likes/{id}")
79+
public RsData<com.back.domain.myhistory.dto.MyHistoryPostGoResponseDto> goFromLikedPost(
80+
@AuthenticationPrincipal(expression = "id") Long userId,
81+
@PathVariable("id") Long postId
82+
) {
83+
var body = myHistoryService.getPostLinkFromMyLikedPost(userId, postId);
84+
return RsData.successOf(body);
85+
}
6586
}
6687

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.back.domain.myhistory.dto;
2+
3+
import com.back.domain.post.post.entity.Post;
4+
import com.back.domain.post.post.entity.PostLike;
5+
import java.time.LocalDateTime;
6+
import lombok.Builder;
7+
import lombok.Getter;
8+
9+
@Getter
10+
@Builder
11+
public class MyHistoryLikedPostItemDto {
12+
private Long id;
13+
private String title;
14+
private String imageUrl;
15+
private LocalDateTime likedAt;
16+
private Integer likeCount;
17+
private Integer commentCount;
18+
19+
public static MyHistoryLikedPostItemDto from(PostLike pl) {
20+
Post p = pl.getPost();
21+
return MyHistoryLikedPostItemDto.builder()
22+
.id(p.getId())
23+
.title(p.getTitle())
24+
.imageUrl(p.getImageUrl())
25+
.likedAt(pl.getCreatedAt())
26+
.likeCount(p.getLikeCount())
27+
.commentCount(p.getCommentCount())
28+
.build();
29+
}
30+
}
31+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.back.domain.myhistory.dto;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.List;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Getter;
7+
8+
@Getter
9+
@AllArgsConstructor
10+
public class MyHistoryLikedPostListDto {
11+
private List<MyHistoryLikedPostItemDto> items;
12+
private boolean hasNext;
13+
private LocalDateTime nextCreatedAt;
14+
private Long nextId;
15+
}
16+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.back.domain.myhistory.repository;
2+
3+
import com.back.domain.post.post.entity.PostLike;
4+
import com.back.domain.post.post.enums.PostLikeStatus;
5+
import com.back.domain.post.post.enums.PostStatus;
6+
import java.time.LocalDateTime;
7+
import java.util.List;
8+
import org.springframework.data.domain.Pageable;
9+
import org.springframework.data.jpa.repository.JpaRepository;
10+
import org.springframework.data.jpa.repository.Query;
11+
import org.springframework.data.repository.query.Param;
12+
import org.springframework.stereotype.Repository;
13+
14+
@Repository
15+
public interface MyHistoryLikedPostRepository extends JpaRepository<PostLike, Long> {
16+
17+
@Query("""
18+
select pl from PostLike pl
19+
join fetch pl.post p
20+
where pl.user.id = :userId
21+
and pl.status = :like
22+
and p.status <> :deleted
23+
order by pl.createdAt desc, pl.id desc
24+
""")
25+
List<PostLike> findMyLikedPostsFirstPage(@Param("userId") Long userId,
26+
@Param("like") PostLikeStatus like,
27+
@Param("deleted") PostStatus deleted,
28+
Pageable pageable);
29+
30+
@Query("""
31+
select pl from PostLike pl
32+
join fetch pl.post p
33+
where pl.user.id = :userId
34+
and pl.status = :like
35+
and p.status <> :deleted
36+
and (pl.createdAt < :lastCreatedAt or (pl.createdAt = :lastCreatedAt and pl.id < :lastId))
37+
order by pl.createdAt desc, pl.id desc
38+
""")
39+
List<PostLike> findMyLikedPostsAfter(@Param("userId") Long userId,
40+
@Param("like") PostLikeStatus like,
41+
@Param("deleted") PostStatus deleted,
42+
@Param("lastCreatedAt") LocalDateTime lastCreatedAt,
43+
@Param("lastId") Long lastId,
44+
Pageable pageable);
45+
46+
@Query("""
47+
select pl from PostLike pl
48+
join fetch pl.post p
49+
where p.id = :postId
50+
and pl.user.id = :userId
51+
and pl.status = :like
52+
""")
53+
PostLike findByPostIdAndUserIdLike(@Param("postId") Long postId,
54+
@Param("userId") Long userId,
55+
@Param("like") PostLikeStatus like);
56+
}

src/main/java/com/back/domain/myhistory/service/MyHistoryService.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.back.domain.myhistory.dto.*;
44
import com.back.domain.myhistory.repository.MyHistoryCommentRepository;
55
import com.back.domain.myhistory.repository.MyHistoryPostRepository;
6+
import com.back.domain.myhistory.repository.MyHistoryLikedPostRepository;
67
import com.back.domain.post.comment.entity.Comment;
78
import com.back.domain.post.post.entity.Post;
89
import com.back.domain.post.post.enums.PostStatus;
@@ -22,6 +23,7 @@ public class MyHistoryService {
2223

2324
private final MyHistoryPostRepository myHistoryPostRepository;
2425
private final MyHistoryCommentRepository myHistoryCommentRepository;
26+
private final MyHistoryLikedPostRepository myHistoryLikedPostRepository;
2527

2628
@Transactional(readOnly = true)
2729
public MyHistoryPostListDto getMyPosts(Long userId, LocalDateTime lastCreatedAt, Long lastId, int limit) {
@@ -108,4 +110,63 @@ public MyHistoryPostGoResponseDto getPostLinkFromMyPost(Long userId, Long postId
108110
String apiUrl = "/api/posts/" + p.getId();
109111
return new MyHistoryPostGoResponseDto(p.getId(), apiUrl);
110112
}
113+
114+
@Transactional(readOnly = true)
115+
public MyHistoryLikedPostListDto getMyLikedPosts(Long userId, LocalDateTime lastCreatedAt, Long lastId, int limit) {
116+
int safeLimit = Math.max(1, Math.min(limit, 100));
117+
int fetchSize = safeLimit + 1;
118+
119+
List<com.back.domain.post.post.entity.PostLike> rows;
120+
if (lastCreatedAt == null || lastId == null) {
121+
rows = myHistoryLikedPostRepository.findMyLikedPostsFirstPage(
122+
userId,
123+
com.back.domain.post.post.enums.PostLikeStatus.LIKE,
124+
com.back.domain.post.post.enums.PostStatus.DELETED,
125+
PageRequest.of(0, fetchSize)
126+
);
127+
} else {
128+
rows = myHistoryLikedPostRepository.findMyLikedPostsAfter(
129+
userId,
130+
com.back.domain.post.post.enums.PostLikeStatus.LIKE,
131+
com.back.domain.post.post.enums.PostStatus.DELETED,
132+
lastCreatedAt,
133+
lastId,
134+
PageRequest.of(0, fetchSize)
135+
);
136+
}
137+
138+
boolean hasNext = rows.size() > safeLimit;
139+
if (hasNext) rows = rows.subList(0, safeLimit);
140+
141+
List<MyHistoryLikedPostItemDto> items = new ArrayList<>();
142+
for (com.back.domain.post.post.entity.PostLike postLike : rows) items.add(MyHistoryLikedPostItemDto.from(postLike));
143+
144+
LocalDateTime nextCreatedAt = null;
145+
Long nextId = null;
146+
if (hasNext && !rows.isEmpty()) {
147+
com.back.domain.post.post.entity.PostLike last = rows.get(rows.size() - 1);
148+
nextCreatedAt = last.getCreatedAt();
149+
nextId = last.getId();
150+
}
151+
152+
return new MyHistoryLikedPostListDto(items, hasNext, nextCreatedAt, nextId);
153+
}
154+
155+
@Transactional(readOnly = true)
156+
public MyHistoryPostGoResponseDto getPostLinkFromMyLikedPost(Long userId, Long postId) {
157+
com.back.domain.post.post.entity.PostLike postLike = myHistoryLikedPostRepository.findByPostIdAndUserIdLike(
158+
postId,
159+
userId,
160+
com.back.domain.post.post.enums.PostLikeStatus.LIKE
161+
);
162+
if (postLike == null) {
163+
throw new ServiceException(404, "좋아요한 게시글을 찾을 수 없습니다.");
164+
}
165+
Post post = postLike.getPost();
166+
if (post.getStatus() == PostStatus.DELETED) {
167+
throw new ServiceException(410, "삭제된 게시글입니다.");
168+
}
169+
String apiUrl = "/api/posts/" + post.getId();
170+
return new MyHistoryPostGoResponseDto(post.getId(), apiUrl);
171+
}
111172
}

0 commit comments

Comments
 (0)