QueryDsl 로 검색 기능 추가하기

최민수·2023년 3월 30일
0

[개발] Java Spring

목록 보기
13/18

QA 게시판 프로젝트 진행 중에, 검색 기능을 추가하고 싶었다.
질문의 제목, 내용 그리고 작성자 중에 검색한 keyword가 포함되어 있으면 해당되는 질문 글들을 찾아주는 기능이다.

처음에는, 간단한 쿼리 작업이기 때문에 JPA가 제공하는 Specification 인터페이스를 사용할까 싶었다. 하지만 나중에는 복잡한 쿼리도 다뤄야 할 때가 생길거고, 또 성능 최적화를 위해 나중에 배우고 싶었던 QueryDsl 을 사용하기로 했다.


Gradle 설정 방법

queryDsl 설정에는 여러가지 방법이 존재하는 것처럼 보였다.
검색하고 찾아본 결과, queryDsl plugin을 이용하는 방법도 있었고 또 dependencies에 추가할 implementation, annotationProcessor 를 설정하는 방법도 있었다.

하지만 plugin의 경우에는 2018년 7월 이후로 업데이트가 안 된 프로젝트라서 사용하기 좀 찝찝했고, gradle 버전은 고도화 되는데 이 변화에 맞추어 업데이트 되지 못해 생기는 오류들이 생길까 걱정됐다. 따라서 후자의 방법을 택했다.

설정은 간단했다.

dependencies {
	implementation 'com.querydsl:querydsl-core'
	implementation 'com.querydsl:querydsl-jpa'
    
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
	annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
	annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
}

궁합이 잘 맞는 버전은 스프링이 알아서 가지고 오도록, 이렇게만 명시해 주면 된다.
또한 QueryDsl 설정을 하기 위해 QueryDslConfig java 파일을 하나 생성해준다.

@Configuration
public class QueryDslConfig {

    @PersistenceContext
    public EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(em);
    }
}

이것이 끝이었다. 이제 domain @Entity 로 선언된 객체들은 Q가 붙은 클래스 파일들이 build 폴더 안에 생길 것이다. 그러면 Repository에서 사용할 QAnswer, QUser 등을 임포트해서 그대로 사용하면 된다.


Gradle 설정에서 마주한 문제

위 설정과 같이 쉽게 끝나면 좋았겠지만.. 항상 개발은 한 번에 잘 되는 경우는 드문 것 같다. 하지만 또 생긴 문제를 이렇게 해결하고 Trouble-shooting 글을 작성하는 것도 재밌는 일이긴 하다.

gradle 파일을 위와 같이 추가해주고 나서 QuerydslConfig 파일을 작성했더니, JPAQueryFactory의 인자에 들어갈 Entitymanager 가 타입이 맞지 않는다는 compileError 가 발생했다.

package com.qa.board.config;


import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.PersistenceContext;

@Configuration
public class QueryDslConfig {

    @PersistenceContext
    public EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(em); // Error!
    }
}

IDE가 발생시킨 이유를 읽어보니 jakarta에서 임포트된 EntityManager를 인수를 받지 않는다고 한다. 그럼 어떤 걸 인수로 받아야 하는지 보니 javax에서 임포트 해야 한다고 한다.

스프링 부트 버전이 3.xx 로 업그레이드 되면서 javax -> jakarta 라이브러리로 이름이 변했다고 알고 있었는데, 이렇게 dependency 까지 신경써야 할 줄은 몰랐었다.

그래서 시키는 대로 javax 를 임포트해 넣어주었더니, 이제는 아까 gradle 파일에 넣은 implementation, annotationProcessor 에서 문제가 발생해 build 가 진행되질 않았다. 아무래도 jakarta 를 사용하는 라이브러리와 javax 를 사용하는 라이브러리 간의 충돌이 있는 것처럼 보였다.


해결 방법

해결법을 오랜 시간동안 찾아 해맸다. 그 결과, 크게 두 가지 정도 시도해 볼 만한 방법이 있었다.

첫번째 방법은 build 시, jakarta와 javax 간의 충돌이 일어나지 않는 라이브러리 버전을 찾아 명시해 주는 것이다. 지금은 따로 버전을 명시해주지 않아 스프링이 최적의 라이브러리 궁합을 찾아 가져오는 방법이었다면, 직접 명시해주는 방법인 것이다.

예를 들면,

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'

5.0.0 과 같이 라이브러리의 버전을 직접 써주는 방법이다.

두번째 방법은 javax, jakarta 두 개의 라이브러리를 모두 컴파일할 수 있도록 dependencies 에 모두 추가하는 방법이다.

예를 들면,

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
implementation 'jakarta.persistence:jakarta.persistence-api'
implementation 'javax.persistence:javax.persistence-api:2.2'

이런 식으로 javax, jakarta 모두에게 관련한 depedency를 추가해주었다.

그 결과, gradle 도 빌드가 잘 진행되었고 QuerydslConfig 파일도 제대로 컴파일 되었다.


해결은 했는데 그래서...

그래서 도대체 jakartajavax는 뭐가 다른건가?

ChatGPT 가 자세하게 설명해준다.

요약하자면,

  • 둘 다 Java EE 기술의 API를 제공해주는 자바 패키지이다.
  • 처음에는, Java EE 기술은 Java Community Process(JCP) 에서 javax 라는 패키지 네임스페이스로 관리되어 왔다.
  • 2017년에 Oracle이 권한을 Eclipse Foundation으로 넘기면서 jakarta 라는 새로운 패키지 네임스페이스로 바꾸어 transfer 과정이 진행됐다.
  • 따라서, rebranding 또는 Java EE 기술을 이어받았다 고 이해할 수 있겠다.
  • 이름은 다르지만, 제공하는 API와 기술은 아주 비슷하고 클래스와 인터페이스 이름만 바뀌었다고 봐도 무방하다.
  • 따라서 Java EE 로부터 Jakarta EE 로 이주하려면 패키지 이름dependency 만 업데이트 해주면 된다.

그렇다면 이번에 생긴 문제는 두 패키지 간의 QueryDsl 라이브러리에 대한 dependency 를 맞춰줘야 했던 문제라고 볼 수 있겠다.

QueryDsl의 설정이 그렇게 까다롭지 않다고 알고 있었어서 그런지, 이번 문제는 조금 당황스러웠다.

앞으로 QueryDsl을 스프링 버전 3.xx 로 사용할 일이 많을 것 같으니 해결 방법을 글로 남겨 둔다.


참고 사이트: https://wikidocs.net/162814
https://stackoverflow.com/questions/74756871/spring-boot-3-with-querydsl

profile
CS, 개발 공부기록 🌱

0개의 댓글