Skip to content
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

페이지네이션 처리 시 최대 다음 페이지 수를 5개로 제한 #902

Open
wants to merge 5 commits into
base: dev/be
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package codezap.global.pagination;

import java.util.List;

public record FixedPage<T> (List<T> contents, int nextPages) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package codezap.global.pagination;

import java.util.Objects;

import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.jpa.impl.JPAQueryFactory;

@Component
public class FixedPageCounter {

private static final int MAXIMUM_PAGE = 5;

public int countNextFixedPage(
JPAQueryFactory queryFactory,
EntityPathBase<?> entityPath,
Pageable pageable,
BooleanExpression... conditions
) {
int maximumElementsCount = pageable.getPageSize() * MAXIMUM_PAGE;
long nextFixedElementCounts = Objects.requireNonNull(queryFactory
.selectFrom(entityPath)
.where(conditions)
.offset(pageable.getOffset())
.limit(maximumElementsCount)
.fetch())
.size();

return (int) Math.ceil((double) nextFixedElementCounts / pageable.getPageSize());
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package codezap.likes.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import codezap.likes.domain.Likes;
import codezap.member.domain.Member;
Expand All @@ -17,11 +13,4 @@ public interface LikesJpaRepository extends JpaRepository<Likes, Long> {
boolean existsByMemberAndTemplate(Member member, Template template);

long countByTemplate(Template template);

@Query("""
SELECT l.template
FROM Likes l
WHERE l.member.id = :memberId AND (l.template.member.id = :memberId OR l.template.visibility = 'PUBLIC')
""")
Page<Template> findAllByMemberId(@Param(value = "memberId") Long memberId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import codezap.likes.domain.Likes;
Expand Down Expand Up @@ -37,8 +35,4 @@ public void deleteByMemberAndTemplate(Member member, Template template) {
public void deleteAllByTemplateIds(List<Long> templateIds) {
likesQueryDslRepository.deleteAllByTemplateIds(templateIds);
}

public Page<Template> findAllByMemberId(Long memberId, Pageable pageable) {
return likesJpaRepository.findAllByMemberId(memberId, pageable);
}
}
6 changes: 3 additions & 3 deletions backend/src/main/java/codezap/likes/service/LikesService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import codezap.global.pagination.FixedPage;
import codezap.likes.domain.Likes;
import codezap.likes.repository.LikesRepository;
import codezap.member.domain.Member;
Expand Down Expand Up @@ -36,8 +36,8 @@ public Boolean isLiked(Member member, Template template) {
return likesRepository.existsByMemberAndTemplate(member, template);
}

public Page<Template> findAllByMemberId(Long memberId, Pageable pageable) {
return likesRepository.findAllByMemberId(memberId, pageable);
public FixedPage<Template> findAllByMemberId(Long memberId, Pageable pageable) {
return templateRepository.findAllLikedByMemberId(memberId, pageable);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import io.swagger.v3.oas.annotations.media.Schema;

public record FindAllTemplatesResponse(
@Schema(description = "전체 페이지 개수", example = "1")
int totalPages,
@Schema(description = "총 템플릿 개수", example = "134")
long totalElements,
@Schema(description = "다음 페이지 개수, 최대 5개입니다.", example = "1")
int nextPages,
@Schema(description = "템플릿 목록")
List<FindAllTemplateItemResponse> templates
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package codezap.template.repository;

import static codezap.template.domain.QTemplate.template;

import java.util.List;
import java.util.Objects;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;

import codezap.global.pagination.FixedPage;
import codezap.global.pagination.FixedPageCounter;
import codezap.likes.domain.QLikes;
import codezap.template.domain.QTemplate;
import codezap.template.domain.Template;
import codezap.template.domain.Visibility;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,8 +22,9 @@ public class TemplateQueryDSLRepository {

private final JPAQueryFactory queryFactory;
private final TemplateSearchExpressionProvider expressionProvider;
private final FixedPageCounter fixedPageCounter;

public Page<Template> findTemplates(
public FixedPage<Template> findTemplates(
Long memberId,
String keyword,
Long categoryId,
Expand All @@ -33,8 +33,8 @@ public Page<Template> findTemplates(
Pageable pageable
) {
List<Template> content = getTemplates(memberId, keyword, categoryId, tagIds, visibility, pageable);
long count = count(memberId, keyword, categoryId, tagIds, visibility);
return new PageImpl<>(content, pageable, count);
int nextFixedPage = countNextFixedPage(pageable, memberId, keyword, categoryId, tagIds, visibility);
return new FixedPage<>(content, nextFixedPage);
}

private List<Template> getTemplates(
Expand All @@ -46,28 +46,30 @@ private List<Template> getTemplates(
Pageable pageable
) {
return queryFactory
.selectFrom(template)
.leftJoin(template.category).fetchJoin()
.leftJoin(template.member).fetchJoin()
.selectFrom(QTemplate.template)
.leftJoin(QTemplate.template.category).fetchJoin()
.leftJoin(QTemplate.template.member).fetchJoin()
.where(matchesKeyword(memberId, keyword, categoryId, tagIds, visibility))
.orderBy(TemplateOrderSpecifierUtils.getOrderSpecifier(pageable.getSort()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

private long count(
private int countNextFixedPage(
Pageable pageable,
Long memberId,
String keyword,
Long categoryId,
List<Long> tagIds,
Visibility visibility
) {
return Objects.requireNonNull(queryFactory
.select(template.count())
.from(template)
.where(matchesKeyword(memberId, keyword, categoryId, tagIds, visibility))
.fetchOne());
return fixedPageCounter.countNextFixedPage(
queryFactory,
QTemplate.template,
pageable,
matchesKeyword(memberId, keyword, categoryId, tagIds, visibility)
);
}

private BooleanExpression[] matchesKeyword(
Expand All @@ -85,5 +87,35 @@ private BooleanExpression[] matchesKeyword(
expressionProvider.matchesKeyword(keyword)
};
}

public FixedPage<Template> findAllLikedByMemberId(Long memberId, Pageable pageable) {
List<Template> content = queryFactory
.select(QLikes.likes.template)
.from(QLikes.likes)
.where(isLikedTemplateByMember(memberId))
.orderBy(TemplateOrderSpecifierUtils.getOrderSpecifier(pageable.getSort()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

return new FixedPage<>(content, countNextFixedPage(memberId, pageable));
}

private int countNextFixedPage(Long memberId, Pageable pageable) {
return fixedPageCounter.countNextFixedPage(
queryFactory,
QLikes.likes,
pageable,
isLikedTemplateByMember(memberId)
);
}

private static BooleanExpression isLikedTemplateByMember(Long memberId) {
BooleanExpression isLikedByMemberId = QLikes.likes.member.id.eq(memberId);
BooleanExpression isLikedTemplateByMemberId = QLikes.likes.template.member.id.eq(memberId);
BooleanExpression isTemplatePublic = QLikes.likes.template.visibility.eq(Visibility.PUBLIC);

return isLikedByMemberId.and(isLikedTemplateByMemberId.or(isTemplatePublic));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import codezap.global.exception.CodeZapException;
import codezap.global.exception.ErrorCode;
import codezap.global.pagination.FixedPage;
import codezap.template.domain.Template;
import codezap.template.domain.Visibility;
import lombok.RequiredArgsConstructor;
Expand All @@ -28,12 +28,16 @@ public List<Template> findByMemberId(Long id) {
return templateJpaRepository.findByMemberId(id);
}

public Page<Template> findAll(
public FixedPage<Template> findAll(
Long memberId, String keyword, Long categoryId, List<Long> tagIds, Visibility visibility, Pageable pageable
) {
return templateQueryDSLRepository.findTemplates(memberId, keyword, categoryId, tagIds, visibility, pageable);
}

public FixedPage<Template> findAllLikedByMemberId(Long memberId, Pageable pageable) {
return templateQueryDSLRepository.findAllLikedByMemberId(memberId, pageable);
}

public boolean existsByCategoryId(Long categoryId) {
return templateJpaRepository.existsByCategoryId(categoryId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import java.util.HashSet;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import codezap.category.domain.Category;
import codezap.global.exception.CodeZapException;
import codezap.global.exception.ErrorCode;
import codezap.global.pagination.FixedPage;
import codezap.member.domain.Member;
import codezap.template.domain.Template;
import codezap.template.domain.Visibility;
Expand Down Expand Up @@ -45,7 +45,7 @@ public List<Template> getByMemberId(Long memberId) {
return templateRepository.findByMemberId(memberId);
}

public Page<Template> findAllBy(
public FixedPage<Template> findAllBy(
Long memberId,
String keyword,
Long categoryId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import jakarta.annotation.Nullable;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -13,10 +12,10 @@
import codezap.category.service.CategoryService;
import codezap.global.exception.CodeZapException;
import codezap.global.exception.ErrorCode;
import codezap.global.pagination.FixedPage;
import codezap.likes.service.LikedChecker;
import codezap.likes.service.LikesService;
import codezap.member.domain.Member;
import codezap.member.service.MemberService;
import codezap.tag.domain.Tag;
import codezap.tag.service.TagService;
import codezap.template.domain.SourceCode;
Expand Down Expand Up @@ -45,7 +44,6 @@ public class TemplateApplicationService {
private final TagService tagService;
private final ThumbnailService thumbnailService;
private final LikesService likesService;
private final MemberService memberService;

@Transactional
public Long create(Member member, CreateTemplateRequest createTemplateRequest) {
Expand Down Expand Up @@ -94,7 +92,7 @@ public FindAllTemplatesResponse findAllBy(
List<Long> tagIds,
Pageable pageable
) {
Page<Template> templates = templateService.findAllBy(
FixedPage<Template> templates = templateService.findAllBy(
memberId, keyword, categoryId, tagIds, Visibility.PUBLIC, pageable
);
return makeAllTemplatesResponse(templates, (template) -> false);
Expand All @@ -108,7 +106,7 @@ public FindAllTemplatesResponse findAllBy(
Pageable pageable,
Member loginMember
) {
Page<Template> templates = templateService.findAllBy(
FixedPage<Template> templates = templateService.findAllBy(
memberId, keyword, categoryId, tagIds, getVisibilityLevel(memberId, loginMember), pageable
);
return makeAllTemplatesResponse(templates, (template -> likesService.isLiked(loginMember, template)));
Expand All @@ -123,18 +121,17 @@ private Visibility getVisibilityLevel(Long memberId, Member loginMember) {
}

public FindAllTemplatesResponse findAllByLiked(Long memberId, Pageable pageable) {
Page<Template> likeTemplate = likesService.findAllByMemberId(memberId, pageable);
FixedPage<Template> likeTemplate = likesService.findAllByMemberId(memberId, pageable);
return makeAllTemplatesResponse(likeTemplate, (template -> true));
}

private FindAllTemplatesResponse makeAllTemplatesResponse(Page<Template> page, LikedChecker likedChecker) {
List<Template> templates = page.getContent();
private FindAllTemplatesResponse makeAllTemplatesResponse(FixedPage<Template> page, LikedChecker likedChecker) {
List<Template> templates = page.contents();
List<FindAllTemplateItemResponse> findAllTemplateByResponse =
getFindAllTemplateItemResponses(templates, likedChecker);

return new FindAllTemplatesResponse(
page.getTotalPages(),
page.getTotalElements(),
page.nextPages(),
findAllTemplateByResponse);
}

Expand Down
Loading
Loading