프로젝트/기록

[Spring] spring boot 3.x 에서 Querydsl 사용하기

공부하샘의 샘 2023. 3. 26. 00:23
 

 

1. 개요

Spring Boot 3.x에서 Querydsl을 사용하기 위한 세팅과 예제를 알아보겠습니다.

 

 

1.1. 개발 환경

IntelliJ IDEA Communication 2022.03.02

Java 17

Gradle 7.6.1

Spring Boot 3.0.4

 

 

 

2. 본론

2.1. 기본 환경 설정

 

2.1.1. build.gradle

// [number] Querydsl

// *********************

로 감싸져 있는 부분을 build.gradle에 추가하시면 됩니다.

 

이때 주의할 부분이 spring boot 3.x 부터는 특히나 jakarta를 명시해줘야 합니다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.4'
    id 'io.spring.dependency-management' version '1.1.0'
    // [1] Querydsl
    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'   
    // ************
}

group = 'net'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

// [2] Querydsl
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}
// ************

repositories {
    mavenCentral()
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.imgscalr:imgscalr-lib:4.2'

    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    // [3] Querydsl
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
    // QFile 생성 및 가져오기
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    // ************
}
test {
    useJUnitPlatform()
}

// [4] Querydsl
def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}
configurations {
    querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}
// ************

 

 

2.2. Test 환경 만들기

2.2.1. TestQueryDslConfig.java

src/test/java/net/<project name>/config/에 파일을 추가해주세요.

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;

@TestConfiguration
public class TestQueryDslConfig {

    @PersistenceContext
    private EntityManager em;

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

 

2.1.3. TestRepository.java

src/test/java/net/<project name>/repository/

Querydsl 테스트를 진행해보겠습니다.

package net.blogteamthreecoderhivebe.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import net.blogteamthreecoderhivebe.config.TestJpaConfig;
import net.blogteamthreecoderhivebe.config.TestQueryDslConfig;
import net.blogteamthreecoderhivebe.entity.Job;
import net.blogteamthreecoderhivebe.entity.Member;
import net.blogteamthreecoderhivebe.entity.constant.MemberCareer;
import net.blogteamthreecoderhivebe.entity.constant.MemberLevel;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;

import java.util.Optional;

import static net.blogteamthreecoderhivebe.entity.QMember.member;
import static org.assertj.core.api.Assertions.assertThat;



@DisplayName("JPA 연결 테스트")
// Querydsl
@DataJpaTest
@Import(TestQueryDslConfig.class)
// ********
public class CoderHiveRepositoryTest {

    @Autowired
    private MemberRepository memberRepository;
    
    @Autowired
    private JobRepository jobRepository;

    // Querydsl
    @Autowired
    private JPAQueryFactory queryFactory;
    // ********

    @DisplayName("QueryFactory 테스트")
    @Test
    public void QueryFactoryTest() {
        final Job job = Job.builder()
                .main("백엔드 개발")
                .detail("웹 서버")
                .build()

        jobRepository.save(job);

        String nickname = "고양이";

        Job savedJob = jobRepository.findById((long)1).get();

        Member mem = Member.builder()
                .job(savedJob)
                .email("example@coderhive.com")
                .level(MemberLevel.BEGINNER)
                .career(MemberCareer.ASSOCIATE)
                .nickname(nickname)
                .build();

        memberRepository.save(mem);

        // Querydsl
        Member fetch = queryFactory.selectFrom(member)
                .fetchOne();
        // ********

        assertThat(member.equals(mem));
    }
}

 

 

2.3. main 에 세팅하기

2.3.1. QueryDslConfig.java

src/main/java/net/<project name>/config/

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

@Configuration
public class QueryDslConfig {

    @PersistenceContext
    private EntityManager em;

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

 

2.3.2. PostRepositoryCustom.java

src/main/java/net/<project name>/repository/querydsl/

public interface PostRepositoryCustom {
    List<Post> findAllInnerFetchJoin();
}

 

2.3.3. PostRepositoryCustomImpl.java

src/main/java/net/<project name>/repository/querydsl/

import com.querydsl.jpa.impl.JPAQueryFactory;
import static com.learning.jpa.domain.post.QPost.post;
import org.springframework.beans.factory.annotation.Autowired;

@Repository
public class PostCustomRepositoryImpl implements PostCustomRepository {

    @Autowired
    private JPAQueryFactory queryFactory;

    @Override
    public List<Post> findAllInnerFetchJoin() {
        return queryFactory.selectFrom(post)
            .innerJoin(post.comments)
            .fetchJoin()
            .fetch();
    }
}

 

2.3.4. PostRepository.java

src/main/java/net/<project name>/repository/

public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryCustom{
    ...
}