이번에 할 것은 정적이었던 쿼리를 동적을 바꿔 보려고 합니다.
일단 쿼리부터 보면
전부 동일한 쿼리이지만 마지막 where 절만 달랐고 JPQL로는 동적 쿼리 작성이 어렵기 때문에
쿼리를 3번을 작성하여야 했습니다.
그래서 쿼리를 동적으로 리팩토링을 하기로 했고 Querydsl을 사용해 봤습니다.
시작하기 앞서 강의에서 봤던 스프링 부트의 버젼은 2.x 버전이었고 3.x 이상부터는 설정이 좀 다르기 때문에 아래 블로그를 보고 참고했습니다.
https://ururuwave.tistory.com/148
프로젝트 환경설정 (SpringBoot 3.x 버전), Querydsl 설정
강의는 스프링부트 2.x 버전이라 3.x버전으로 세팅하는 법을 정리해보려 한다.강의 자료에 3.x 버전 설명이 있지만 중간 중간 설명이 달라서 환경설정하는데 예상보다 오래걸렸다;; 1. 프로젝트
ururuwave.tistory.com
Querydsl 설정을 마치고 Q클래서 까지 만들어 졌다면
spring data JPA와 Querydsl을 함께 사용하기 위해
인터페이스를 하나 만들어 주고
BoardRepositoryImpl 클래스에서 구현을 해줬습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
public class BoardRepositoryImpl implements BoardRepositoryCustom {
private final JPAQueryFactory qf;
private BoardRepositoryImpl(EntityManager em) {
qf = new JPAQueryFactory(em);
}
@Override
public PagedModel<CmnBoardListResponseDTO> search(String keyword, Pageable pageable, String searchType) {
QOeBoardImg oeBoardImgSub = new QOeBoardImg("OeBoardImgSub");
List<CmnBoardListResponseDTO> content = qf.select(Projections.constructor(
CmnBoardListResponseDTO.class,
oeBoard.boardPk,
oeBoard.title,
oeBoard.viewCnt,
oeBoard.likeCnt,
oeBoard.member.nickname,
JPAExpressions
.select(oeBoardImg.s3ImgAddress)
.from(oeBoardImg)
.where(oeBoardImg.boardImgPk.eq(
JPAExpressions
.select(oeBoardImgSub.boardImgPk.min())
.from(oeBoardImgSub)
.where(oeBoardImgSub.board.boardPk.eq(oeBoard.boardPk))))
))
.from(oeBoard)
.leftJoin(oeBoard.member, member)
.where(
nicknameEq(searchType,keyword),
titleOrContentEq(searchType,keyword)
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
Long total = qf.select(oeBoard.count())
.from(oeBoard)
.where(nicknameEq(searchType, keyword),
titleOrContentEq(searchType, keyword)).fetchOne();
return new PagedModel<>(new PageImpl<>(content, pageable, total == null ? 0L : total));
}
private Predicate titleOrContentEq(String searchType, String keyword) {
if(searchType.equals("title")){
return oeBoard.title.contains(keyword);
} else if (searchType.equals("titleAndContent")) {
return oeBoard.title.contains(keyword).or(oeBoard.content.contains(keyword));
}
return null;
}
private BooleanExpression nicknameEq(String searchType, String keyword) {
return searchType.equals("nickname") ? oeBoard.member.nickname.contains(keyword) : null;
}
}
|
cs |
위 코드는 앞서 봤던 3개의 정적 쿼리를 하나의 동적 쿼리로 리팩토링 된 모습입니다.
설명을 해보자면 쿼리는 실제 값을 가져오는 쿼리와 페이징을 위해 게시물 수를 나타내는 count쿼리 총 2번이 나갑니다.
count를 따로 뺀 이유는 실제 필요한 값을 가져오기 위해 조인하고 서브쿼리를 사용하는 쿼리랑 count쿼리가 같을 필요가 없기 때문에 따로 작성해 주었습니다.
또한 처음에 serch 메서드는 Page를 봔환 했으나
WARN 4209 --- [p-nio-80-exec-1] ration$PageModule$WarningLoggingModifier : Serializing PageImpl instances as-is is not supported, meaning that there is no guarantee about the stability of the resulting JSON structure!
For a stable JSON structure, please use Spring Data's PagedModel (globally via @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO))
or Spring HATEOAS and Spring Data's PagedResourcesAssembler as documented in https://docs.spring.io/spring-data/commons/reference/repositories/core-extensions.html#core.web.pageables.
위와 같은 경고 메시지가 나왔다 캡쳐를 따로 하지못하여서 다음 블로그에서 메시지를 가져왔습니다.
3.3 이상 스프링 부트의 컨트롤러에서 에서 Page 객체를 그대로 응답할 때 발생한 경고
경고 메시지 발견 3.3 이상의 스프링 부트를 사용하는 프로젝트에서 Page 객체를 컨트롤러에서 Json으로 변환하여 응답할 때 이전에는 볼 수 없었던 경고메시지가 보였습니다. > PageImpl 인스턴스를
velog.io
대충 요약하자면 Page 객체를 반환하는 건 엔티티를 그대로 반환하는 것과 다르지 Json 구조의 안정성을 보장 못 하니까 Page 대신 Spring Data에서 제공하는 PagedModel을 사용해야 한다.
정도로 이해했습니다.
그리고 혹시 Page 정보 외에 더 들어가야 할 것이 있다면 따로 DTO를 만드는 것도 방법이 될 수 있겠다 생각만 하고 넘어갔습니다.
마지막으로
일단 자바 코드로 쿼리를 작성하기 때문에 대부분의 오류는 컴파일 단계에서 잡아주고 where 절의 조건을 메서드 형식으로 빼서 보기 좋게 작성할 수 있었습니다.(쿼리를? 코드를?)
추가로 titleOrContentEq는 Predicate를 반환 하는데 Predicate는 and나 or같은 조건 조합 기능을
제공하지 않기 때문에 ( oeBoard.title.contains(keyword).or(oeBoard.content.contains(keyword))구문은 작동 하지만
titleOrContentEq.and()는 지원하지 않는다는 뜻 )
재사용성을 고려하여 BooleanExpression을 주로 쓰면 좋을 거 같다 라고 생각 했습니다.
'spring > 개발 - OEasy' 카테고리의 다른 글
[Spring][JPA] JPQL 최적화 해보기 (0) | 2025.03.23 |
---|---|
Spring - stomp를 사용하여 채팅과 투표기능 개발 (0) | 2024.12.11 |
Spring - 스케줄러와 기상청 API를 이용한 [오이지수] 개발 (1) | 2024.12.09 |