우리 서비스인 COOKLE 에도 동적쿼리를 사용하는 경우가 있다 → 바로 “게시글 조회” 기능!
WHERE tag = ${tag}WHERE dateLoe ≥ ${dateLoe}WHERE dateGoe ≤ ${dateGoe}WHERE tag = ${tag} AND dateLoe ≥ ${dateLoe} AND dateGoe ≤ ${dateGoe}ORDERBY ${sortTarget}@Getter
public static class Summary {
/* 검색조건 */
private String tag;
private Optional<LocalDateTime> dateLoe = Optional.empty();
private Optional<LocalDateTime> dateGoe = Optional.empty();
/* 정렬기준 */
private SortConditions sortTarget;
public Summary(
String tag,
String dateLoe,
String dateGoe,
String sortTarget) {
this.tag = tag;
if (!dateLoe.isBlank()) {
this.dateLoe = Optional.of(LocalDate.parse(dateLoe, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay());
}
if (!dateGoe.isBlank()) {
this.dateGoe = Optional.of(LocalDate.parse(dateGoe, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay());
}
this.sortTarget = SortConditions.valueOf(sortTarget);
}
}
해당 쿼리를 작성하기 위해서는 일단 spring-data-jpa 환경이라면, 메서드 쿼리 방식만으로는 불가능하다.
따라서 jpql을 작성해주기 시작해야한다.. → 이런 방식으로 동적쿼리를 작성하다가는.. 아마도 쿼리가 복잡해질 수록 오타 찾느라 아주 정신이 없을 것으로 예상된다!!..!!
이런 경우에 querydsl을 통해 한번에 아주 편리하게 동적쿼리를 작성할 수 있다😃
where()에 null이 들어오면 무시한다.where()에 , 을 and 조건으로 사용한다.BooleanExpression에서 null을 반환하든 조건을 반환하든 where 조건절을 통해 잘 걸러진 쿼리가 완성되는 것이다.
BooleanExpression을 반환하는 메서드를 통해 조건을 확인해서 조건이 있다면 해당 조건을, 없다면 null을 반환한다.where()에서 null이면 무시하고, 조건이 존재하면 필터링해준다.@RequiredArgsConstructor
public class BoardRepositoryCustomImpl implements BoardRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public List<BoardResponse.Summary> searchBoards(BoardRequest.Summary request) {
return queryFactory
.select(Projections.constructor(BoardResponse.Summary.class,
board.id,
users.nickname,
board.createdAt,
ExpressionUtils.as(
JPAExpressions
.select(boardImage.url).from(boardImage)
.where(
boardImage.board.id.eq(board.id),
boardImage.imageType.eq(ImageType.THUMBNAIL),
boardImage.deletedAt.isNull()), "url"
),
board.likeCount,
board.replyCount
))
.from(board)
.join(board.users, users)
.where(
searchTag(request),
dateLoe(request),
dateGoe(request),
board.deletedAt.isNull()
)
.orderBy(sort(request))
.distinct().fetch();
}
private BooleanExpression searchTag(BoardRequest.Summary request) {
if (StringUtil.isNullOrEmpty(request.getTag())) {
return null;
}
return board.tag.like("%" + request.getTag() + "%");
}
private BooleanExpression dateLoe(BoardRequest.Summary request) {
if (request.getDateLoe().isEmpty()) {
return null;
}
return board.createdAt.after(request.getDateLoe().get());
}
private BooleanExpression dateGoe(BoardRequest.Summary request) {
if (request.getDateGoe().isEmpty()) {
return null;
}
return board.createdAt.before(request.getDateGoe().get());
}
private OrderSpecifier<?> sort(BoardRequest.Summary request) {
if (request.getSortTarget().equals(SortConditions.CREATED_AT_DESC)) {
return board.createdAt.desc();
} else if (request.getSortTarget().equals(SortConditions.CREATED_AT_ASC)) {
return board.createdAt.asc();
} else if (request.getSortTarget().equals(SortConditions.LIKE_COUNT_DESC)) {
return board.likeCount.desc();
} else {
return board.replyCount.desc();
}
}
}
COOKLE 서비스에서는 dto를 통해 검색조건을 받아와 쿼리를 동적으로 작성한다.null이 아니라 “”(빈 문자열)로 넘어오는 경우가 많기 때문이다..!