-
Notifications
You must be signed in to change notification settings - Fork 0
마이 페이지 기능 추가 #30
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
마이 페이지 기능 추가 #30
Changes from 18 commits
d45dfb0
41393ec
2e67b7a
1845269
195d3f5
239fc75
b71c57b
d1cde30
52d6b8a
4e2ca6e
2579995
3d1e845
744e7ca
ca39cfe
666b993
2bb5977
a8084a4
88de81d
f7c45bf
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,20 @@ | ||
| package com.example.log4u.common.util; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.data.domain.Slice; | ||
| import org.springframework.data.domain.SliceImpl; | ||
|
|
||
| public class PageableUtil { | ||
| public static <T> Slice<T> checkAndCreateSlice(List<T> content, Pageable pageable) { | ||
| boolean hasNext = content.size() > pageable.getPageSize(); | ||
|
|
||
| // 다음 페이지가 있으면 마지막 항목 제거 | ||
| if (hasNext) { | ||
| content.remove(content.size() - 1); // removeLast() 대신 인덱스로 처리 | ||
| } | ||
|
|
||
| return new SliceImpl<>(content, pageable, hasNext); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -217,4 +217,44 @@ public void checkDiaryExists(Long diaryId) { | |
| throw new NotFoundDiaryException(); | ||
| } | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public PageResponse<DiaryResponseDto> getMyDiariesByCursor(Long userId, VisibilityType visibilityType, | ||
| Long cursorId, int size) { | ||
| List<VisibilityType> visibilities = | ||
|
Collaborator
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. 사용자 흐름에서 VisibilityType이 null로 들어오는 경우가 있을까요? 3개의 타입에 대해서 전부 일일이 찾는 비용이 성능을 많이 잡아먹지 않을까?라는 생각과, 아예 Type을 지정해서 받는게 특정 Type만 찾는다는 점에서 성능에 좀 더 유리하지 않나? 라는 생각이 들었던 것 같습니다 |
||
| visibilityType == null ? List.of(VisibilityType.PUBLIC, VisibilityType.PRIVATE, VisibilityType.FOLLOWER) : | ||
| List.of(visibilityType); | ||
|
|
||
| Slice<Diary> diaries = diaryRepository.findByUserIdAndVisibilityInAndCursorId( | ||
| userId, | ||
| visibilities, | ||
| cursorId != null ? cursorId : Long.MAX_VALUE, | ||
| PageRequest.of(0, size) | ||
| ); | ||
|
|
||
| Slice<DiaryResponseDto> dtoSlice = mapToDtoSlice(diaries); | ||
|
|
||
| Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null; | ||
|
|
||
| return PageResponse.of(dtoSlice, nextCursor); | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| public PageResponse<DiaryResponseDto> getLikeDiariesByCursor(Long userId, Long targetUserId, Long cursorId, | ||
| int size) { | ||
| List<VisibilityType> visibilities = determineAccessibleVisibilities(userId, targetUserId); | ||
|
|
||
| Slice<Diary> diaries = diaryRepository.getLikeDiarySliceByUserId( | ||
| targetUserId, | ||
| visibilities, | ||
| cursorId != null ? cursorId : Long.MAX_VALUE, | ||
| PageRequest.of(0, size) | ||
| ); | ||
|
|
||
| Slice<DiaryResponseDto> dtoSlice = mapToDtoSlice(diaries); | ||
|
|
||
| Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null; | ||
|
|
||
| return PageResponse.of(dtoSlice, nextCursor); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package com.example.log4u.domain.follow.repository; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.data.domain.Slice; | ||
| import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| import com.example.log4u.common.util.PageableUtil; | ||
| import com.example.log4u.domain.follow.entitiy.Follow; | ||
| import com.example.log4u.domain.follow.entitiy.QFollow; | ||
| import com.example.log4u.domain.user.dto.UserThumbnailResponseDto; | ||
| import com.example.log4u.domain.user.entity.QUser; | ||
| import com.querydsl.core.BooleanBuilder; | ||
| import com.querydsl.core.types.Projections; | ||
| import com.querydsl.core.types.dsl.NumberPath; | ||
|
|
||
| @Repository | ||
| public class FollowQuerydsl extends QuerydslRepositorySupport { | ||
| private final QFollow follow = QFollow.follow; | ||
| private final QUser user = QUser.user; | ||
|
|
||
| public FollowQuerydsl() { | ||
| super(Follow.class); | ||
| } | ||
|
|
||
| private NumberPath<Long> getNumberPath(boolean isFollowerQuery) { | ||
| return isFollowerQuery ? follow.followerId : follow.followingId; | ||
| } | ||
|
|
||
| private BooleanBuilder getBooleanBuilder(boolean isFollowerQuery, Long userId, Long cursorId) { | ||
| BooleanBuilder builder = new BooleanBuilder(); | ||
| builder.and(getNumberPath(isFollowerQuery).eq(userId)); | ||
|
|
||
| if (cursorId != null) { | ||
| builder.and(follow.id.lt(cursorId)); | ||
| } | ||
|
|
||
| return builder; | ||
| } | ||
|
|
||
| private List<UserThumbnailResponseDto> getContent(boolean isFollowerQuery, Long userId, Long cursorId) { | ||
| BooleanBuilder builder = getBooleanBuilder(isFollowerQuery, userId, cursorId); | ||
|
|
||
| return from(follow) | ||
| .select(Projections.constructor(UserThumbnailResponseDto.class, | ||
| getNumberPath(!isFollowerQuery), | ||
| user.nickname, | ||
| user.nickname)) | ||
| .where(builder) | ||
| .distinct() | ||
| .fetch(); | ||
| } | ||
|
|
||
| //내 팔로워 아이디 슬라이스 | ||
| public Slice<UserThumbnailResponseDto> getFollowerSliceByUserId(Long userId, Long cursorId, Pageable pageable) { | ||
| boolean isFollowerQuery = true; | ||
| List<UserThumbnailResponseDto> content = getContent(isFollowerQuery, userId, cursorId); | ||
| return PageableUtil.checkAndCreateSlice(content, pageable); | ||
|
Collaborator
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. 해당 함수안에 있는 로직을 저는 로직단에서 일일이 작성을 했었는데 Util클래스로 빼는게 가독성, 재사용성면에서 훨씬 좋은 것 같네요. 배워갑니다 |
||
| } | ||
|
|
||
| // 내가 팔로잉하는 아이디 슬라이스 | ||
| public Slice<UserThumbnailResponseDto> getFollowingSliceByUserId(Long userId, Long cursorId, Pageable pageable) { | ||
| boolean isFollowerQuery = false; | ||
| List<UserThumbnailResponseDto> content = getContent(isFollowerQuery, userId, cursorId); | ||
| return PageableUtil.checkAndCreateSlice(content, pageable); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.example.log4u.domain.subscription; | ||
|
|
||
| public enum PaymentProvider { | ||
| TOSS, | ||
| KAKAO, | ||
| NAVER | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.example.log4u.domain.subscription; | ||
|
|
||
| public enum PaymentStatus { | ||
| SUCCESS, // 결제 완료 | ||
| FAILED, // 결제 실패 | ||
| REFUNDED // 환불 완료 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.example.log4u.domain.subscription.dto; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| import com.example.log4u.domain.subscription.PaymentProvider; | ||
|
|
||
| import jakarta.annotation.Nullable; | ||
| import lombok.Builder; | ||
|
|
||
| @Builder | ||
| public record SubscriptionResponseDto( | ||
| boolean isSubscriptionActive, | ||
|
|
||
| @Nullable | ||
| PaymentProvider paymentProvider, | ||
|
|
||
| @Nullable | ||
| LocalDateTime startDate | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.example.log4u.domain.subscription.entity; | ||
|
|
||
| import com.example.log4u.common.entity.BaseEntity; | ||
| import com.example.log4u.domain.subscription.PaymentProvider; | ||
| import com.example.log4u.domain.subscription.PaymentStatus; | ||
|
|
||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.EnumType; | ||
| import jakarta.persistence.Enumerated; | ||
| import jakarta.persistence.GeneratedValue; | ||
| import jakarta.persistence.GenerationType; | ||
| import jakarta.persistence.Id; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import lombok.experimental.SuperBuilder; | ||
|
|
||
| @SuperBuilder | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @AllArgsConstructor(access = AccessLevel.PACKAGE) | ||
|
|
||
| @Entity | ||
| public class Subscription extends BaseEntity { | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| @Column(nullable = false) | ||
| private Long userId; | ||
|
|
||
| @Column(nullable = false) | ||
| @Enumerated(EnumType.STRING) | ||
| private PaymentProvider paymentProvider; | ||
|
|
||
| @Column(nullable = false) | ||
| private Long amount; | ||
|
|
||
| @Column(nullable = false, unique = true) | ||
| private String paymentKey; | ||
|
|
||
| @Column(nullable = false) | ||
| @Enumerated(EnumType.STRING) | ||
| private PaymentStatus paymentStatus; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.example.log4u.domain.subscription.repository; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import java.util.Optional; | ||
|
|
||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import com.example.log4u.domain.subscription.PaymentStatus; | ||
| import com.example.log4u.domain.subscription.entity.Subscription; | ||
|
|
||
| public interface SubscriptionRepository extends JpaRepository<Subscription, Long> { | ||
| Optional<Subscription> findByUserIdAndCreatedAtBeforeAndPaymentStatusOrderByCreatedAtDesc(Long userId, | ||
| LocalDateTime now, | ||
| PaymentStatus paymentStatus); | ||
| } | ||
|
|
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.
코드 일관성을 위해 서비스 층에서는 get~~ Repository층에서는 find~~ 메서드명을 이런식으로 맞추자라는 의견이 있었던 것 같은데, 혹시 맞을까요?
맞다면 메서드명 통일 시키는 것은 어떻게 생각하시나요?