Spring Boot 3에서 JOOQ 세팅

조제·2024년 11월 22일
0

적용환경

  • jdk 21
  • Spring boot 3
  • postgresql 15
  • jookversion 3.19.14
  • nu.studer.jooq 플러그인 버전 9.0 (3rd party)
  • gradle

build.gradle 전문

buildscript {
	ext {
		jooqVersion = '3.19.14'
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '3.3.5'
	id 'io.spring.dependency-management' version '1.1.6'
	id 'nu.studer.jooq' version '9.0'  // JOOQ 코드 생성을 위한 플러그인
}

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

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(21)
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter'

	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'

	// db
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	runtimeOnly 'org.postgresql:postgresql'

	// Swagger
	implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'

	// test
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
	testCompileOnly  'org.projectlombok:lombok'
	testAnnotationProcessor  'org.projectlombok:lombok'

	// JOOQ 의존성 추가
	implementation 'org.springframework.boot:spring-boot-starter-jooq'

	jooqGenerator 'org.postgresql:postgresql'
	jooqGenerator "org.jooq:jooq:${jooqVersion}"
	jooqGenerator "org.jooq:jooq-meta:${jooqVersion}"

	jooqGenerator project(':jooq-custom') // 서브모듈을 jooqGenerator 설정에 추가
}

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

jooq {
	version.set("${jooqVersion}")

	configurations {
		create("main") {
			generationTool {
				jdbc {	// DB 접속정보 설정, 로컬의 경우 아래처럼 사용하고, 실제 배포 환경에서는 접속정보등을 환경변수등으로 추가해줘야 한다.(jenkins 등에서)
					driver = "org.postgresql.Driver"
					// PostgreSQL URL 형식으로 변경
					url = System.getenv("DB_URL") ?: "jdbc:postgresql://127.0.0.1:32367/project"
					user = System.getenv("DB_USER") ?: "dev"
					password = System.getenv("DB_PASSWORD") ?: "password"
				}

				generator {
					name = "org.jooq.codegen.DefaultGenerator" // Java 코드 생성기, Kotlin 의 경우 다른 제너레이터 사용

					database {
						name = "org.jooq.meta.postgres.PostgresDatabase"
						inputSchema = "public"  // 기본 스키마를 public으로 변경
						includes = ".*"         // 모든 테이블 포함
						excludes = "flyway_schema_history|spatial_ref_sys"  // 시스템 테이블 제외
					}

					// 생성된 코드 옵션
					generate {
						daos = true                       // DSL 생성시 dao 생성 여부
						records = true                    // DSL 생성시 record 생성 여부
						fluentSetters = true              // 메서드 체이닝 가능한 setter 생성
						javaTimeTypes = true              // Java 8 날짜/시간 타입 사용
						deprecated = false                // deprecated 코드 생성 안함
						pojos = true                      // POJO 생성 추가
						interfaces = true                 // 인터페이스 생성 추가
					}

					target {
						// 생성될 DSL 클래스의 패키지명, 프로젝트 패키지와 일관되계 셋팅하면 된다.
						packageName = "com.jooq.project.generated"
						// DSL 생성 위치를 build 디렉토리로 변경
						directory = "build/generated-src/jooq/main"
					}

					strategy {
						name = "com.jooq.custom.generator.CustomPrefixGeneratorStrategy" // 서브모듈의 커스텀 jooqGenerator 설정에 추가
					}
				}
			}
		}
	}
}

sourceSets {
	main {
		java {
			srcDirs = ['src/main/java', "build/generated-src/jooq/main"]	// 생성된 코드를 프로젝트 소스로 인식하도로 설정
		}
	}
}

// JOOQ 코드 생성이 컴파일 전에 실행되도록 설정
tasks.named('compileJava').configure {
	it.dependsOn(tasks.named('generateJooq'))
}

tasks.named('compileTestJava').configure {
	it.dependsOn(tasks.named('generateJooq'))
}

1. JOOQ 디펜던시와 DSL Generator 3rd party 플러그인 추가

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.5'
    id 'io.spring.dependency-management' version '1.1.6'
    id 'nu.studer.jooq' version '9.0'  // JOOQ 코드 생성을 위한 플러그인
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-jooq'
}

일단 위처럼 플러그인과 디펜던시 추가후 gradle 새로고침한 뒤 gradle dependeices에서 jooq 버전 확인하면 아래처럼 spring boot에 적합한 3.19.14 버전을 자동으로 가져온 것을 확인 할 수 있습니다.

2. 위 버전이 확인되었으면 gradle에서 전역변수로 해당 버전 선언

buildscript {
	ext {
		jooqVersion = '3.19.14'
	}
}
  • 위처럼 jooq version을 선언하는 것은 나중에 sub 모듈을 추가하는데, 해당 모듈에서 jooq 버전이 필요합니다.

3. JOOQ DSL generator 의존성 추가

jooqGenerator 'org.postgresql:postgresql'
jooqGenerator "org.jooq:jooq:${jooqVersion}"
jooqGenerator "org.jooq:jooq-meta:${jooqVersion}"

4. JOOQ generator 설정 추가

jooq {
	version.set("${jooqVersion}")

	configurations {
		create("main") {
			generationTool {
				jdbc {	// DB 접속정보 설정, 로컬의 경우 아래처럼 사용하고, 실제 배포 환경에서는 접속정보등을 환경변수등으로 추가해줘야 한다.(jenkins 등에서)
					driver = "org.postgresql.Driver"
					// PostgreSQL URL 형식으로 변경
					url = System.getenv("DB_URL") ?: "jdbc:postgresql://127.0.0.1:32367/project"
					user = System.getenv("DB_USER") ?: "dev"
					password = System.getenv("DB_PASSWORD") ?: "password"
				}

				generator {
					name = "org.jooq.codegen.DefaultGenerator" // Java 코드 생성기, Kotlin 의 경우 다른 제너레이터 사용

					database {
						name = "org.jooq.meta.postgres.PostgresDatabase"
						inputSchema = "public"  // 기본 스키마를 public으로 변경
						includes = ".*"         // 모든 테이블 포함
						excludes = "flyway_schema_history|spatial_ref_sys"  // 시스템 테이블 제외
					}

					// 생성된 코드 옵션
					generate {
						daos = true                       // DSL 생성시 dao 생성 여부
						records = true                    // DSL 생성시 record 생성 여부
						fluentSetters = true              // 메서드 체이닝 가능한 setter 생성
						javaTimeTypes = true              // Java 8 날짜/시간 타입 사용
						deprecated = false                // deprecated 코드 생성 안함
						pojos = true                      // POJO 생성 추가
						interfaces = true                 // 인터페이스 생성 추가
					}

					target {
						// 생성될 DSL 클래스의 패키지명, 프로젝트 패키지와 일관되계 셋팅하면 된다.
						packageName = "com.jooq.project.generated"
						// DSL 생성 위치를 build 디렉토리로 변경
						directory = "build/generated-src/jooq/main"
					}
				}
			}
		}
	}
}

sourceSets {
	main {
		java {
			srcDirs = ['src/main/java', "build/generated-src/jooq/main"]	// 생성된 코드를 프로젝트 소스로 인식하도로 설정
		}
	}
}

위처럼 셋팅하면 gradle Task에서 아래처럼 jooq 가 활성화 되며 DSL을 생성할수 있는 task 가 발생합니다.

생성된 task 이름을 확인하고 tasks.named('compileJava').configure, tasks.named('compileTestJava') 를 셋팅하면 컴파일 타임에 자동으로 DSL 을 생성해줍니다. (다만 컴파일이 조금 느려집니다.)

// JOOQ 코드 생성이 컴파일 전에 실행되도록 설정
tasks.named('compileJava').configure {
	it.dependsOn(tasks.named('generateJooq'))
}

tasks.named('compileTestJava').configure {
	it.dependsOn(tasks.named('generateJooq'))
}

5. JOOQ Config 생성

@Configuration
public class JooqConfig {
    @Bean
    public DefaultConfigurationCustomizer jooqDefaultConfigurationCustomizer() {
        return configuration -> configuration.settings()
                .withExecuteDeleteWithoutWhere(ExecuteWithoutWhere.THROW)  // 조건절 없이 delete 발생시 예외 발생
                .withExecuteUpdateWithoutWhere(ExecuteWithoutWhere.THROW)  // 조건절 없이 update 발생시 예외 발생
                .withRenderSchema(false)  // 스키마 이름을 sql 에 포함 하지 않음
                .withRenderFormatted(true)  // SQL 로깅 포맷팅
                .withBatchSize(100) // 배치 크기 설정
                .withQueryTimeout(60); // SQL 실행 타임아웃;
    }
}

6. 부가 설정 (sub module 세팅)

Jooq의 제너레이터는 스키마를 기본으로 Table class, Pojo, dao 등을 생성하는데, 생성시 해당 네이밍을 커스텀 할 수 있습니다.

  • 프로젝트에서 gradle 서브 모듈을 생성합니다. (jooq-custom)
  • jooq-custom 서브 모듈의 build.gradle 을 아래처럼 셋팅합니다.
plugins {
    id 'java'
}

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

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.jooq:jooq-codegen:${jooqVersion}"
}
  • jooq-custom 서브 모듈에 CustomPrefixGeneratorStrategy 생성
public class CustomPrefixGeneratorStrategy extends DefaultGeneratorStrategy {

    @Override
    public String getJavaClassName(Definition definition, Mode mode) {

        if(mode == Mode.DEFAULT){
            return "J" + super.getJavaClassName(definition, mode);
        }else if (mode == Mode.POJO){
            return super.getJavaClassName(definition, mode) + "Pojo";
        }

        return super.getJavaClassName(definition, mode);
    }

}

위 설정은 DSL 생성시 table 클래스의 접두사 J 추가하고 pojo 생성시 접미사 Pojo 추가 하는 설정입니다.

  • 프로젝트 root build.gradle에 서브모듈 추가
dependencies {
    jooqGenerator project(':jooq-custom') // 서브모듈을 jooqGenerator 설정에 추가
}

jooq {
	...
	strategy {
		name = "com.jooq.custom.generator.CustomPrefixGeneratorStrategy" // 서브모듈의 커스텀 jooqGenerator 설정에 추가
	}
	...
}

JOOQ 생성

gradlew clean build 를 실행할 경우 build 폴더에 아래와 같이 코드가 생성됩니다.


Github : https://github.com/whwp4151/spring-boot-jooq-sample

profile
조제

0개의 댓글