๊น€์˜ํ•œ๋‹˜ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ๋‚˜์„œ ๊ฐ•์˜์— ์žˆ๋Š” Querydsl ์„ธํŒ…๊ณผ ํ˜„์žฌ ๋‚ด๊ฐ€ ์“ฐ๊ณ  ์žˆ๋Š” ์Šคํ”„๋ง 3.x ๋ฒ„์ „์˜ ์„ธํŒ…์ด ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹จ๊ฑธ ์•Œ์•˜๋‹ค. ๊ทธ๋ž˜์„œ ํ•ด๋‹น ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋Š”๊ฒƒ๊ณผ ๋™์‹œ์— ๊ฐ๊ฐ์˜ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ์กฐ๊ธˆ ์•Œ์•„๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ง€๋„๋ก ํ•˜๊ฒ ๋‹ค.

QueryDSL

  • JPA์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์ฟผ๋ฆฌ์ธ JPQL(Java Persistence Query Language)์„ ํ†ตํ•ด ๋™์  ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ต‰์žฅํžˆ ๋‚œ์žกํ•ด์ง„๋‹ค๋Š” ๊ฒƒ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค.
  • JPQL์€ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฌธ์ž์—ด์„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ด์–ด๋ถ™์ด๋Š” ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ๋ฌธ์ž์—ด์ด๊ธฐ์— ์˜คํƒ€๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์—๋Ÿฌ๋ฅผ ์žก์•„์ฃผ์ง€ ๋ชปํ•œ๋‹ค.(๋‹ค๋งŒ, NamedQuery๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋Šฅํ•˜๋‹ค) ๋˜ํ•œ ๋™์ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ, ์ค‘๊ฐ„์ค‘๊ฐ„ if๋ฌธ์— ์˜ํ•ด ๋ฌธ์ž์—ด์ด ์ถ”๊ฐ€๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง„๋‹ค. ๋”ฐ๋ผ์„œ ์ฟผ๋ฆฌ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • QueryDSL์€ ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ค์–ด์กŒ๋‹ค. Type-Safeํ•œ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์—”ํ‹ฐํ‹ฐ์™€ ๋งคํ•‘๋˜๋Š” ์ •์  ํƒ€์ž… QClass๋ฅผ ์ƒ์„ฑํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค. ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์˜ค๋ฅ˜๋ฅผ ์žก์•„๋‚ผ ์ˆ˜ ์žˆ๊ณ  ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ์กฐ๊ฑด์„ ๋ณด๋‹ค ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์šฉ์ดํ•ด์ง„๋‹ค๋Š” ๋ง์ด๋‹ค.
  • QueryDSL๋„ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” JPQL๋ฅผ ๊ตฌ์„ฑํ•ด ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค. ๋‹ค๋งŒ ์‚ฌ์šฉ์ž๋“ค์ด ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ถ”์ƒํ™”ํ•ด๋†“์€ JPQL ๋นŒ๋”๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

Gradle ์„ค์ •

  • Spring Boot 3.x ๋ฒ„์ „ ๊ธฐ์ค€
  • QueryDSL Implementation ๋ถ€๋ถ„๊ณผ QueryDSL Build Options ๋ถ€๋ถ„์„ ์ถ”๊ฐ€

build.gradle (groovy)

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
}

group = 'com.pythonstrup'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    // QueryDSL Implementation
    implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}

test {
    useJUnitPlatform()
}

/**
 * QueryDSL Build Options
 */
def querydslDir = "src/main/generated"

sourceSets {
    main.java.srcDirs += [ querydslDir ]
}

tasks.withType(JavaCompile) {
    options.getGeneratedSourceOutputDirectory().set(file(querydslDir))
}

clean.doLast {
    file(querydslDir).deleteDir()
}

build.gradle.kts (kotlin)

  • ์ฝ”ํ‹€๋ฆฐ์˜ ๊ฒฝ์šฐ, QeuryDSL Version Setting ์ฃผ์„ ๋ถ€๋ถ„๋„ ์ถ”๊ฐ€
plugins {  
    id 'java'  
    id 'org.springframework.boot' version '3.1.5'  
    id 'io.spring.dependency-management' version '1.1.3'  
    // querydsl๊ด€๋ จ ๋ช…๋ น์–ด๋ฅผ gradleํƒญ์— ์ƒ์„ฑํ•ด์ค€๋‹ค. (๊ถŒ์žฅ์‚ฌํ•ญ)  
//    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"  
}  

group = 'study'  
version = '0.0.1-SNAPSHOT'  

java {  
    sourceCompatibility = '17'  
}  

configurations {  
    compileOnly {  
        extendsFrom annotationProcessor  
    }  
}  

repositories {  
    mavenCentral()  
}  

dependencies {  
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'  
    implementation 'org.springframework.boot:spring-boot-starter-web'  
    compileOnly 'org.projectlombok:lombok'  
    runtimeOnly 'com.h2database:h2'  
    annotationProcessor 'org.projectlombok:lombok'  
    testImplementation 'org.springframework.boot:spring-boot-starter-test'  
    implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'  


   // QueryDSL Implementation
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"  
    annotationProcessor "jakarta.annotation:jakarta.annotation-api"  
    annotationProcessor "jakarta.persistence:jakarta.persistence-api"  
    // === QueryDsl ๋ ===}  

tasks.named('test') {  
    useJUnitPlatform()  
}  

//QueryDsl ๋นŒ๋“œ ์˜ต์…˜ (์„ ํƒ) ===  

def querydslDir = 'src/main/generated'  

sourceSets {  
    main.java.srcDirs += [ querydslDir ]  
}  

tasks.withType(JavaCompile) {  
    options.generatedSourceOutputDirectory = file(querydslDir)  
}  

clean.doLast {  
    file(querydslDir).deleteDir()  
}

Gradle ๋™์ž‘ ์›๋ฆฌ

์˜์กด์„ฑ ์„ค์ •

  • Querydsl JPA Support ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

maven repository querydsl support

Annotation Processor

  • ๋จผ์ €, Annotation Processor๋Š” ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ Annotation์— ์ •์˜๋œ ์ผ๋ ฌ์˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ์—๋Ÿฌ๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์†Œ์Šค์ฝ”๋“œ ๋ฐ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • querydsl-apt๋Š” ์†Œ์Šค ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ Querydsl ๊ด€๋ จ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ฟผ๋ฆฌ ํƒ€์ž… ํด๋ž˜์Šค๋“ค์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  Java ์ฝ”๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ฒ€์‚ฌํ•˜๋Š” ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. sourceSets์— QClass๋ฅผ ์ €์žฅํ•  ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด ํ•ด๋‹น ๊ฒฝ๋กœ์— ์ฟผ๋ฆฌ ํƒ€์ž… ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.
  • annotation-api๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ•ด๋‹น api์—๋Š” @Generated, @Deprecated, @SuppressWarnings, @Override์™€ ๊ฐ™์€ ์ž๋ฐ” ํ‘œ์ค€ ์–ด๋…ธํ…Œ์ด์…˜์ด ํ•ด๋‹น API์— ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

Unable to load class 'jakarta.annotation.Generated'

  • persistence-api๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. persistence-api๋Š” @Entity, @Id, @GeneratedValue, @Column ๋“ฑ์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ง€์›ํ•œ๋‹ค.

Unable to load class 'jakarta.persistence.Entity'.

๋นŒ๋“œ์˜ต์…˜

querydslDir

  • querydslDir์€ ๋ณ€์ˆ˜๋‹ค. QClass๋ฅผ ์ €์žฅํ•˜๊ธธ ์›ํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์คฌ๋‹ค. ๋Œ€์ฒด๋กœ "src/main/generated" ๊ฒฝ๋กœ๋กœ ์„ค์ •ํ•œ๋‹ค.

sourceSets

  • Gradle ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ •์˜ํ•œ ์†Œ์Šค์ฝ”๋“œ์™€ ๋ฆฌ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • java source set์— querydsl QClass ์œ„์น˜๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

JavaCompile ๋ช…๋ น์–ด

  • JavaCompile ์ž‘์—…์ด ์ผ์–ด๋‚  ๋•Œ, querydsl QClass ํŒŒ์ผ ์ƒ์„ฑ ์œ„์น˜๋ฅผ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • Groovy => tasks.withType(JavaCompile) {} ๋กœ ์ถ”๊ฐ€

Clean ๋ช…๋ น์–ด

  • gradle clean ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•  ๋•Œ, ๋™์ž‘์‹œํ‚ฌ ์ž‘์—…์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • clean ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋˜๋ฉด QClass Directory ์‚ญ์ œํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

์‹คํ–‰ ๋ฐฉ๋ฒ•

Qclass ์ƒ์„ฑ ๋ฐ ์‚ญ์ œ

์ƒ์„ฑ

  • Gradle - Task - other - compileJava๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.
  • ๋‹จ์‹œ SpringBootApplication ์„ ์‹คํ–‰ํ•ด๋„ ์ƒ์„ฑ๋œ๋‹ค.

ZowtPeT.png|462

  • ์•„๋ž˜์™€ ๊ฐ™์ด src/main/generated ๊ฒฝ๋กœ์— QClass๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
    V65Pla5.png|297

์‚ญ์ œ

  • Gradle - Task - build - clean ์„ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.
  • src/main/generated ๋””๋ ‰ํ† ๋ฆฌ์™€ ํŒŒ์ผ์ด ์ „๋ถ€ ์‚ญ์ œ๋œ๋‹ค.
    pFYAzPB.png|351

์ฃผ์˜์‚ฌํ•ญ

  • src/main/generated ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๊ฐœ๋ฐœํ•  ๋•Œ ํŽธ์˜๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์‹ค์ œ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด build๋ฅผ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•  ๋•Œ, ์ฝ”๋“œ ์‹คํ–‰์„ ์œ„ํ•ด ํ•„์š”ํ•œ QClass๋“ค์ด build ๋””๋ ‰ํ† ๋ฆฌ์˜ entity์™€ ๊ฐ™์€ ๊ฒฝ๋กœ์— ์ „๋ถ€ ํฌํ•จ๋˜๊ธฐ ๋•Œ๋ฌธ์— Docker์™€ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ์— generated ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ COPYํ•ด์„œ ๋„ฃ์„ ์ด์œ ๊ฐ€ ์—†๋‹ค.

ThqLndo.png|406

  • Git๊ณผ ๊ฐ™์€ ๋ฒ„์ „๊ด€๋ฆฌ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, generated๋ฅผ ๊ตณ์ด ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ignore ํŒŒ์ผ์— src/main/generated ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜์ž.

6NOqYik.png|408

์ฐธ๊ณ ์ž๋ฃŒ