Kotlin + Spring Boot 2.1.0 + Thymeleaf + IntelliJ IDEA + Gradle で Hello World

## 概要

IntelliJ IDEA で Kotlin + Spring Boot 2.1.0 + Thymeleaf を使用して Hello World を表示するプログラムを書く。

## 環境

- IntelliJ IDEA Community Version 2018.2.5
- Kotlin plugin version 1.3.0-release-IJ2018.2-1
- Gradle 4.8.1
- Spring Boot 2.1.0
- Thymeleaf 3.0.11

## Spring Initializr でプロジェクトの雛形を生成する

[Spring Initializr](https://start.spring.io/) で以下の内容を指定して 「Generate Project」 する。

- Generate a 「Gradle Project」 with 「Kotlin」 and Spring Boot 「2.1.0」
- Group: com.example
- Artifact: demo
- Dependencies: Web, Thymeleaf

<img width="1009" alt="sp1.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/d6286bb4-3b16-096e-3ba2-9a051fd4188a.png">

プロジェクトの zip ファイルをダウンロードできる。

### プロジェクトファイル

ダウンロードした zip ファイルを展開。

```
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   ├── kotlin
    │   │   └── com
    │   │       └── example
    │   │           └── demo
    │   │               └── DemoApplication.kt
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── kotlin
            └── com
                └── example
                    └── demo
                        └── DemoApplicationTests.kt
```

### ビルド用ファイル build.gradle

今回は Kotlin 1.3.0 を使用しているので kotlinVersion = '1.3.0' に書き直しても良いが、修正しなくても良い。

```
buildscript {
    ext {
        kotlinVersion = '1.2.70'
        springBootVersion = '2.1.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}
compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ["-Xjsr305=strict"]
        jvmTarget = "1.8"
    }
}

repositories {
    mavenCentral()
}


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

### アプリケーションクラス DemoApplication.kt

特に何も修正しない。

```
package com.example.demo

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

@SpringBootApplication
class DemoApplication

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

## IntelliJ IDEA でプロジェクトを作成する

IntelliJ IDEA にて Import Project で build.gradle を指定する。

<img width="669" alt="sp3.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/de78bb3b-1517-682f-9a72-bc3a64ef26a0.png">

Use auto-import にチェックを入れてインポート。

<img width="931" alt="sp2.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/6b7b8c94-81ce-a56a-18dc-7c2f0a27c30a.png">

## 雛形プログラムを実行する

IntelliJ IDEA のメニューにて View → Tool Windows → Gradle で Gradle のウィンドウを開く。

<img width="657" alt="sp4.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/2ad22aa5-aadd-9ebd-c982-6cb1b63bbcea.png">

Gradle のウィンドウにて Tasks → application → bootRun で右クリックして Run 'demo [bootRun]' を選択して実行。

<img width="410" alt="sp5.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/4cbe9595-7b78-c518-6f4a-b2a330a74822.png">

実行すると Run ウィンドウに以下のような Spring Boot のメッセージが表示される。

```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.0.RELEASE)
```

その後「Tomcat started on port(s): 8080 (http) with context path ''」や「Started DemoApplicationKt」というようなログが表示される。

http://localhost:8080 にアクセスすると以下のようなメッセージが表示される。サーバが起動してはいるが、プログラムの中身が無い状態になっている。

```
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
```

## Hello World のコードを追加する

2つのファイル HelloController.kt と hello_name.html を追加して Hello World を実現する。

<img width="312" alt="sp7.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/5d31dfd0-42ae-048d-b8ee-089765f4cdb9.png">

### Controller クラスを追加する

以下の HelloController クラスを src/main/kotlin/com/example/demo/HelloController.kt に追加する。

<img width="353" alt="sp6.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/507a1668-df13-f979-a877-eac5ecbd74a6.png">

```kt
package com.example.demo

import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod

@Controller
class HelloController {

    @RequestMapping(value = ["/hello"], method = [RequestMethod.GET])
    @ResponseBody
    fun hello_world(): String {
        return "hello, world"
    }

    @RequestMapping(value = ["/hello/{name}"], method = [RequestMethod.GET])
    fun hello_name(@PathVariable name: String, model: Model): String {
        model.addAttribute("name", name)
        return "hello_name" // Thymeleaf テンプレートファイル名
    }
}
```

### Thymeleaf のテンプレートファイルを追加する

以下の HTML テンプレートファイルを src/main/resources/templates/hello_name.html に追加する。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Hello, [[${name}]]</title>
</head>
<body>
<p>Hello, [[${name}]]</p>
</body>
</html>
```

## Hello World プログラムを実行する

再度、プログラムを実行する。

<img width="316" alt="spb.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/c95b55ae-58a6-7609-d100-0ba3029880d0.png">

http://localhost:8080/hello にアクセスすると、「hello, world」と表示される。

<img width="374" alt="sp8.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/cd9576f2-92dc-eb18-40ee-c2b3641fc267.png">

http://localhost:8080/hello/hoge にアクセスすると、「Hello, hoge」と表示される。

<img width="374" alt="sp9.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/f06b4980-218b-13c8-0948-79ae077f07e6.png">

URLの「hoge」の部分は任意の文字列を指定できる。

<img width="374" alt="spa.png" src="https://qiita-image-store.s3.amazonaws.com/0/139365/f84ce796-fb6f-0266-7be2-2d024de260b5.png">

## 参考資料

- [IntelliJ IDEA: The Java IDE for Professional Developers by JetBrains](https://www.jetbrains.com/idea/)
- [Spring Boot](http://spring.io/projects/spring-boot)