반응형
querydsl을 이용하여 검색 조건을 이용한 동적 쿼리를 짜봤습니다.
조건의 적용은 아래와 같습니다.
1. 페이지 번호와 페이지 당 개수를 지정하여 페이징을 할 수 있다.
2. 각 필드명으로 정렬을 적용할 수 있다.
3. 크게 세 분류의 옵션이 있으며, 각 옵션의 항목들은 중복 선택할 수 있다.
4. 첫 번째 옵션의 한 항목을 체크하면, 날짜 조건을 추가할 수 있다.
1번과 2번은 QuerydslRepositorySupport를 상속하여 applyPagination으로 쉽게 적용할 수 있었습니다.
3번과 4번은,
(체크된 옵션 1 or(
날짜 조건 항목 체크되면 start <= 입력일 <= end
)) and (체크된 옵션 2 or)
and (체크된 옵션 3 or)
와 같은 형태로 작성하였습니다.
public class TicketRepositoryImpl extends QuerydslRepositorySupport implements CustomTicketRepository {
private JPAQueryFactory queryFactory;
public TicketRepositoryImpl(JPAQueryFactory queryFactory) {
super(Ticket.class);
this.queryFactory = queryFactory;
}
@Override
public Page<TicketSimpleDto> findAllTicketWithConditions(TicketSearchConditionDto conditionDto, Pageable pageable) {
JPAQuery<TicketSimpleDto> query = queryFactory
.select(Projections.constructor(TicketSimpleDto.class,
ticket.id, ticket.title, ticket.price, ticket.view, ticket.address,
ticket.startDateTime, ticket.endDateTime, ticket.termType, ticket.ticketStatus,
ticket.placeType, user.nickname, ticket.createdAt
)).from(ticket)
.leftJoin(ticket.writer, user)
.where(ticketSearchPredicate(conditionDto));
// count query 분리. leftJoin이므로 조인 미적용
long count = queryFactory.selectFrom(ticket).where(ticketSearchPredicate(conditionDto)).fetchCount();
List<TicketSimpleDto> result = getQuerydsl().applyPagination(pageable,
query).fetch(); // applyPagination으로 pageable에 지정된 페이징 조건 적용
return new PageImpl<>(result, pageable, count); // Page로 반환
}
// where 절에 적용할 predicate
private BooleanBuilder ticketSearchPredicate(TicketSearchConditionDto conditionDto) {
return new BooleanBuilder()
.and(termTypeOrCondition(conditionDto.getTermTypes(), conditionDto.getDateTime())) // 옵션 1
.and(placeTypeOrCondition(conditionDto.getPlaceTypes())) // 옵션 2
.and(ticketStatusOrCondition(conditionDto.getTicketStatuses())); // 옵션 3
}
private BooleanBuilder dateTimeCondition(LocalDateTime dateTime) {
return new BooleanBuilder().and(dateTimeLoe(dateTime)).and(dateTimeGoe(dateTime));
}
private BooleanExpression dateTimeLoe(LocalDateTime dateTime) {
return dateTime != null ? ticket.startDateTime.loe(dateTime) : null;
}
private BooleanExpression dateTimeGoe(LocalDateTime dateTime) {
return dateTime != null ? ticket.endDateTime.goe(dateTime) : null;
}
private BooleanBuilder termTypeOrCondition(List<TermType> termTypes, LocalDateTime dateTime) {
BooleanBuilder builder = new BooleanBuilder();
termTypes.stream().forEach(t -> builder.or(ticket.termType.eq(t))); // 체크된 항목 or로 묶어줌
// TermType.INPUT이 체크되어 있으면 직접 입력한 날짜 검색 조건도 추가
return termTypes.contains(TermType.INPUT) ? builder.or(dateTimeCondition(dateTime)) : builder;
}
private BooleanBuilder placeTypeOrCondition(List<PlaceType> placeTypes) {
BooleanBuilder builder = new BooleanBuilder();
placeTypes.stream().forEach(p -> builder.or(ticket.placeType.eq(p))); // 체크된 항목 or
return builder;
}
private BooleanBuilder ticketStatusOrCondition(List<TicketStatus> ticketStatuses) {
BooleanBuilder builder = new BooleanBuilder();
ticketStatuses.stream().forEach(t -> builder.or(ticket.ticketStatus.eq(t))); // 체크된 항목 or
return builder;
}
}
오류가 있으면 지적부탁드립니다.
반응형
'Spring' 카테고리의 다른 글
스프링부트 웹소켓 stomp를 이용한 실시간 알림 구현 (0) | 2021.11.09 |
---|---|
스프링부트 Redis로 캐시 적용하기 (0) | 2021.11.09 |
스프링부트 JPA 무한스크롤 구현 (0) | 2021.11.09 |
스프링부트 JPA querydsl 대댓글(계층형 댓글) 기능 구현 (5) | 2021.11.09 |
@RequestMapping 기본 사용법 (0) | 2021.11.09 |