ㅋㅋㅋ 고대 선배들이 남겨준 페이징 처리
사실 회사에서는 페이징 처리는 이미 구현이 되어있어서 고민을 해본 적이 없었다.
페이징 처리
jpa로 페이징 처리를 할때는 Page라는 객체를 쓰면 간단해진다.
그러나 이것은 단점을 가지고 있는데, count 쿼리를 사용하기때문에 총 개수가 많아지면 점점 느려진다. 왜냐면 전체 개수를 세야하기 때문이다.
그래서 그것의 대안으로 어떻게 하는가?
1) 더보기 방식, 아래를 스크롤하면 현재 위치의 index에서 다음 10개를 가져오는 방식
2) Page 쿼리를 수정해서 위에처럼 현재 index에서 10개를 가져오는 방식으로 수정
현재 나는 순수 jpa는 타자 칠게 많아서 눈으로 읽어주기만하고
queryDSL로 적용해보려고한다.
1) 전체 유저의 조회 + 페이징처리
2) 찾기 기능(키워드) + 페이징 처리
이렇게 2개의 api를 구현하고 싶어서 김영한님이 알려주신 QueryDSL을 적용했는데 아뿔싸
내가 만든 SearchDTO를 적용하자니 코드가 복잡해졌다. 수정 수정이 필요하다!!
더보기
SearchDTO 는 인터페이스 적용을 아직 하지 않음
package com.coopang.user.presentation.request;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SearchRequestDto {
private String keyword; // 회원 검색 키워드
private String sortBy; // 정렬 기준 (createdAt, updatedAt 등)
private Integer page; // 페이지 번호
private Integer size; // 페이지 크기
// 페이지 크기 유효성 검사를 수행하고, 기본값을 반환하는 메서드
// 페이지 크기를 10, 30, 50으로 제한
public int getValidatedSize() {
return (size == null) ? 10 : (size <= 10 ? 10 : (size <= 30 ? 30 : 50));
}
// 페이지 번호 기본값 설정 메서드
public int getValidatedPage() {
return (page != null && page >= 0) ? page : 0;
}
// 정렬 기준 기본값 설정 메서드
public String getValidatedSortBy() {
return (sortBy != null && !sortBy.isEmpty()) ? sortBy : "createdAt";
}
}
굴러가긴 하나 정리 안된 막써 QueryDSL
package com.coopang.user.infrastructure.repository;
import static com.coopang.user.domain.entity.user.QUserEntity.userEntity;
import com.coopang.user.application.enums.UserRoleEnum;
import com.coopang.user.domain.entity.user.UserEntity;
import com.coopang.user.presentation.request.UserSearchCondition;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Objects;
@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
private final JPAQueryFactory queryFactory;
public UserRepositoryCustomImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}
@Override
public Page<UserEntity> search(UserSearchCondition condition, Pageable pageable) {
List<UserEntity> users = queryFactory
.select(userEntity)
.from(userEntity)
.where(
usernameEq(condition.getUserName()),
emailEq(condition.getEmail()),
roleEq(condition.getUserRole())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(getOrderSpecifier(pageable))
.fetch();
long total = queryFactory
.select(userEntity.count())
.from(userEntity)
.where(
usernameEq(condition.getUserName()),
emailEq(condition.getEmail()),
roleEq(condition.getUserRole())
)
.fetchOne();
return new PageImpl<>(users, pageable, total);
}
private OrderSpecifier<?>[] getOrderSpecifier(Pageable pageable) {
if (pageable.getSort().isEmpty()) {
return new OrderSpecifier<?>[] {userEntity.createdAt.desc()}; // 기본 정렬 기준
}
// 정렬 조건을 직접 생성합니다.
OrderSpecifier<?>[] orderSpecifiers = pageable.getSort().stream()
.map(order -> {
if (order.getProperty().equals("createdAt")) {
return order.isAscending() ? userEntity.createdAt.asc() : userEntity.createdAt.desc();
}
if (order.getProperty().equals("updatedAt")) {
return order.isAscending() ? userEntity.updatedAt.asc() : userEntity.updatedAt.desc();
}
// 다른 정렬 기준 추가 가능
return null;
})
.filter(Objects::nonNull)
.toArray(OrderSpecifier[]::new);
// 정렬 조건이 없는 경우 기본 정렬 기준을 사용합니다.
return orderSpecifiers.length > 0 ? orderSpecifiers : new OrderSpecifier<?>[] {userEntity.createdAt.desc()};
}
private Predicate emailEq(String email) {
return StringUtils.hasText(email) ? userEntity.email.eq(email) : null;
}
private Predicate usernameEq(String userName) {
return StringUtils.hasText(userName) ? userEntity.username.eq(userName) : null;
}
private Predicate roleEq(String userRole) {
return StringUtils.hasText(userRole) ? userEntity.role.eq(UserRoleEnum.valueOf(userRole)) : null;
}
}
'Today I Learned' 카테고리의 다른 글
협업 과정에서의 문제 해결과 카프카 메시징 구조 개선 (0) | 2024.10.14 |
---|---|
@Component, @Configuration + @ConfigurationProperties (0) | 2024.10.02 |
DDD Layered Architecture의 application service와 domain service에 어떤 코드를 넣어야 하는 걸까? (0) | 2024.09.23 |
DDD Architecture (0) | 2024.09.14 |
grafana에 loki 추가 (0) | 2024.09.14 |