Spring Boot / Thymeleafの基礎を学ぶ【初心者向け】

## はじめに
この記事は社内でSpring Boot（実質的にはSpring？）の勉強会を行うにあたり作成した資料となります。
１時間程度で済む簡単なものになっています。
「Spring Bootってこんな感じなんだ」ということが少しでも伝われば幸いです。
なお、私自身Spring並びにSpring Boot初心者なため、記事に誤っている点があるかもしれません。
その際はご指摘いただけますと幸いです。

## 環境
- Mac
- Spring 2.0.2
- Dokcer for Mac
- Gradle 5.2.1
- VSCode

※Eclipseでええやん！って人はDockerじゃなくても○。
※Gradleについては以下の記事が分かり易かったです。
→　 [多分わかりやすいGradle入門] (https://tech-lab.sios.jp/archives/9500)
　　[Gradle入門] (https://qiita.com/vvakame/items/83366fbfa47562fafbf4)

## Springについて
### 強み
 - 変更に強い
    - DI(Dependency Injection）という仕組みが導入されている。
      - それぞれが独立しているため依存度が低く、変更に強い。
 - 拡張性が高い
    - 基本的な機能の大部分が `インターフェース` として提供されている。 
    - 必要な部分は簡単に追加できる。
 - 保守性が高い
    - `AOP（アスペクト指向プログラミング）` を用いることができる。
      - 共通のプログラムを再利用することでコーディング量減・修正も簡単
 - テストが簡単
    -  `Spring MVC Test` という専用のテストプログラムで結合テストが簡単にできる。 
 - 大規模データベース `NoSQL` に対応

### 弱み
 - フレームワークの規模が大きく、全体を把握するのが難しい。
 - DIコンテナの正しい使い方が難しい
 - 日本語のドキュメントが乏しい

## じゃあSpring Bootって何？
>WEBアプリケーションに特化した「Spring MVC」というフレームワークの完成形として、Spring MVCやその他のSpring Frameworkのライブラリ類をいい感じに組み合わせたWebアプリケーション環境を簡単に構築するライブラリです。

【参考： [[Java] Spring BootでHello World!（入門編）] (https://www.marineroad.com/staff-blog/16785.html)】

>その特徴を簡単にまとめると、

>1.アノテーションを記述するだけで実装できる機能が多数あり、コード量を削減できる
2.Webコンテナをjarに内蔵することで、jar単体でWebアプリケーションが実行できる
3.今までのSpringフレームワークでは必須だった、XML設定ファイルが不要になった
4.Spring Initializrというプロジェクト雛形生成サービスがあり、一から開発する必要がない

>などなど様々な高速システム開発のための機能が提供されています。

【[[Java] Spring Bootで簡単・高速にWebAPI開発] (http://www.xn--springboot-mh5yz04y.tokyo/01-introduction-spring-boot/)】


## 下準備
- Docker for Macをインストールし、 `docker` コマンドが打てることを確認する。
- 以下のコマンドを実行する。

```
$ git clone https://github.com/miwa0519/spring-boot.git
$ cd spring-boot/spring_boot_docker/
```

- 以下のコマンドを実行。
 - Tomcatが8080ポートで動く。
 - 3000番ポートは人気者だから別ポートがいい、という場合は `docker-compose.yml` 内の3000部分を別の番号に変えるといい。
 - Springが上手く動いていればコンソールに `Spring>>>` みたいな例のAAが出る。~~出ると少しテンションが上がる。~~

```
$ docker build -t spring-docker ./
$ docker run -p 3000:8080 spring-docker
```

- http://localhost:3000
にアクセスする。(3000は任意のポートに変えていい)

今回のサンプルだと、ソースコードを編集する度に上記コマンドを実行する必要があります。
今後改善予定です。面倒臭くてすみません:bow_tone1:

- ※こちらは必要な人のみ
 - [こちらの記事] (https://qiita.com/h-r-k-matsumoto/items/406a3b48f75131a65e0a) でVSCode向けのプラグインを取り纏めてくださっています。 `import` とか手入力してられるかよ！という人にはオススメです。


## とりあえずHello Worldしてみる
`src/main/java/com/example/demo` 直下に `HelloController.java` を作成します。
`HelloController.java` 内に以下のソースを記述します。

```java:src/main/java/com/example/demo/HelloController.java
package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
  @RequestMapping("/hello")
  public String hello() {
    return "Hello World!";
  }
}
```

http://localhost:3000/hello
にアクセスすると `Hello World!` と表示されていると思います。

<img width="417" alt="スクリーンショット 2019-05-29 12.52.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273022/5bff1516-81ed-b0a4-dbdf-d7cbed48994d.png">


アノテーションが二つ出てきました。これらが何をしているかを簡単に説明します。

1. `@RestController` ：RestControllerアノテーションをつけると、このコントローラーが `Webアプリケーション` のリクエストを受け付ける `Restコントローラー` になる。
2. `@RequestMapping` ：RequestMappingアノテーションをつけると、ルーティングを行なってくれる。今回でいうと、 `http://localhost:3000/hello` にアクセスすると `Hello` メソッドを実行する、という紐付けが行われる。

これらが使えるように、それぞれのクラスをインポートしてます。インポート出来ていないとコンパイルエラーになるので気をつけてください。

もう少しWebアプリらしく `Hello World!` したいので、今度はテンプレートを作ってみたいと思います。

## Viewの部分を実装する
Spring Bootでは1.2以降はJSPが非推奨とされています。
なので今回は `Thymeleaf` というテンプレートエンジンを使います。
Spring Bootでは `Thymeleaf`を使うのが無難らしいです。

### Thymeleafを使えるように設定する
設定をしないとThymeleafは使えません。

`build.gradle` を以下のように書き換えてください。

```diff:build.gradle
// 中略

dependencies {
+	compile('org.springframework.boot:spring-boot-starter-thymeleaf')
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

```
### 実際にHTMLを書いてみる
Thymeleafの設定ができたので、実際にHTMLを書いてViewを実装していきます。
`src/resources` 直下に `templates` ディレクトリを用意し、 `hello.html`　ファイルを作成します。

```src/main/resources/templates/hello.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Thymeleaf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <p th:text="'Hello Wonderful World!'" />
  </body>
</html>
```
※ `th:text` は `Thymeleaf` の属性。Thymeleafの記述については以下が分かりやすかったです。
[[Java] Spring BootでThymeleafを使ってみよう！（応用編）] (https://www.marineroad.com/staff-blog/17761.html)

### HelloControllerを修正する
テンプレートを用意したので、今度はコントローラーがそのテンプレートを呼び出してくれるように修正します。

```diff:HelloController.java
package com.example.demo;

  import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
+ import org.springframework.stereotype.Controller;
+ import org.springframework.web.bind.annotation.RequestMethod;

- @RestController
+ @Controller
  public class HelloController {
    @RequestMapping("/hello")
    public String hello() {
-     return "Hello World!"
+     return "hello";
    }
  }

```

`@RestController` を `@Controller` に変更しました。
これにより、WebAPIとして機能していた `HelloController` が `MVC` の `C` として振る舞うようになります。
それにより、 `return` の部分に記載した `hello` を `ViewResolver` がView名として認識し、実際のファイル名に変換し、クライアントに返却します。

最初のコマンドを再度実行した後に
http://localhost:3000/hello
をリロードします。テンプレートが呼び出されて、表示される文言が変わっていることが確認できると思います。

<img width="455" alt="スクリーンショット 2019-05-29 12.56.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273022/779f5428-13d8-fde4-402a-ba28bfa9bf10.png">



## 簡単な計算アプリを作ってみる
MVCのVとCについてはここまでで学ぶことが出来ました。
最後にModelについての説明を加えながら、与えた数字を元に足し算を行ってくれる簡単なアプリを作成したいと思います。

### Model作ってみる
まず、フォームの値を受け取って計算するためのモデルを作成します。
Controllerを作成したディレクトリの中に `model` ディレクトリを作成し、その中に `Form.java` を作成します。

```java:src/main/java/com/example/demo/model/Form.java
package com.example.demo.model;

public class Form {

  private int num1 = 0;
  private int num2 = 0;
  private int total = 0;

  public int getNum1(){
    return num1;
  }

  public void setNum1(int num){
    this.num1 = num;
  }

  public int getNum2(){
    return num2;
  }

  public void setNum2(int num){
    this.num2 = num;
  }

  public int getTotal(){
    return total;
  }

  public void setTotal(int total){
    this.total = total;
  }
  public void sumTotal(){
    total = this.num1 + this.num2;
    setTotal(total);    
  }
}
```

入力値を保持する `num1` 、 `num2` と合計値を保持する `total` フィールドを作成し、それぞれに `getter` と `setter` を定義します。
また、 `num1`と `num2` の合計を算出する `sumTotal` メソッドを定義しておきます。

### 入力フォームを表示する
modelを定義したので、次は入力フォームを表示してみます。
まず、入力フォームを表示するためのコントローラーを定義します。

```java:src/main/java/com/example/demo/CalculateController.java
package com.example.demo;
import com.example.demo.model.Form;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

@Controller
public class CalculateController {
  @RequestMapping("/calculate")
  public String form(Model model){
    model.addAttribute("form", new Form());
    return "index";
  }
}
```

今までの `Controller` と違うところは、メソッドに `Model` 型のオブジェクトを引数に取っているところです。
この `Model` に値をセットすることでHTMLに値を渡す事が出来ます。(Springが用意してくれているクラス)
`model.addAttribute("form", new Form())` の部分で、 `model` に対し、Formインスタンスを渡しています。

```
model.addAttribute("変数名", オブジェクト)
```
※ちなみに、第2引数に `Form form` と記述しても同じ意味になります。（裏で 
 `addAttribute` と同じことが実行されるイメージ）

【参考：[【Spring Boot】ModelクラスとModel And Viewクラス] (https://pointsandlines.jp/java/model-and-view)】

 `form` メソッドでは `index` というテンプレートを最後に返しています。
今度は `index` テンプレートを作成し、入力画面を作成します。

### 入力画面を作る

```java:src/main/resources/templates/index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Index</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <h1>Form</h1>
    <form action="#" th:action="@{/result}" th:object="${form}" method="post">
      <p>first number: <input type="number" th:field="*{num1}" /></p>
      <p>Second number: <input type="number" th:field="*{num2}" /></p>
      <p><input type="submit" value="calculate" /></p>
    </form>
  </body>
</html>
```

最初に作った `hello.html` と異なるところは、 `th:action` 、 `th:object` 、 `th:field` という属性が出てきている点です。 
なんとなく見た目で伝わるかと思いますが、簡単に使い方だけご紹介します。


| th:action        　     |th:object                               | th:field="*{フィールド名}"|
|:-----------------------|:----------------------------------------|:------------------|
| フォームのアクションを指定する |${}で指定したオブジェクトにフォームで入力した値が入る。| th:objectで指定しているオブジェクトのフィールドに対して入力された値を入れる。        |

【参考： [Spring Boot でフォームの値を取得して操作] 】(https://qiita.com/NariseT/items/172ca093364aa9391989)

各テキストエリアに入力された値は、先ほどコントローラーで `Model` オブジェクトに追加した `Form` インスタンスの各フィールドに値がセットされます。

http://localhost:3000/calculate
にアクセスすると入力フォームが表示されるはずです。

<img width="670" alt="スクリーンショット 2019-05-29 13.54.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273022/fa5d75b4-ba6d-3eff-8587-8538956c2109.png">

### Controllerを修正する
今度はフォームで入力した値を受け取り、計算を行い、その結果を画面に表示できるようにします。
まずはコントローラーに新しいメソッドを追加します。

```diff:src/main/java/com/example/demo/CalculateController.java
package com.example.demo;
import com.example.demo.model.Form;

// 中略
  import org.springframework.ui.Model;
+ import org.springframework.web.bind.annotation.RequestMethod;
+ import org.springframework.web.bind.annotation.ModelAttribute;

  @Controller
  public class CalculateController {
    @RequestMapping("/calculate")
    public String form(Model model){
      model.addAttribute("form", new Form());
      return "index";
  }

+   @RequestMapping(value="/result", method = RequestMethod.POST)
+   public String result(@ModelAttribute Form form, Model model){
+     form.sumTotal();
+     model.addAttribute("form", form);
+     return "result";
+   }
  }
```

`@RequsetMapping` は今回パラメータを受け取るので、HTTPメソッドを指定します。
`method = RequestMethod.post` と記載することでこれはPOSTだよ！と指定できます。
また今回はメソッドの引数に `@ModelAttribute` というアノテーションがついています。このアノテーションをつけると `input` の値を受け取ることが出来ます。

`form` の各フィールドには入力フォームで入力された値がセットされている状態なので、 `Form` クラスで定義した `sumTotal` メソッドを呼び出し、 `form` の `total` フィールドに合計値を保持させます。

その結果を `result` テンプレートに表示させたいので、今度は `result` テンプレートを作成します。

### 計算結果を画面に表示する
`templates` ディレクトリ直下に以下のファイルを作成してください。

```java:src/main/resources/templates/result.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Result</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <h1>Result</h1>
    <p th:text="'Answer: ' + ${form.getTotal()}" />
    <a href="/calculate">Calculate Another number</a>
  </body>
</html>
```
`${}` で式展開を行なってくれるので、getterを使っての合計値を取得し、表示します。

計算実行結果は以下です。

<img width="636" alt="スクリーンショット 2019-05-29 13.59.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273022/4fa5b085-4ae9-fe49-4607-b0903c9e94ae.png">
<img width="599" alt="スクリーンショット 2019-05-29 13.28.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273022/981db89f-0927-b978-5cdb-06ab9d595cbc.png">


## 最後に
私自身がSpring Bootについて初歩的な部分を学んで感じたのは以下の三点です。

- 面倒な設定が少なく、すぐに開発に取りかかれた。（Dockerで動かすのが大変だったくらい）
- ソースコードが割と直感的に書ける
- 自分の求めているドキュメントに辿り着くまでの時間が壮大（自分の調べ方が下手なだけかも）

とはいえ私自身、初歩的な部分しかまだ分からない状況なので、今後も少しずつ学んでいけたらと思っております。
この記事がSpring Boot、Spring初心者の何かの皆さんの役に立てば幸いです。

## 参考

- [Docker+Spring-boot事始め](https://qiita.com/minase_tetsuya/items/cb9f937ad2e0767f45d3)
　環境構築でお世話になりました。プロジェクトを作るところからやってみたい方におすすめ
- [エンジニア志望者必見のSpring Frameworkとは] (https://blog.codecamp.jp/spring-framework)
- [Spring Boot でフォームの値を取得して操作] (https://qiita.com/NariseT/items/172ca093364aa9391989)　フォームってどうやって書くんだ？という時に凄く助かりました。
- [多様化するJavaのフレームワーク問題を解決する、「Spring Boot」とは？] (https://codezine.jp/article/detail/11310)