既存の Spring Boot をマルチモジュールにしたい場合

# 今回やること
既存で作成した Spring Boot を マルチモジュールで管理できるようにしたい
- root モジュールには、kotlinなどの言語・フレームワークを管理
- サブモジュール別でライブラリ等を自分で管理できるようにする

# 最終ゴール
- サブモジュールで Bootrun できる
    - API 実行後、指定の返り値が返ってくること

# 注意
- 意味や解釈を間違えている可能性があります・・・🙇（調べてから記載はしてはいるのですが・・・）
    - ご指摘していただけるとありがたいです

# 前提条件
- すでに [spring initializr](https://start.spring.io/) で　作成後、`bootRun` で起動ができる

```
. (rootモジュール）
| - build.gradle.kts
| - settings.gradle.kts
| - src...
```


| ライブラリ | バージョン |
|:-:|:-:|
| spring boot | 2.5.13 |
| kotlin | 1.5.32 |
| Gradle | 7.4.1 |

# 実践

## 1. root モジュールの「build.gradle.kts」を確認

```Gradle
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
	id("org.springframework.boot") version "2.5.13"
	id("io.spring.dependency-management") version "1.0.11.RELEASE"
	kotlin("jvm") version "1.5.32"
	kotlin("plugin.spring") version "1.5.32"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11

repositories {
	mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-web")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("org.jetbrains.kotlin:kotlin-reflect")
	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
	kotlinOptions {
		freeCompilerArgs = listOf("-Xjsr305=strict")
		jvmTarget = "11"
	}
}

tasks.withType<Test> {
	useJUnitPlatform()
}


```

## 2. マルチモジュール化するための土台を作成 （サブモジュール名は 「sample-todo」 )

### 2 - 1. 新しいモジュール と build.gradle.kts を作成

```
. (rootモジュール）
| - build.gradle.kts
| - settings.gradle.kts
| - sample-todo // 新しく作成
  | - build.gradle.kts // 新しく作成
```

### 2 - 2. root モジュール　の 「build.gradle.kts」に記載

```Gradle
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
	id("org.springframework.boot") version "2.5.13"
	id("io.spring.dependency-management") version "1.0.11.RELEASE"
	kotlin("jvm") version "1.5.32"
	kotlin("plugin.spring") version "1.5.32"
}

// 全てのモジュールに対して適用する依存関係等を指定することができる
allprojects {
	group = "com.example"
	version = "0.0.1-SNAPSHOT"

	// 依存関係を取得することができる?
	// これがないと、起動できない
	repositories {
		mavenCentral()
	}

	tasks.withType<KotlinCompile> {
		kotlinOptions {
			freeCompilerArgs = listOf("-Xjsr305=strict")
			jvmTarget = "11"
		}
	}

	tasks.withType<Test> {
		useJUnitPlatform()
	}
}

// サブモジュールで使用する共通の依存関係を指定できる
subprojects {
    apply {
		plugin("java")
		plugin("kotlin")
		plugin("io.spring.dependency-management")
		plugin("org.jetbrains.kotlin.jvm")
		plugin("org.jetbrains.kotlin.plugin.spring")
	}

    java.sourceCompatibility = JavaVersion.VERSION_11

	dependencies {
		implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
		implementation("org.jetbrains.kotlin:kotlin-reflect")
		implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
	}
}

```

### 2 - 3. root モジュール　の 「settings.gradle.kts」に記載

```Gradle
rootProject.name = "root モジュール名"
include("sample-todo") // <- サブモジュールを追加
```

### 2 - 4. sample-todo モジュールの「build.gradle.kts」に記載

```Gradle
// Spring bootを導入する
plugins {
    id("org.springframework.boot")
}

// web サービスを使う上での最低限の依存関係を入れる
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

```

### 2 - 5. 以下のようなディレクトリ構造にする

```
sample-todo
├── build.gradle.kts
└── src
    ├── main
    │   └── kotlin
    │       └── com
    │           └── example
    │               └── sampleTodo
    │                   └── SampleTodoApplication.kt
    └── test
        └── kotlin

```

SampleTodoApplication.kt を↓ のように記載

```kotlin:SampleTodoApplication.kt
package com.example.sampleTodo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class SampleTodoApplication

fun main(args: Array<String>) {
    runApplication<SampleTodoApplication>(*args)
}
```

「Bootrun」 を行ってみる。（起動だけはできる状態）

### 2 - 6. root モジュールの「src」 より下のデクレクトリを削除

```
. root モジュール
└── src（ここから下のファイルは削除して良い）
     ├── main
     │   ├── kotlin
     │   │   └── com
     │   │       └── example
     │   │           └── ...
     │   └── resources
     └── test
          └── kotlin
               └── com
                    └── ....
```

## 3. APIの作成・実行

```
src
 ├── main
 │   └── kotlin
 │       └── com
 │           └── example
 │               └── sampleTodo
 │                   ├── SampleTodoApplication.kt
 │                   └── controller
 │                       └── SampleController.kt (新しく作成）
 └── test
      └── kotlin

```

```kotlin:SampleController.kt
package com.example.sampleTodo.controller

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class SampleController(){
    @GetMapping
    fun get(): String {
        return "OK"
    }
}
```

API を叩けるツール・コマンドで実行を行い、**以下の値が表示されれば終了**
- HTTPステータス「200」
- 「OK」の文字列が表示される



# 他にも・・・

## root モジュールで指定されたバージョンとは違うバージョンを使いたい場合

root モジュールの `「build.gradle.kts」` に記載
```gradle
plugins {
  id("org.springframework.boot") version "2.4.5" apply false
}
```

`apply false` を記載することで、「このプラグインは、`rootProjects` では適用しないことを宣言している ことになる


# 参考資料
- https://kazamori.jp/blogs/2020/06/30/gradle-multi-project/
- https://it-blue-collar-dairy.com/springboot_multi-project_sample/
- https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:dependencies_which_dependencies
- https://qiita.com/BooookStore/items/695b199a5d13f633a2dc
- https://qiita.com/k-okajima/items/ca29e2956a03c5768747