-
Notifications
You must be signed in to change notification settings - Fork 0
[feat] 내가 팔로잉하는 유저들 중, 최근 공개 피드 작성한 유저 정보 조회 api 개발 #199
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
Changes from all commits
91aa98a
90bef68
26eb2ca
c2fe1fb
e98f47b
5e5922c
b69d084
964f08c
5dc6fc3
bc773a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package konkuk.thip.user.adapter.in.web.response; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Schema(description = "전체 피드 조회 상단에서의 내 띱 목록 응답 DTO") | ||
| public record UserFollowingRecentWritersResponse( | ||
| @Schema(description = "내가 팔로잉하는 사람들 중, 최근에 공개 피드를 작성한 사람들") | ||
| List<RecentWriter> recentWriters | ||
| ) { | ||
| public record RecentWriter( | ||
| @Schema(description = "최근에 피드를 작성한 사람의 userId 값") | ||
| Long userId, | ||
|
|
||
| @Schema(description = "최근에 피드를 작성한 사람의 nickname 값") | ||
| String nickname, | ||
|
|
||
| @Schema(description = "최근에 피드를 작성한 사람의 profileImageUrl 값") | ||
| String profileImageUrl | ||
| ) {} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,11 +7,13 @@ | |
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||
| import konkuk.thip.comment.adapter.out.jpa.QCommentJpaEntity; | ||
| import konkuk.thip.common.entity.StatusType; | ||
| import konkuk.thip.feed.adapter.out.jpa.QFeedJpaEntity; | ||
| import konkuk.thip.post.adapter.out.jpa.QPostJpaEntity; | ||
| import konkuk.thip.post.adapter.out.jpa.QPostLikeJpaEntity; | ||
| import konkuk.thip.room.adapter.out.jpa.QRoomJpaEntity; | ||
| import konkuk.thip.room.adapter.out.jpa.QRoomParticipantJpaEntity; | ||
| import konkuk.thip.user.adapter.out.jpa.QAliasJpaEntity; | ||
| import konkuk.thip.user.adapter.out.jpa.QFollowingJpaEntity; | ||
| import konkuk.thip.user.adapter.out.jpa.QUserJpaEntity; | ||
| import konkuk.thip.user.application.port.out.dto.QReactionQueryDto; | ||
| import konkuk.thip.user.application.port.out.dto.QUserQueryDto; | ||
|
|
@@ -159,5 +161,36 @@ public List<ReactionQueryDto> findLikeAndCommentByUserId(Long userId, LocalDateT | |
| .toList(); | ||
| } | ||
|
|
||
| @Override | ||
| public List<UserQueryDto> findFeedWritersOfMyFollowingsOrderByCreatedAtDesc(Long userId, Integer size) { | ||
| QFollowingJpaEntity following = QFollowingJpaEntity.followingJpaEntity; | ||
| QUserJpaEntity writer = new QUserJpaEntity("writer"); | ||
| QFeedJpaEntity feed = QFeedJpaEntity.feedJpaEntity; | ||
| QAliasJpaEntity alias = QAliasJpaEntity.aliasJpaEntity; | ||
|
|
||
| return queryFactory | ||
| .select(new QUserQueryDto( | ||
| writer.userId, | ||
| writer.nickname, | ||
| alias.imageUrl | ||
| )) | ||
| .from(following) | ||
| .join(following.followingUserJpaEntity, writer) // writer : 나에게 팔로잉 당하는 사람들 | ||
| .join(feed).on(feed.userJpaEntity.eq(writer)) | ||
| .join(writer.aliasForUserJpaEntity, alias) | ||
| .where( | ||
| following.userJpaEntity.userId.eq(userId) // 내가 팔로잉 하는 사람 | ||
| .and(writer.status.eq(StatusType.ACTIVE)) // 그 중 아직 회원인 사람 | ||
| .and(feed.status.eq(StatusType.ACTIVE)) // 그 중 삭제 X & 공개피드를 작성한 사람 | ||
| .and(feed.isPublic.isTrue()) | ||
| ) | ||
| .groupBy( // 그룹핑 | ||
| writer.userId, | ||
| writer.nickname, | ||
| alias.imageUrl | ||
| ) | ||
|
Comment on lines
+181
to
+191
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굿굿 꼼꼼하네욥 👍🏻 |
||
| .orderBy(feed.createdAt.max().desc()) // 피드 작성 시각 중 최대값 == 가장 최근에 작성한 피드 | ||
| .limit(size) // 무한 스크롤 X | ||
| .fetch(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| package konkuk.thip.user.application.mapper; | ||
|
|
||
| import konkuk.thip.user.adapter.in.web.response.UserFollowingRecentWritersResponse; | ||
| import konkuk.thip.user.adapter.in.web.response.UserSearchResponse; | ||
| import konkuk.thip.user.application.port.out.dto.UserQueryDto; | ||
| import org.mapstruct.Mapper; | ||
|
|
@@ -12,6 +13,12 @@ public interface UserQueryMapper { | |
| // List<QueryDto> -> List<DTO> | ||
| List<UserSearchResponse.UserDto> toUserDtoList(List<UserQueryDto> userQueryDtos); | ||
|
|
||
|
|
||
|
|
||
| } | ||
| // 단건 매핑: UserQueryDto -> RecentWriter | ||
| UserFollowingRecentWritersResponse.RecentWriter toRecentWriter(UserQueryDto dto); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 이거는 미리 만들어두신건가여??
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 맞습니다! map struct 가 사용할 매핑 메서드를 미리 인터페이스에 정의해놓았습니다 |
||
| // 리스트 매핑: List<UserQueryDto> -> List<RecentWriter> | ||
| List<UserFollowingRecentWritersResponse.RecentWriter> toRecentWriterList(List<UserQueryDto> dtos); | ||
| // 래핑: List<UserQueryDto> -> UserFollowingRecentWritersResponse | ||
| default UserFollowingRecentWritersResponse toRecentWriterResponses(List<UserQueryDto> dtos) { | ||
| return new UserFollowingRecentWritersResponse(toRecentWriterList(dtos)); | ||
| } | ||
|
Comment on lines
+19
to
+23
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오호 dto 생성 책임도 mapper가 갖도록 했네요! 좋습니다! 서비스 로직이 가벼워질 것 같아요 |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package konkuk.thip.user.application.port.in; | ||
|
|
||
| import konkuk.thip.user.adapter.in.web.response.UserFollowingRecentWritersResponse; | ||
|
|
||
| public interface UserShowFollowingRecentWritersUseCase { | ||
|
|
||
| UserFollowingRecentWritersResponse showMyFollowingRecentWriters(Long userId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,9 +18,18 @@ public record UserQueryDto(Long userId, | |
| Assert.notNull(userId, "userId must not be null"); | ||
| Assert.notNull(nickname, "nickname must not be null"); | ||
| Assert.notNull(profileImageUrl, "profileImageUrl must not be null"); | ||
| Assert.notNull(aliasName, "aliasName must not be null"); | ||
| Assert.notNull(aliasColor, "aliasColor must not be null"); | ||
| // Assert.notNull(aliasName, "aliasName must not be null"); | ||
| // Assert.notNull(aliasColor, "aliasColor must not be null"); | ||
| // Assert.notNull(followerCount, "followerCount must not be null"); // 내 팔로잉 목록 조회에서는 필요 x | ||
| Assert.notNull(createdAt, "createdAt must not be null"); | ||
| // Assert.notNull(createdAt, "createdAt must not be null"); | ||
|
Comment on lines
+21
to
+24
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏻 |
||
| } | ||
| } | ||
|
|
||
| @QueryProjection | ||
| public UserQueryDto( | ||
| Long userId, | ||
| String nickname, | ||
| String profileImageUrl | ||
| ) { | ||
| this(userId, nickname, profileImageUrl, null, null, null, null); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package konkuk.thip.user.application.service; | ||
|
|
||
| import konkuk.thip.user.adapter.in.web.response.UserFollowingRecentWritersResponse; | ||
| import konkuk.thip.user.application.mapper.UserQueryMapper; | ||
| import konkuk.thip.user.application.port.in.UserShowFollowingRecentWritersUseCase; | ||
| import konkuk.thip.user.application.port.out.UserQueryPort; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class UserShowFollowingRecentWritersService implements UserShowFollowingRecentWritersUseCase { | ||
|
|
||
| private static final int SIZE = 10; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p2: 페이징 처리 필요하지않으면 사용하지 않으니 빼셔도 좋을듯합니다!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 아마 기본 사이즈라도 유지보수하기 쉽게 서비스 로직에서 LIMIT도 넘겨주기로 통일했던 것 같습니다! |
||
| private final UserQueryPort userQueryPort; | ||
| private final UserQueryMapper userQueryMapper; | ||
|
|
||
| @Override | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p2: 트랜잭션 어노테이션 누락된것같습니다!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 엇 서비스에서 도메인 조회가 없어서 트랜잭션을 추가하진 않았는데 팀 컨벤션 차원으로 추가해보겟습니다! |
||
| @Transactional(readOnly = true) | ||
| public UserFollowingRecentWritersResponse showMyFollowingRecentWriters(Long userId) { | ||
| return userQueryMapper.toRecentWriterResponses(userQueryPort.findRecentFeedWritersOfMyFollowings(userId, SIZE)); | ||
| } | ||
| } | ||
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.
와우 친절띠니 LGTM