plugins { id 'java' id 'war' id 'eclipse' id 'idea' id 'org.cyclonedx.bom' version '3.2.4' id 'org.springframework.boot' version '2.7.18' id 'io.spring.dependency-management' version '1.1.3' } group = 'com.eactive' version = '1.0.0' sourceCompatibility = "1.8" targetCompatibility = "1.8" def nexusUrl = "https://nexus.eactive.synology.me:8090" allprojects { repositories { maven { url "${nexusUrl}/repository/maven-public/" allowInsecureProtocol = true } } } // 로컬 전용 라이브러리 — WebLogic 배포 산출물(war/bootWar)에서 제외한다. // 정보보호 점검에서 Actuator/모니터링 라이브러리가 배포본에 실려 있으면 불필요하게 탐지되므로 // 로컬(bootRun/IDE)에서만 classpath 에 오르게 한다. 제외 로직은 아래 war/bootWar 블록. // // ※ Spring Boot 의 developmentOnly 를 쓰지 않는 이유 // developmentOnly 는 bootJar/bootWar 에서만 제외된다. 표준 war task 는 runtimeClasspath 를 // 그대로 쓰므로 산출물에 실린다 (실측: devtools 가 eapim-portal.war 에 포함되어 있었음). // ※ 별도 configuration(localOnly)을 쓰지 않는 이유 // runtimeClasspath 에서 빠지면 IntelliJ 가 모듈 classpath 를 구성할 때도 빠져 // IDE 로 기동할 때 Actuator/SBA 가 동작하지 않는다. def localOnlyLibPrefixes = [ 'spring-boot-devtools', 'spring-boot-starter-actuator', 'spring-boot-actuator', // spring-boot-actuator, -autoconfigure 모두 매칭 'micrometer-', // actuator 전용(runtimeClasspath 상 다른 출처 없음 — 확인함) 'spring-boot-admin-', ] dependencies { annotationProcessor "org.projectlombok:lombok:1.18.28" annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.2.0", "org.mapstruct:mapstruct-processor:1.5.5.Final" implementation 'com.eactive.elink.common:elink-common-data:4.5.5' // OpenAPI 3.0/3.1 spec 지원 (Nexus/Maven 해석). 기존 libs/swagger fileTree 대체. // swagger 최신 릴리스(2.2.52/2.1.45)도 SpecVersion 은 V30/V31 까지만 — OpenAPI 3.2 는 // 아직 swagger-core/parser 어느 버전도 미지원. 지원 추가 시 버전만 상향하면 됨. JDK8 호환. implementation 'io.swagger.core.v3:swagger-core:2.2.52' // io.swagger.v3.oas.models.*, io.swagger.v3.core.util.Json implementation 'io.swagger.parser.v3:swagger-parser:2.1.45' // io.swagger.parser.OpenAPIParser, io.swagger.v3.parser.* implementation 'io.swagger:swagger-annotations:1.6.14' // io.swagger.annotations.ApiModelProperty (CommissionSearch) implementation project(':elink-online-core-jpa') implementation project(':elink-portal-common') // implementation project(':kjb-safedb') implementation('org.springframework.boot:spring-boot-starter') implementation 'org.springframework.boot:spring-boot-starter-jta-atomikos' implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-validation') // ↓ 로컬 전용. war/bootWar 산출물에서는 localOnlyLibPrefixes 로 제외된다. // runtimeOnly 인 이유: compileClasspath 에서 빠지므로 자바 코드가 이 API 를 참조하면 // 컴파일 단계에서 막힌다. implementation 이면 참조가 컴파일에 통과해버리고, // 배포본(actuator/SBA 제외됨)에서 NoClassDefFoundError 로 터진다. // IntelliJ / bootRun 은 runtimeClasspath 기준이라 로컬 기동에는 정상 포함된다. // 설정(application-local*.yml)으로만 사용한다. runtimeOnly('org.springframework.boot:spring-boot-starter-actuator') // Spring Boot Admin client. 2.7.16 = Spring Boot 2.7.x 대응 마지막 계열(Java 8 호환). runtimeOnly('de.codecentric:spring-boot-admin-starter-client:2.7.16') // 위 runtimeOnly 원칙의 유일한 예외. InterceptorsEndpointConfig 가 actuator API // (@Endpoint / InfoContributor)를 참조해야 하므로 compileClasspath 에만 올린다. // compileOnly 는 runtimeClasspath 에 포함되지 않으므로 war/bootWar 산출물에는 영향이 없다. // 해당 클래스는 @ConditionalOnClass 로 actuator 부재 시 로드되지 않으니 // 배포본(actuator 제외)에서 NoClassDefFoundError 가 나지 않는다. compileOnly('org.springframework.boot:spring-boot-actuator') implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.0' implementation group: 'com.fasterxml.woodstox', name: 'woodstox-core', version: '6.5.1' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-security' implementation('org.springframework.boot:spring-boot-starter-cache') implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.data:spring-data-envers' implementation 'org.springframework.boot:spring-boot-starter-jdbc' developmentOnly 'org.springframework.boot:spring-boot-devtools' implementation 'org.springframework:spring-expression:5.3.30' implementation group: 'xalan', name: 'xalan', version: '2.7.3' implementation 'org.hibernate:hibernate-envers:5.6.15.Final' implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.0.0' implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' implementation 'com.github.ua-parser:uap-java:1.5.3' implementation 'org.apache.httpcomponents:httpclient:4.5.14' implementation 'com.navercorp.lucy:lucy-xss-servlet:2.0.1' implementation 'javax.servlet:javax.servlet-api:4.0.0' implementation 'org.jasypt:jasypt:1.9.3' implementation 'xerces:xercesImpl:2.12.2' implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.apache.commons:commons-collections4:4.4' implementation 'commons-net:commons-net:3.9.0' implementation('commons-beanutils:commons-beanutils:1.9.4') { // exclude group: 'commons-collections', module: 'commons-collections' } implementation 'org.mapstruct:mapstruct:1.5.5.Final' // WS-2026-0003 (jackson-core async parser DoS, CVSS 7.5) — 2.18.6 에서 수정. JDK8 호환. implementation 'com.fasterxml.jackson.core:jackson-core:2.18.6' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.6' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.6' implementation group: 'org.apache.velocity', name: 'velocity-engine-core', version: '2.3' // runtimeOnly group: 'com.mysql', name: 'mysql-connector-j', version: '8.4.0' runtimeOnly 'com.oracle.database.jdbc:ojdbc8:19.20.0.0' implementation 'net.bytebuddy:byte-buddy:1.14.5' // Commons FileUpload (WAS 독립적인 multipart 처리) implementation 'commons-fileupload:commons-fileupload:1.5' implementation 'commons-io:commons-io:2.15.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' testImplementation 'org.mockito:mockito-inline:3.11.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.seleniumhq.selenium:selenium-java:4.8.3' testImplementation group: 'io.github.bonigarcia', name: 'webdrivermanager', version: '5.9.1' testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.2.1' } ext { springMavenArtifactVersion = '5.3.30' encoding = 'UTF-8' profile = 'local' } task printProfile { doLast { if (project.hasProperty('profile')) { println "Current profile: ${project.property('profile')}" } else { println "No profile specified" } } } bootRun { // 디버깅 사용시에는 아래 내용 주석 해제 하세요 // jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005' sourceResources sourceSets.main // processResources 필터 우회 (dev yml 직접 참조) // 로컬 기동 기본 프로파일. // dev/stage/prod 는 리버스프록시(OHS) 뒤 WAR 배포용이라 server.forward-headers-strategy=framework 가 // 걸려 있다. framework 는 신뢰 프록시 목록 없이 X-Forwarded-* 를 그대로 신뢰하므로 앞단이 없는 // 로컬 기동에는 쓰지 않는다(로컬은 공통 기본값 native = Tomcat RemoteIpValve, 사설대역만 신뢰). // 다른 프로파일로 띄우려면: gradle bootRun -PbootProfile=dev // ('profile' 이 아니라 'bootProfile' 인 이유: 위 ext 블록이 profile='local' 을 이미 점유하고 있어 // findProperty('profile') 은 -P 지정 여부와 무관하게 항상 'local' 을 돌려준다.) def bootRunProfile = (project.findProperty('bootProfile') ?: 'local_rinjaemac').toString() args = ["--spring.profiles.active=" + bootRunProfile] } // annotation processor 출력 디렉토리는 IntelliJ/Gradle 통합이 자동 등록함. // 명시적으로 srcDir 추가하면 IntelliJ idea 모드에서 MapStruct가 같은 파일을 // 중복 생성하려다 javax.annotation.processing.FilerException 발생함. sourceSets { main { java { srcDir 'src/main/java' } } } configurations { annotationProcessor // WebLogic 배포 시 Tyrus WebSocket 필터(weblogic.websocket.tyrus.TyrusServletFilter)와 // 충돌 방지: WAR 에 번들된 Tomcat WsSci 가 javax.websocket.server.ServerContainer 속성을 // WsServerContainer 로 등록 → WebLogic Tyrus 필터가 TyrusServerContainer 로 캐스팅하다 실패. // 앱은 WebSocket 미사용이므로 Tomcat WebSocket 모듈 제외. all { exclude group: 'org.apache.tomcat.embed', module: 'tomcat-embed-websocket' } } compileJava { options.annotationProcessorPath = configurations.annotationProcessor options.compilerArgs += ["-parameters"] options.encoding = 'UTF-8' } processResources { // exclude { details -> // details.file.name.startsWith('application-') && // details.file.name.endsWith('.yml') && // !(details.file.name in ['application-stage.yml', 'application-prod.yml']) // } } test { useJUnitPlatform { if (project.hasProperty('includeE2E') && project.includeE2E.toBoolean()) { includeTags 'e2e' } else { excludeTags 'e2e' } } enabled = true } // 로컬 전용 설정 파일. 배포 산출물(WAR)에 실리면 Actuator/SBA 설정이 그대로 노출되어 // 정보보호 점검에 불필요하게 걸린다. processResources 는 건드리지 않는다 // (bootRun 이 build/resources/main 을 그대로 쓰므로 로컬 기동이 깨진다). def localOnlyResources = ['**/application-local*.yml'] // 배포 산출물에서 로컬 전용 라이브러리를 걸러낸다. localOnlyLibPrefixes 는 파일 상단 정의. def excludeLocalOnlyLibs = { org.gradle.api.file.FileCollection cp -> cp.filter { f -> !localOnlyLibPrefixes.any { p -> f.name.startsWith(p) } } } bootWar { archiveFileName = "eapim-portal-boot.war" mainClass = 'com.eactive.apim.portal.PortalApplication' rootSpec.exclude(localOnlyResources) classpath = excludeLocalOnlyLibs(classpath) } war { archiveFileName = "eapim-portal.war" from('src/main/resources/jeus-web-dd.xml') { into 'WEB-INF' } from('src/main/resources/weblogic.xml') { into 'WEB-INF' } rootSpec.exclude(localOnlyResources) classpath = excludeLocalOnlyLibs(classpath) } task printSourceSets { doLast { sourceSets.each { srcSet -> println "SourceSet: ${srcSet.name}" println " Java srcDirs : ${srcSet.allJava.srcDirs}" println " Resources : ${srcSet.resources.srcDirs}" println " Output dir : ${srcSet.output.classesDirs.asPath}" } } } // CycloneDX SBOM -> xlsx 변환 (gradle sbomXlsx) apply from: "$projectDir/gradle/sbom-xlsx.gradle"