【SpringBoot入門】thymeleafを使ってフォーム送信

#目的

[Spring Quickstart Guide](https://spring.io/quickstart)を取り組み終えた方、SpringBootを学び始めた方、復習をしたい方に向けて、

公式ガイド[Handling Form Submission](https://spring.io/guides/gs/handling-form-submission/)を実際に取り組み学んだことを共有します。

完成形はこちらになります。

Form画面で入力された値をResult画面で表示させるという処理を実装していきます。

![スクリーンショット 2020-07-08 13.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/4f501b36-035e-2014-29fa-ba078394de6f.png)

![スクリーンショット 2020-07-08 13.44.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/7170b180-6d05-3dc0-75e2-4829a418324a.png)



開発環境、これまでのおさらいは以下になります。

```text:開発環境
OS： macOS Mojave バージョン10.14.6
テキストエディタ： Visual Studio Code（以下VSCode）
Java: 11.0.2
```


[QuickstartGuideのおさらいはこちらから](https://qiita.com/morioheisei/items/59384f015e9e3801c4a7)
[Building a RESTful Web Service編のおさらいはこちらから](https://qiita.com/morioheisei/items/03106a823063677fe2f7)
[Consuming a RESTful Web Service編のおさらいはこちらから](https://qiita.com/morioheisei/items/c0a7432ad0f7281730d5)
[Accessing Data with JPA編のおさらいはこちらから](https://qiita.com/morioheisei/items/3d93da3757f27a158466)




#1.SpringBoot projectを始めよう！

まずは、[spring initializr](https://start.spring.io/)にアクセスします。

1.ADD DEPENDENCIESボタンをクリックして、`Spring Web`と`Thymeleaf`を追加。
2.Artifact, Nameは、`handling-form-submission`に変更。
3.Javaを11に変更。

そして`GENERATE`ボタンをクリックしてZipファイルをダウンロードします。

![スクリーンショット 2020-07-08 9.35.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/dd1d177a-bb6a-135b-729f-01cae1a1827c.png)


ダウンロードしたZipファイルを展開したら準備完了です。

#2.コードを追加しよう！

先ほどのフォルダをVSCodeで開きます。
拡張機能のJava Extension Packのインストールの推奨します。と言われるのでインストールしておきましょう。

![スクリーンショット 2020-06-30 10.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/80331ebc-b6e3-af7b-181a-3c8921288b00.png)

##GreetingController.javaを作成しよう！

`src/main/java/com/example/handlingformsubmission/` にGreetingController.javaファイルを作成します。

![スクリーンショット 2020-07-08 9.55.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/3559b183-fd92-d52e-1f90-e3a4d00f4696.png)

公式を参考にコードを追加します。

```java:GreetingController.java
package com.example.handlingformsubmission;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class GreetingController {

  @GetMapping("/greeting")
  public String greetingForm(Model model) {
    model.addAttribute("greeting", new Greeting());
    return "greeting";
  }

  @PostMapping("/greeting")
  public String greetingSubmit(@ModelAttribute Greeting greeting) {
    return "result";
  }

}
```

追加したコードを深掘りしていきます。

###①`@Controller`

```java:GreetingController.java
@Controller
public class GreetingController {
  // 省略
}
```

`@Controller`というアノテーションをつける事によってSpringBootは、このクラスをコントローラとして扱ってくれます。
Viewに遷移してHTMLを作成するので、後述するメソッドの戻り値にViewを指定しなければいけません。

今回は登場しませんが、`@RestController`というアノテーションも同様にコントローラとして扱ってくれますが、Viewに遷移せずメソッドの戻り値がレスポンスのコンテンツになります。

###②greetingFormメソッド

```java:GreetingController.java
@GetMapping("/greeting")
public String greetingForm(Model model) {
  model.addAttribute("greeting", new Greeting());
  return "greeting";
}
```

**1.`@GetMapping`**
このアノテーションを付与する事で、`（）`内に記述したURLでGETリクエストがあった時に付与されたメソッドが呼び出されるようになります。
今回は`@GetMapping("/greeting")`です。したがって、`http://localhost8080/greeting`でGETリクエストがあった時、`greetingFormメソッドが呼ばれます。`

**2.model.addAttribute**
メソッドの引数に`Modelクラス`の引数を受け取っています。これは、View側に渡すデータを設定するためです。
`addAttribute(第一引数、第二引数)`メソッドを用いる事でView側にデータを渡しており、
第二引数にデータを設定して、第一引数の名前でView側でそのデータを使用することが出来ます。

今回は、`インスタンス化されたGreetingオブジェクト`を`greeting`という名前でViewに渡しています。
Greetingの実装は後ほど。

**3.メソッドの戻り値**
メソッドの戻り値にViewを指定しています。今回は`greeting`をreturnしています。
という事は、greeting.htmlが必要であるという事になります。実装は後ほど。

###②greetingSubmitメソッド

```java:GreetingController.java
@PostMapping("/greeting")
public String greetingSubmit(@ModelAttribute Greeting greeting) {
  return "result";
}
```

**1.`@PostMapping`**
このアノテーションを付与する事で、`（）`内に記述したURLでPOSTリクエストがあった時に付与されたメソッドが呼び出されるようになります。
今回は`@PostMapping("/greeting")`です。したがって、`http://localhost8080/greeting`でPOSTリクエストがあった時、`greetingSubmitメソッドが呼ばれます。`

**2.`@ModelAttribute`**
メソッドの引数にあるこのアノテーションは、指定したクラスにPOSTで送られてきた値をセットするためのものです。
今回は、`greeting`変数に送られてきた値が格納されており、`Greetingクラスの各変数に`値がセットされます。

**3.メソッドの戻り値**
メソッドの戻り値にViewを指定しています。今回は`result`をreturnしています。
という事は、result.htmlが必要であるという事になります。実装は後ほど。



##Greeting.javaを作成しよう！

`src/main/java/com/example/handlingformsubmission/` にGreeting.javaファイルを作成します。

![スクリーンショット 2020-07-08 13.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/44c14f06-935b-2e05-5279-4d6d24b7ff83.png)


公式を参考にコードを追加します。

```java:Greeting.java
package com.example.handlingformsubmission;

public class Greeting {

  private long id;
  private String content;

  public long getId() {
    return id;
  }
  public void setId(long id) {
    this.id = id;
  }

  public String getContent() {
    return content;
  }
  public void setContent(String content) {
    this.content = content;
  }

}
```

追加したコードを深掘りしていきます。

**1.変数の宣言**

```java:Greeting.java
private long id;
private String content;
```

`long型のid`、`String型のcontent`と２つの変数を宣言しています。
アクセス修飾子は`private`なので同一クラス内からしかアクセス出来ません。

**2.ゲッター、セッターメソッドの定義**

```java:Greeting.java
public long getId() {
  return id;
}
public void setId(long id) {
  this.id = id;
}

public String getContent() {
  return content;
}
public void setContent(String content) {
  this.content = content;
}
```

formで送信された値を格納したり、取り出したりするためのゲッター、セッターメソッドを用意します。


##greeting.htmlを作成しよう！


`src/main/resources/templates/` にgreeting.htmlファイルを作成します。
このhtmlファイルはフォーム画面を表示するためのものです。

![スクリーンショット 2020-07-08 13.52.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/1b102753-32ad-ab96-5e36-9118401308e4.png)


公式を参考にコードを追加します。

```html:greeting.html
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Getting Started: Handling Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>Form</h1>
    <form action="#" th:action="@{/greeting}" th:object="${greeting}" method="post">
      <p>Id: <input type="text" th:field="*{id}" /></p>
      <p>Message: <input type="text" th:field="*{content}" /></p>
      <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
    </form>
</body>
</html>
```

追加したコードのthymeleafの記述について深掘りしていきます。

> thymeleafとは、springbootで扱う事が出来るテンプレートエンジンです。th:〇〇と記述します。
> 日本語で書かれた[thymeleafチュートリアル](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html#thymeleaf%E3%81%AE%E7%B4%B9%E4%BB%8B)もあります！


**th:action**

formタグのaction属性の内容を置換しています。記述の仕方は、`th:action="@{}"`です。
method="post"となっているので、Submitボタンが押された時にGreetingControllerのgreetingSubmitメソッドが呼ばれます。

**th:object**

`th:object`でオブジェクトを指定しています。これにより、オブジェクト内の変数の参照の仕方がgreeting.idではなく、*{id}のような記述方法が可能になります。

**th:field**

th:objectで指定したオブジェクト内の変数を表示するために`th:field="*{変数名}"`と記述します。
今回は、Greetingクラスの中にid、contentがあるので、`th:field="*{id}"`、`th:field="*{content}"`となります。
また、`th:field="*{変数名}"`の中に記述した変数名がinputのid属性とname属性になります。


##result.htmlを作成しよう！

`src/main/resources/templates/` にresult.htmlファイルを作成します。
このhtmlファイルはフォーム画面から送られた結果を表示するためのものです。

![スクリーンショット 2020-07-08 14.57.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/9ba5a7d3-0e56-c4f7-9440-a920ff5f1e41.png)



公式を参考にコードを追加します。

```html:result.html
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Getting Started: Handling Form Submission</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Result</h1>
    <p th:text="'id: ' + ${greeting.id}" />
    <p th:text="'content: ' + ${greeting.content}" />
    <a href="/greeting">Submit another message</a>
</body>
</html>
```

追加したコードのthymeleafの記述について深掘りしていきます。

**th:text**

`th:text="{変数名}"`とする事で変数をテキストとして表示する事が出来ます。
文字列も混ぜて表示する際は、`''`で文字列を囲い、`＋`で連結させる事で文字列と変数を結合して表示出来ます。

今回は、フォームで送られてきたGreetingクラスのidとcontentを表示しているので、
`th:text="'id: ' + ${greeting.id}"`、`th:text="'content: ' + ${greeting.content}"`となります。


#3.実行してみよう！

アプリケーション実行の準備が出来たので確認しましょう。

ターミナルで以下のコマンドを入力してEnterしてください。

```terminal:ターミナル
$ ./mvnw spring-boot:run
```

そして、`http://localhost:8080/greeting`にアクセスすると以下のフォーム画面が表示されるはずです。（greeting.htmlが表示される）

![スクリーンショット 2020-07-08 15.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/cf93a2f5-1add-fae6-aaf2-0e412c5db479.png)

IdとMessageに任意の値を入力して、Submitボタンをクリックしてください。
そうするとResult画面が表示されるはずです。（result.htmlが表示される）

![スクリーンショット 2020-07-08 15.25.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555244/4d0bcc95-31de-4478-aac0-ed5a383d0c41.png)

完成です！お疲れ様でした。

#参考サイト

**[@ModelAttribute を使う](https://kazkn.com/post/2017/use-model-attribute/)**
**[Thymeleafの使い方](https://learning-collection.com/thymeleaf%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/)**
**[Spring Boot で Thymeleaf 使い方メモ](https://qiita.com/opengl-8080/items/eb3bf3b5301bae398cc2)**