이번에는 지난번 spring boot maven 멀티모듈 생성/빌드 단계 정리에 이어서 java Gradle 멀티 모듈 생성 및 빌드 까지의 단계를 정리합니다.
스펙
- IDE: IntelliJ
- JDK: 17(Temurin 17.0.13)
- spring boot: 3.3.4
- Gradle:
- mybatis: 3.0.3
- mysql: 8.0.36
모듈
- gradle_demo
- demo_core: DB, Repository, Service, Com
- demo_api: Controller
#1.프로젝트 생성
- 프로젝트명: gradle_demo / 언어: Java / 타입: Gradle-Goovy
- 그룹: com.example
- 아티팩트: gradle_demo
- 패키지명: com.example.gradledemo
부모프로젝트 종속성 설정(하위 자식 모듈에 공통으로 주입)
- Spring Boot DevTools
- Lombok
- Validation

#2.하위모듈 생성
- 프로젝트 > 새로 만들기 > 모듈 > Java
- demo_core
- 시스템빌드: Gradle
- JDK: 17
- Gradle DSL: Groovy
- 상위: gradle_demo
- demo_api
- 시스템빌드: Gradle
- JDK: 17
- Gradle DSL: Groovy
- 상위: gradle_demo
#3.부모 프로젝트 src 삭제
- 부모 프로젝트는 자식 모듈의 dependencis만 관리하기 때문에 별도의 Java 소스가 필요없어 삭제 처리
#4.부모 프로젝트(rootProject gradle_demo) settings.gradle 확인
부모프로젝트(root)settings.gradle파일에 생성한 하위 모듈을 include 하고 있는지 확인(없으면 하위 모듈 include)
#5.부모 프로젝트 build.gradle 설정(주석 참고)
- 부모 프로젝트 build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.4'
id 'io.spring.dependency-management' version '1.1.6'
}
//root project 실행가능 Jar 파일 생성 기능 OFF
bootJar.enabled = false
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
//전체 프로젝트 공통 설정
allprojects {
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
}
}
//하위 프로젝트 공통 설정
subprojects {
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
}
//하위 프로젝트 demo_core 개별 설정(core 모듈은 실행가능한 Jar 는 필요 없지만, api 모듈이 참조할 plain.jar 는 생성해줘야함)
project(':demo_core') {
jar {
enabled = true
manifest {
attributes('Start-Class': 'com.example.demo_api.GradleDemoApplication') //필수!! 메인 클래스 지정
}
}
bootJar {
enabled = false
}
}
//하위 프로젝트 demo_api 개별 설정(실행 가능한 Jar 생성 / demo_core 모듈 종속성 설정)
project(':demo_api') {
jar {
enabled = false
}
bootJar {
enabled = true
}
dependencies {
implementation(project(':demo_core'))
}
}
#6.demo_core build.gradle 설정
- demo_core build.gradle
- 기본적인 설정은 부모프로젝트 build.gradle에 넣어놨기 때문에 demo_core 모듈에서는 DB, mybatis 관련 dependencies설정만 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
runtimeOnly 'com.mysql:mysql-connector-j'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
#7.demo_api pom.xml 설정
- demo_api build.gradle
- 기본적인 설정은 부모프로젝트 build.gradle에 넣어놨기 때문에 demo_api 모듈에서는 필요한 web, thymeleaf dependencies 설정만 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
#8.패키지 디렉토리 / 파일 생성
- demo_core
src/main/java/com/example/demo_core
ㄴ common
ㄴ App.config
ㄴ entity
ㄴ Member(class)
ㄴ mapper
ㄴ TestMapper(interface)
ㄴ repository
ㄴ TestRepo(class)
ㄴ service
ㄴ TestService(class)
src/main/resources
ㄴ /com/example/demo_core/mapper
ㄴ testMapper.xml
ㄴ application.properties
- demo_api
src/main/java/com/example/demo_api
ㄴ controller
ㄴ TestController(class)
ㄴ DemoApiApplication(main class)
src/main/resources
ㄴ static
ㄴ templates
ㄴ application.yaml
#9.application 설정
- demo_core모듈의 resources에 application.properties 파일을 생성하여 mybatis / db connect 설정 정보를 추가 한다.
spring.application.name=demo_core
mybatis.mapper-locations=classpath:com/example/demo_core/mapper/**/*.xml
mybatis.type-aliases-package=com.example.demo_core
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.auto-mapping-unknown-column-behavior=warning
mybatis.configuration.auto-mapping-behavior=partial
logging.level.com.payco.spa_core.mapper=trace
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/squid_proxy?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
spring.datasource.username=test
spring.datasource.password=demo123
logging.level.org.springframework.jdbc=trace
- demo_api모듈의 resources에 application.yaml 파일을 생성하여 서버 정보, 타임리프 정보를 추가 한다.
- 참고로 타임리프 classpath 정보가 없을 경우 에러를 만나게 된다.
spring:
application:
name: demo_api
mvc:
static-path-pattern: /static/**
thymeleaf:
prefix: classpath:/templates/
suffix: .html
cache: false
server:
port: 9090
#10. 테스트 코드 작성
아래 코드는 간단하게 회원 이름을 조회하는 코드입니다.
mysql db table에 샘플 데이터를 준비해주세요.(별도 설명 X)
- demo_core / entity / Member(class)
package com.example.demo_core.entity;
import lombok.Data;
@Data
public class TestMember {
private Long id;
private String name;
public TestMember(Long id, String name) {
this.id = id;
this.name = name;
}
}
- demo_core / mapper / TestMapper(interface)
package com.example.demo_core.mapper;
import com.example.demo_core.entity.TestMember;
import org.apache.ibatis.annotations.Mapper;
import java.util.Optional;
@Mapper
public interface TestMapper {
Optional<TestMember> findById(Long id);
}
- demo_core / mapper / testMapper.xml (resource)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo_core.mapper.TestMapper">
<select id="findById" parameterType="Long" resultType="TestMember">
select * from test_member where id = #{id}
</select>
</mapper>
- demo_core / repository / TestRepository(class)
package com.example.demo_core.repository;
import com.example.demo_core.entity.TestMember;
import com.example.demo_core.mapper.TestMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
@RequiredArgsConstructor
public class TestRepository {
private final TestMapper testMapper;
public Optional<TestMember> findById(Long id) {
return testMapper.findById(id);
}
}
- demo_core / service / TestService(class)
package com.example.demo_core.service;
import com.example.demo_core.entity.TestMember;
import com.example.demo_core.repository.TestRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class TestService {
private final TestRepository testRepository;
public String findById(Long id) {
Optional<TestMember> member = testRepository.findById(id);
return member.map(TestMember::getName).orElse(null);
}
}
- demo_core / common / AppConfig(class)
package com.example.demo_core.common;
import com.example.demo_core.mapper.TestMapper;
import com.example.demo_core.repository.TestRepository;
import com.example.demo_core.service.TestService;
import lombok.RequiredArgsConstructor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@RequiredArgsConstructor
@MapperScan(basePackages = "com.example.demo_core.mapper")
public class AppConfig {
private final TestMapper testMapper;
@Bean
public TestRepository testRepository() {
return new TestRepository(testMapper);
}
@Bean
public TestService testService() {
return new TestService(testRepository());
}
}
- GradleDemoApplication(main class)
package com.example.demo_api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.example")
public class GradleDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GradleDemoApplication.class, args);
System.out.println("== start gradle demo application ==");
}
}
- TestController(class)
package com.example.demo_api.controller;
import com.example.demo_core.service.TestService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("api")
public class TestController {
private final TestService testService;
@GetMapping("/test/{id}")
public String test(@PathVariable("id") Long id) {
log.info("TestController#test({})", id);
return testService.findById(id);
}
}
#11.Spring Boot 실행 테스트(IntelliJ 로컬머신)
- server port : 9090
- 인텔리제이에서 메인클래스를 실행하여 localhost:9090/api/test/3에서 테스트 진행(포스트맨)
#12.Gradle build
- 빌드 명령어
./gradlew clean build
#12. jar 파일 실행
java -jar demo_api-0.0.1-SNAPSHOT.jar
postman으로 테스트 성공(200 OK)
localhost:9090/api/test/4
이상 spring boot gradle 멀티 모듈 프로젝트 생성 및 빌드 과정에 대한 정리를 마치겠습니다.
아주 기본적인 프로젝트 설정이기 때문에 위 내용을 참고하여 프로젝트에 응용하시면 될 것 같습니다.
참고로 시간이 지날수록 spring boot 및 각 dependency 버전이 변경되기 때문에 자신의 상황에 맞춰 업데이트 해서 진행하셔야 합니다.
'Study > Spring' 카테고리의 다른 글
Spring Boot에서 예외(Exception) 처리하기 (0) | 2024.10.26 |
---|---|
spring boot Maven 멀티모듈 프로젝트 생성/빌드 (0) | 2024.10.23 |
댓글