Kotlin + Spring Boot + Thymeleaf で学んだことの整理

# はじめに
9月くらいからちまちま触っていたアプリケーションについて、学んだことを整理するためにここに簡単に残します。

勉強になったことやこれから学びたいことがたくさんあるので、この記事の続編がじゃんじゃん追加になるイメージで書き進めていこうと思います。

https://gitlab.com/takkii1010/kotlin-demo

…あくまで自分の備忘録！

[Thymeleafの紹介](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#thymeleaf%E3%81%AE%E7%B4%B9%E4%BB%8B)

## この記事における達成目標
* Webアプリケーションとしての最低限のサンプルとして成り立つこと
* Kotlin、Spring Boot、Thymeleafの雰囲気を知る
* データの保持はなし
  * GetのURLパラメータから取得した値をブラウザ上に表示できる

<img width="512" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/7d56249c-1f87-65ea-c279-3c0c9aab8dc1.png">

## 環境

```
$ gradle -version

Gradle        5.6.2
Kotlin:       1.3.41
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM:          1.8.0_222 (AdoptOpenJDK 25.222-b10)
OS:           Mac OS X 10.14.1 x86_64
```
* IntelliJ IDEA 2019.2.2

※なお、IntelliJ IDEAのバージョンが古い場合、Gradleのバージョンの違いでうまく動かないことがあります。躓いてかなり時間を費やしてしまったので備忘です    
[Android Gradle 5.0 Update:Cause: org.jetbrains.plugins.gradle.tooling.util](https://stackoverflow.com/questions/53702038/android-gradle-5-0-updatecause-org-jetbrains-plugins-gradle-tooling-util)

> For others who have the same problem in IntelliJ:  
upgrading to the latest IDE version should resolve the issue.  
In my case going from 2018.1 -> 2018.3.3


### 作るもの
1. index.html
1. DemoController.kt
1. main.css

#### STEP1 大枠のデモ用アプリを作成
[Spring Initializr](https://start.spring.io/) から、何の言語を使うかなどを設定し、デモ用にアプリを作成します。

自分で1から作成する必要がない！なんて楽なんだ…。
細かい部分はあとでカスタマイズしましょう。

以下の設定を選択し、「Generate the projexts」を押下するとzipでダウンロードできます。

|設定項目|選択|
|:--:|:--:|
|Project|Gradle Project|
|Language|Kotlin|
|Spring Boot|2.1.8(あとで `2.1.7` にカスタマイズします)|
|Project Metadata|変更なし|
|Dependencies|SpringBootDevTools, Lombok, Spring Configuration Processor, Spring Web, Thymeleaf|

#### STEP2 IDEA でOpen

* ダウンロードした `demo.zip` を任意の場所に展開
* IntelliJ(IDEはお好みで)を起動し、「Open」→ 展開したプロジェクト `demo` を選択
* 開くと勝手にプロジェクト用にGradleのinstallが始まります　`demo/.gradle` 配下ですね。  
<img width="350" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/75950ccc-bf61-4eba-98fe-5111492893e5.png">


#### STEP3 まずは、中身見てみます
* 上記を見る限り、resources配下には何もないのでHTMLやCSS、JSは作成する必要があります。
* デフォルトで作成されているのは、 `DemoApplication.kt` ですね。
  * 中身を見ると、どうやら起動するmainメソッドのよう（日本語正しいかな）
  
    ```ruby: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)
    }
    ```

#### STEP4 SpringBootのバージョンを変更します
作成した時点（2019/9/6）では、 [Spring Initializr](https://start.spring.io/) からは `2.1.7` が選択できなかったため、 `build.gradle.kt` を直接修正します。
(勉強したいバージョンが `2.1.7` なので…)

※なお、現在の最新は、 `2.1.9` のようです。（2019／10／9）

* 簡単です！ `8` を `7` に変えるだけ。

  修正前

  ```ruby:build.gradle.kt
  import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

  plugins {
  	id("org.springframework.boot") version "2.1.8.RELEASE"
  	id("io.spring.dependency-management") version "1.0.8.RELEASE"
  	kotlin("jvm") version "1.2.71"
  	kotlin("plugin.spring") version "1.2.71"
  }

  ~省略~
  ```
  修正後

  ```ruby:build.gradle.kt
  import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

  plugins {
  	id("org.springframework.boot") version "2.1.7.RELEASE"
  	id("io.spring.dependency-management") version "1.0.8.RELEASE"
  	kotlin("jvm") version "1.2.71"
  	kotlin("plugin.spring") version "1.2.71"
  }

  ~省略~
  ```
* 「Close Project」で一度プロジェクトを閉じて、再度開きます
* すると以下のように表示されるので、「Apply dependencies」　
 <img width="582" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/c4c1d98d-5a6a-75c6-de82-83ea5df6c4d6.png">


  他に良いやり方を知っているよって方はぜひ教えてください…！

#### STEP5 画面作成
ようやく本題です。
Thymeleafを使って初期画面を作成していきます。  

今回はサンプルなので、ごく簡単に作りました。

```ruby:UserController.kt
package com.example.demo.controller

import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.*

@Controller
@RequestMapping("user")
class UserController {

    @GetMapping
    fun index(@RequestParam(name = "inputName") inputName: String, model: Model): String {
        model.addAttribute("yourName", inputName)
        return "index"
    }
}
```
* Spring MVCについては、 [図解で学ぶ Spring MVC](https://speakerdeck.com/otty375/architecture-of-spring-mvc) がとてもわかりやすい
* @Controller, @RestControllerの違いは、 [ここ](https://qiita.com/tag1216/items/3680b92cf96eb5a170f0) がわかりやすかった

```ruby:index.html
<!DOCTYPE html>
<html lang="en" xmlnxs="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
  <title>Title</title>
</head>
<body>
  <table>
      <tr>
          <td>
              <span th:text="あなたの名前" />
          </td>
          <td>
              <span th:text="${yourName}" />
          </td>
      </tr>
  </table>
</body>
</html>
```
* linkタグでのパスの指定は、 `static` 配下から指定
* `th:text` , `${yourName}` については、 [Thymeleaf公式(スタンダード式構文)](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%80%E3%83%BC%E3%83%89%E5%BC%8F%E6%A7%8B%E6%96%87)


```ruby:main.css
@charset "utf-8";
/* ---- テーブル ---- */
table, td, th {
  border: 1px solid black;
  margin: auto;
}
table td {
  padding: 10px;
}
```

#### STEP6 起動＆動作確認
* `demo` > `Tasks` > `build` > `build`
* `demo` > `Tasks` > `application` > `bootRun`  
<img width="305" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/ec576a61-d25f-b4bb-c56c-70bb561a02da.png">

* `http://localhost:8080/user?inputName=takkii1010` にアクセス  
<img width="512" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439602/7d56249c-1f87-65ea-c279-3c0c9aab8dc1.png">


### 参考サイト
[Thymeleaf公式ドキュメント](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)
[Spring Initializr](https://start.spring.io/)

### 最後に
…Bootstrapでかっこよくしたいところですね。
Bootstrapも「今後やりたいこと」に追加します。

#### 今後やりたいこと
##### 機能  
* 入力フォームがあり、簡単なデータの保持ができる（DBなしでメモリ上に保持でOK）
* 登録済みデータの更新ができる
* DBに接続してデータの保持ができる
* サーバ間でのREST通信
* ローカル環境からAWSへの移行（無料の範囲で遊ぶ予定）

あとは思い付いた機能を随時追加

##### テスト関連
* JUnit
* Selenide

##### UI改善
* BootstrapでおしゃれなUIにする