【初心者】Spring Boot で骨組みだけの CRUD アプリを作ってデータの流れを確認する

# はじめに

**Spring Boot** のデータの流れをイメージで捉えるために、次のような骨組みだけのサンプルアプリを作って、データの受け渡しを一つ一つ確認していきます。
![2021-04-24 131659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/70dc7cf4-8a81-fb92-42d1-a2489ba10c2b.png)
サンプルアプリには、**Create**（登録）、**Read**（閲覧）、**Update**（更新）、**Delete**（削除）の主要4機能を全て入れるようにしますが、本記事の趣旨とは関係のない余計なコードは排除して、最小限のコード量にします。

Service や Repository は作らず、データの処理は Controller のみで手短に済ませます。
そして、次のように簡略化した **MVC** のイメージ図に当てはめて、**CRUD** のそれぞれの機能を確認していきます（下図の詳細は[後述](#5-1-一覧表示機能read)）。
![2021-04-25 114510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/eefec4af-a684-080f-0ea1-e0012941abe4.png)

実際に動かして確認できるように、**全てのソースコード**を掲載してから、各機能におけるデータの流れを追っていきますので、ソースコードが不要な方は、そのあたりは適当に読み飛ばしてください。

使用する環境は次のとおりです。

|項目|内容|
|---|---|
|IDE|Spring Tool Suite4|
|OS|Windows 10|
|データベース|MySQL|
|DB接続のAPI|JDBC API|
|ビルドツール|Gradle|

学習のアウトプットとして書いている記事なので、記述内容に間違いなどがあるかもしれません。
お気づきのことなどあれば、ご指摘などいただけると幸いです。

**＜目次＞**
[1. データベースの用意（MySQL）](#1-データベースの用意mysql)
[2. プロジェクト作成時の設定内容](#2-プロジェクト作成時の設定内容)
[3. 作成するファイルとソースコード](#3-作成するファイルとソースコード)
[4. Spring MVC のイメージ](#4-spring-mvc-のイメージ)
[5. 機能ごとのデータの流れのイメージ](#5-機能ごとのデータの流れのイメージ)

# 1. データベースの用意（MySQL）

先に、MySQL のデータベースを用意しておきます。
MySQL の部分は要点のみを書きますので、詳細については [MySQLの使い方](https://www.dbonline.jp/mysql/) という記事を参考にしてください。

**＜データベースの作成＞**

CREATE DATABASE 文で `spring_test` という名前のデータベースを作成しておきます。

```
mysql> create database spring_test;
Query OK, 1 row affected (0.33 sec)
```

**＜ユーザーの作成＞**

CREATE USER 文で `yama3@localhost` という名前のデータベースを作成しておきます（ユーザー名とパスワードは何でもいいです）。

```
mysql> create user 'yama3'@'localhost' identified by '123456';
Query OK, 0 rows affected (0.32 sec)
```

GRANT 文で、データベース（`spring_test`）に対する全ての権限を設定しておきます。

```
mysql> grant all on spring_test.* to 'yama3'@'localhost';
Query OK, 0 rows affected (0.23 sec)
```

# 2. プロジェクト作成時の設定内容

プロジェクト作成については、設定内容を中心に書いていきます。
細かいことは[前回記事](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d)に書きましたので、必要に応じて参照してみてください。

Spring Tool Sweet（STS）を使用してプロジェクトを作成していきます。
メニューから「**File**」→「**New**」→「**Spring Starter Project**」の順で選択して、次の画面を表示します。

ここでは、ビルドツール（Type）は **Gradle** を、Java バージョン（Java Version）は **11** を選択しています。
プジェクト名（Name）は適当に付けておきます。
![2021-04-20 210308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/577cf168-1148-a998-7af9-14ccf31e7b0f.png)

「**Next**」ボタンを押すと、下図のライブラリを選択する画面になります。
選択するのは、「JDBC API」「MySQL Driver」「Spring Boot DevTools」「Spring Web」「Thymeleaf」の5つとなります（細かいことは[こちら](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#new-spring-starter-project-dependencies)を参照）。
![2021-04-22 225753.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0ab19ac8-2835-ea9b-6fc3-1a138cca1310.png)
「**Finish**」をクリックすれば、プロジェクトが作成されます。

# 3. 作成するファイルとソースコード

以下、作成するファイルの全体図と、ソースコードの全体を一通り掲載しておきます。
個々のメソッドにおけるデータの受け渡しの流れについては、後から「[5. 機能ごとのデータの流れのイメージ](#5-機能ごとのデータの流れのイメージ)」のところで確認していきます。

## 3-1. ファイルのディレクトリ

プロジェクトのディレクトリ構成は、下図のとおりです。
<font color="blue">青枠</font>の2つのファイルは、ファイルもコードも自動生成されるので、そのまま使います。
<font color="green">緑枠</font>の1つのファイルは、ファイルのみ作成されているので、そこにコードを書き込みます。
<font color="red">赤枠</font>の7つのファイルは、所定のディレクトリにファイルを作成の上、コードを書いていきます。

![2021-04-22 231224_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/09437a82-9e0b-5d9b-8718-0aba346d3cf4.png)

<font color="red">※注意点</font>　3つのHTMLファイルは、`src/main/resources/templates`の下に`sample`というフォルダを作成した上で、その中に格納していますのでご注意ください。

## 3-2. アプリケーションクラス（自動生成）

プロジェクト作成時に、`CrudSampleApplication.java`というファイルが自動生成されています（プロジェクト名によって名前は異なります）。
特に変える必要もないので、このままにしておきます。

mainメソッドの中身は **[SpringApplication](https://spring.pleiades.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-application)** の **run メソッド**が記載されているだけです。
これにより、アプリケーションが起動されます。

```/src/main/java/com/example/demo/CrudSampleApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CrudSampleApplication {

	public static void main(String[] args) {
		SpringApplication.run(CrudSampleApplication.class, args);
	}
}
```

## 3-3. ビルドスクリプト（自動生成）

ビルドスクリプト（`build.gradle`）も自動生成されます。
プロジェクトで設定したライブラリなどが反映されています。
これも、そもままにしておきます。

```/build.gradle
plugins {
	id 'org.springframework.boot' version '2.4.5'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-jdbc'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'mysql:mysql-connector-java'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
	useJUnitPlatform()
}
```

## 3-4. アプリケーションプロパティ

ここにデータベースに関する設定を、以下のように記述します（ファイルは `src/main/resources` のフォルダに入っています）。

```/src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/spring_test
spring.datasource.username=yama3
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.initialization-mode=always
spring.datasource.schema=classpath:schema.sql
spring.datasource.data=classpath:data.sql
spring.datasource.sql-script-encoding=utf-8
```

以下、個別の設定が必要なところに触れておきます。
**spring.datasource.url** の末尾の `spring_test` は MySQL のデータベース名です。
**spring.datasource.username** には MySQL のユーザー名を記載します。
**spring.datasource.password** には MySQL のユーザーパスワードを記載します。

その他は、上記のままで大丈夫だと思います。設定内容の詳細は[こちら](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#4-%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E8%A8%AD%E5%AE%9A)を参照してください。

## 3-5. SQLスクリプト

SQLスクリプトには、プロジェクト起動時に実行されるSQL文を記載します。
`schema.sql`および`data.sql`には、次のような初期設定を書いておきます。
（細かいことは[こちら](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#6-sql%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)を参照してください）

### 3-5-1. schema.sql

```/FormTest/src/main/resources/schema.sql
DROP TABLE IF EXISTS test_table;

CREATE TABLE test_table
(
   id INT NOT NULL AUTO_INCREMENT,
   name VARCHAR(100) NOT NULL,
   old INT NOT NULL,
   PRIMARY KEY(id)
);
```

### 3-5-2. data.sql

```/FormTest/src/main/resources/data.sql
INSERT INTO test_table(name, old)
VALUES('Taro', 30), ('Jiro', 25), ('Saburo', 22);
```

## 3-6. コントローラー

コントローラーには、データベースからのデータの取得も含めた処理を書いておきます（邪道ですが）。
こうすることで、データベースとのデータのやりとりが一目瞭然になります。

本来は、ビジネスロジック（Service）とデータアクセス（Repository）を作成して分担して処理すべきところですが、ここでは作成していません。
（コントローラー作成に関する細かいことは[こちら](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#7-%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%AE%E4%BD%9C%E6%88%90)を参照してください）

```/src/main/java/com/example/demo/TestController.java
package com.example.demo;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sample")
public class TestController {

	private JdbcTemplate jdbcTemplate;
	
	//コンストラクタ
	@Autowired
	public TestController(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	//一覧画面の表示
	@GetMapping
	public String index(Model model) {
		String sql = "SELECT * FROM test_table";
		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
		model.addAttribute("testList", list);
		return "sample/index";
	}
	
	//新規入力フォームの表示
	@GetMapping("/form")
	public String form(@ModelAttribute TestForm testForm) {
		return "sample/form";
	}
	
	//新規入力データの保存
	@PostMapping("/form")
	public String create(TestForm testForm) {
		String sql = "INSERT INTO test_table(name, old) VALUES(?, ?);";
		jdbcTemplate.update(sql, testForm.getName(), testForm.getOld());
		return "redirect:/sample";
	}
	
	//編集フォームの表示
	@GetMapping("/edit/{id}")
	public String edit(@ModelAttribute TestForm testForm, @PathVariable int id) {
		String sql = "SELECT * FROM test_table WHERE id = " + id;
		Map<String, Object> map = jdbcTemplate.queryForMap(sql);
		testForm.setId((int)map.get("id"));
		testForm.setName((String)map.get("name"));
		testForm.setOld((int)map.get("old"));
		return "sample/edit";
	}
	
	//編集データの保存
	@PostMapping("/edit/{id}")
	public String update(TestForm testForm, @PathVariable int id) {
		String sql = "UPDATE test_table SET name = ?, old = ? WHERE id = " + id;
		jdbcTemplate.update(sql, testForm.getName(), testForm.getOld());
		return "redirect:/sample";
	}
	
	//データの削除
	@PostMapping("/delete/{id}")
	public String delete(@PathVariable int id) {
		String sql = "DELETE from test_table WHERE id = " + id;
		jdbcTemplate.update(sql);
		return "redirect:/sample";
	}
}
```

### 3-6-1. コンストラクタについての補足

上記では、コンストラクタを書いています。
コンストラクタの上にあるアノテーション`@Autowired`がなくとも、このサンプルアプリは動きます。

なお、フィールド部分を下記のように書けば、コンストラクタは無くとも動きます。

```java:参考
	@Autowired
	private JdbcTemplate jdbcTemplate;
```

**＜参考サイト＞**
・[Spring FrameworkでDIする3つの方法](https://reasonable-code.com/spring-injection-method/)

### 3-6-2. リクエストマッピングについて

リクエストマッピング（RequestMapping）には、クライアントから受け付けた**リクエスト URL** 及び **HTTP メソッド**によって、Controller 内のどのメソッドに処理を渡すかを決める役割があります。

上記の `TestController` の **create メソッド**を例に、ルールを見てみます。
まず、クラスの頭に付けているアノテーション **＠RequestMapping("/sample")** では、ベースパスを `/sample` と指定しています。
そして、create メソッドの頭に付いている **＠PostMapping("/form")** では、HTTPメソッドは `Post`、相対パスは `/form` という指定をしています。
この場合、リクエストURLが `/sample/form` で、HTTPメソッドが `POST` であれば、update メソッドに処理が渡されるということになります。

以上のルールに基づいて、クライアントからのリクエストと、それに対応する `TestController` のメソッドをまとめると次のようになります。

|HTTPメソッド|リクエストURL|Controller|処理内容|
|---|---|---|---|
|Get|/sample|index|一覧画面表示|
|Get|/sample/form|form|入力画面表示|
|Post|/sample/form|create|入力データ保存|
|Get|/sample/edit/{id}|edit|編集画面表示|
|Post|/sample/edit/{id}|update|編集データ保存|
|Post|/sample/delete/{id}|delete|データ削除|

## 3-7. フォームクラス

入力値を保持するためのフォームクラスを作成します。
このフォームクラスを入れ物にして、ビュー、コントローラー、クライアントの間のデータのやり取りを行います。

次のように、入力値（ここでは `test_table`のカラム）と対応させたフィールドを作成します。
フォームクラスには、コンストラクタがなくても大丈夫ですが、`getter` と `setter` は必須となりますので、作成しておきます。

```/src/main/java/com/example/demo/TestForm.java
package com.example.demo;

public class TestForm {
	
	private Integer id;
	private String name;
	private Integer old;

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getOld() {
		return old;
	}
	public void setOld(Integer old) {
		this.old = old;
	}
}
```

## 3-8. HTMLファイル

HTMLファイルは、最低限の内容を書いておきました。
3つのHTMLファイルは、`src/main/resources/templates`の下に`sample`というフォルダを作成した上で、その中に格納しています。

なお、オブジェクト（Map）から要素を取り出すのに `"${testForm.name}"` という書き方をしていますが、これは `"*{name}"` というように簡単に書くこともできます。
ここでは、イメージのし易さを優先して、あえて前者の書き方をしています。

### 3-8-1. index.html

これは一覧表示の画面です。

```/src/main/resources/templates/sample/index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>CRUD Sample</title>
</head>
<body>
    <h2>一覧ページ</h2>
    <table>
        <tr><th>id</th><th>name</th><th>old</th></tr>
        <tr th:each="test : ${testList}">
            <td th:text="${test.id}"></td>
            <td th:text="${test.name}"></td>
            <td th:text="${test.old}"></td>
            <td>
                <a href="#" th:href="@{'/sample/edit/' + ${test.id}}"><button>編集</button></a>
            </td>
            <td>
                <form action="#" th:action="@{'/sample/delete/' + ${test.id}}" method="post">
                    <button>削除</button>
                </form>
            </td>
        </tr>
    </table>
    <div><a href="#" th:href="@{/sample/form}">入力フォーム</a></div>
</body>
</html>
```

### 3-8-2. form.html

新規入力フォームの画面です。

```/src/main/resources/templates/sample/form.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>CRUD Sample</title>
</head>
<body>
    <h2>入力フォーム</h2>
    <form method="post" action="#" th:action="@{/sample/form}" th:object="${testForm}">
        <label for="name">名前</label>
        <input type="text" id="name" name="name" th:value="${testForm.name}"><br>
        <label for="old">年齢</label>
        <input type="text" id="old" name="old" th:value="${testForm.old}"><br>
        <input type="submit" value="送信">
    </form>
    <div><a href="#" th:href="@{/sample}">トップページ</a></div>
</body>
</html>
```

### 3-8-3. edit.html

編集フォームの画面です。新規入力フォームとほとんど同じ内容です。
共通化する方法もありますが、分かりやすさのために、別途作成しています。

```/src/main/resources/templates/sample/edit.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>CRUD Sample</title>
</head>
<body>
    <h2>編集フォーム</h2>
    <form method="post" action="#" th:action="@{'/sample/edit/' + ${testForm.id}}" th:object="${testForm}">
        <label for="name">名前</label>
        <input type="text" id="name" name="name" th:value="${testForm.name}"><br>
        <label for="old">年齢</label>
        <input type="text" id="old" name="old" th:value="${testForm.old}"><br>
        <input type="submit" value="送信">
    </form>
    <div><a href="#" th:href="@{/sample}">トップページ</a></div>
</body>
</html>
```

## 3-9. アプリケーションの起動

アプリケーションを起動してみます（起動方法の細かいことは[こちら](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#9-%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E8%B5%B7%E5%8B%95)を参照してください）。
Package Explorer上のプロジェクト名（ここでは`CRUDSample`）を右クリックして、「Run As」→「Spring Boot App」を選択します。
Console 画面に次のような表示がされていきます。
![2021-04-25 111446.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/a331f1b4-76db-035a-c141-3d005538ad51.png)
アプリケーションが起動したら http://localhost:8080/sample にアクセスします。
次のような画面が表示されたら成功です。
![2021-04-24 131659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/70dc7cf4-8a81-fb92-42d1-a2489ba10c2b.png)

# 4. Spring MVC のイメージ

データの流れを見るには、Spring MVC の構造を何となく把握しておく必要がありますが、「Spring MVC」という文言で画像検索すると、多種多様な画像が出てきます。
それぞれ内容が異なるので、なかなかイメージが掴みにくいところです。

## 4-1. 理論上のMVC

Spring MVC の図を確認する前に、まず、理論上のMVCの図を見てみます。
一般的な MVC はだいたい次のような構造として説明されています。
![2021-04-24 142143.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/05873565-08dd-6820-1005-04e627897768.png)

|項目|説明|
|---|---|
|Model|データの管理・処理を行う（DBへのアクセスなども含む）。|
|View|ユーザーへのへの表示・出力を行う。|
|Controller|ユーザーからのリクエストを受け付け、Model 及び View に伝達する。|

## 4-2. Spring MVC

数多のサイトに掲載されている Spring MVC の図が多種多様なのは、結局、簡単に図式化できるような構造ではないからだろうと思います。
とはいえ、Spring MVC のイメージを掴まないとデータの流れが見えてこないので、簡単に作図しておきます。
（[このあたり](https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/html/mvc.html#mvc-servlet)のサイトを参考にしています）
![2021-04-24 113207.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/5bb59447-ee39-cdd8-02b8-8d0847ce9d46.png)
図で見ると、Model の存在がいまいちよく分かりません。
個人的には、右側の **Business Class** と **Data Access** が Model に見えて仕方ないのですが、あくまでイメージの問題なので、深く考えないようにします。

上記のモデル図のままだと、データの流れのイメージを把握するのが難しくなってしまうため、**Front Controller** と **Controller** を一体のものとみなして、次のようなシンプルなモデルとして捉えておきます。

![2021-04-25 110340.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/358482c1-fccf-0881-0916-cde207e00ffd.png)

以下では、上記の構造を更に簡略化して、データの流れを追っていきます。

**＜参考サイト＞**
・[Web MVC framework](https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/html/mvc.html)
・[Spring Framework Learning 05](https://hackmd.io/@--Dj5YTqT2u8XdFR90gIgw/BkeW3irX-?type=view)

# 5. 機能ごとのデータの流れのイメージ

前置きが長くなりましたが、ここからが本題です。
データの流れがイメージできると、コードを書く際にも迷いが少なくなります。

大事なのは、次のところだと思います。
① **Controller** と **View** の間のデータのやり取りは、**Model** を介して行われていること
② やり取りするデータは、**Controller** にあるメソッドの**引数**に入れて、取得したり更新したりすること
このあたりに注目していただけると、分かりやすいのではないかと思います。

## 5-1. 一覧表示機能（READ）

まずは、CRUD の **Read**（読み込み）から確認していきます。
次の画面を表示するには、データベースから、登録されているデータの一覧を取得する必要があります。
![2021-04-24 131659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/70dc7cf4-8a81-fb92-42d1-a2489ba10c2b.png)

関係する Controller と View のコードは次のとおりです。

#### ① Controller のソースコード（抜粋）

一覧表示をする場合は、ユーザーは、リクエストURLは「**/sample**」、HTTPメソッドは「**GET**」でアクセスしてきます。
この場合は、**index メソッド**に処理が渡されます（対応関係のルールは「[3-6-2. リクエストマッピングについて](#3-6-2-リクエストマッピングについて)」に書いたとおりです）。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//中略
	@GetMapping
	public String index(Model model) {
        String sql = "SELECT * FROM test_table";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        model.addAttribute("testList", list);
        return "sample/index";
	}
}
```

**index メソッド** の中身を見てみると、最初の2行で次の処理を行っています。
・[JdbcTemplateクラス](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html)を使用してデータベースに接続（使用メソッドは queryForList）
・SQL文の実行により取得した一覧データを、List オブジェクトである **list** に格納（[参考](https://qiita.com/t-yama-3/items/969825d5c1bc4a16866d#-sql%E6%96%87%E3%81%AE%E5%AE%9F%E8%A1%8C)）

次の1行で、**list** に `testList` という名前を付けた上で、**Model** に格納しています（Model は引数に設定するだけで使えます）。
この **Model** が View にデータを渡してくれます。

最後の `return` では、一覧表示に使用するテンプレートを `sample/index.html` と指定しています。

#### ② View のソースコード（抜粋）

Controller から命令を受けた View は、`/src/main/resources/templates` フォルダから **sample/index.html** を探し出します。
データベースから取得している一覧データ **list** は、**Model** に `testList` という名前で格納されてますので、View 側ではこれを `${testList}` という記述で呼び出します（Thymeleaf を使用）。

```html:/sample/index.html（抜粋）
<table>
    <tr th:each="test : ${testList}">
        <td th:text="${test.id}"></td>
        <td th:text="${test.name}"></td>
        <td th:text="${test.old}"></td>
    </tr>
</table>
```
`th:each`の記述で、for each 文のように1レコード分ずつデータを取り出して、画面を作成します。

#### ③ データの流れのイメージ

一覧表示（READ）におけるデータの流れを図にすると、次のようになります。
ここでは、index メソッドの引数である <font color="red">**Model**</font> がデータ受け渡しの役割を担っています。
![2021-04-25 114510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/eefec4af-a684-080f-0ea1-e0012941abe4.png)
Controller が直接 View にデータを渡しているのではなく、 Controller が <font color="red">**Model**</font> にデータを格納して、View は <font color="red">**Model**</font> にデータを取りに行くというイメージです。

## 5-2. 登録機能（CREATE）

次に、CRUD の **Create**（登録）についてです。
まず、最初に入力フォームを表示する必要があるので、その部分から確認していきます。

### 5-2-1. 入力フォームの表示

次の入力フォームの表示では、データベースからデータを取得する必要はありません。
ここでは、フォームの入力データを保持するためのフォームクラス（`TestForm.java`）の使用が必要になります。
![2021-04-24 132040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/7a873e70-c1d8-0019-0241-8ac3cef75085.png)

#### ① Controller のソースコード（抜粋）

入力フォームを表示する場合、ユーザーは、リクエストURL「**/sample/form**」、HTTPメソッド「**GETメソッド**」でアクセスすることになります。
この場合は、**form メソッド**に処理が渡されます。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//中略
	@GetMapping("/form")
	public String form(@ModelAttribute TestForm testForm) {
		return "sample/form";
	}
}
```

**form メソッド** の中身は、`return` の1行のみです。
この1行で、View に対して一覧表示に使用するテンプレートを `sample/form.html` と指定しています。

なお、引数に指定しているフォームクラスには、`＠ModelAttribute`というアノテーションが付いています。
これにより、**Model** にフォームクラスのインスタンス `testForm` が追加されることになります（厳密なことは[こちらの記事](https://kazkn.com/post/2017/use-model-attribute/)を参照してください）。
`testForm` には何らの値を入れていませんので、中身は空っぽのままです。View は、この空の `testForm` を **Model** を介して取得することになります。

なお、`＠ModelAttribute` を付けずに、次のように記載しても動作します。

```java:TestController.java（参考）
	public String form(TestForm testForm) {
		return "sample/form";
	}
```

これは、「<font color="blue">ハンドラメソッドの引数に、フレームワーク側がサポートしていないクラスがあると自動的に ＠RequestParam または ＠odelAttribute とみなされるため</font>」とのことです（「[ModelAttributeでフォームパラメータをオブジェクトにマッピングする](https://tech.chakapoko.com/java/spring/spring-mvc-form-param.html)」より）。

**＜参考サイト＞**
・[Spring MVC についてまとめてみるよ！！！](https://qiita.com/Furuta03/items/76318ab3524c43630761#form%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%8Bentity%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%AE%E9%80%A3%E6%90%BA)
・[はじめてのSpring MVCアプリケーション](https://terasolunaorg.github.io/guideline/public_review/Overview/FirstApplication.html#controller)
・[ModelAttributeでフォームパラメータをオブジェクトにマッピングする](https://tech.chakapoko.com/java/spring/spring-mvc-form-param.html)
・[@ModelAttribute を使う](https://kazkn.com/post/2017/use-model-attribute/)

#### ② View のソースコード（抜粋）

Controller から命令を受けた View は、`/src/main/resources/templates` フォルダから **sample/form.html** を探し出します。
**Model** から取得した、フォームクラスのインスタンス `testForm` を、以下のようにセットして画面を作成します（Thymeleaf を使用）。

```html:/sample/form.html（抜粋）
<form method="post" action="#" th:action="@{/sample/form}" th:object="${testForm}">
    <label for="name">名前</label>
    <input type="text" id="name" name="name" th:value="${testForm.name}"><br>
    <label for="old">年齢</label>
    <input type="text" id="old" name="old" th:value="${testForm.old}"><br>
    <input type="submit" value="送信">
</form>
```

#### ③ データの流れのイメージ

データの流れを図にすると、次のようになります。
ここでは、form メソッドの引数である <font color="red">**testForm**</font> が受け渡しされています。
![2021-04-25 144615.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/4c9c2725-fe48-5a10-7252-098c5fd9bcd8.png)

### 5-2-2. データベースへの登録

次に、ユーザーからの新規登録のリクエストを受けた場合の処理になります。つまり、CRUD の **Create** の部分となります。
ユーザーが、フォームにデータを入力して送信ボタンを押すと、次のように、リクエストURLは「**/sample/form**」、HTTP メソッドは「**POST**」でデータが送信されます。

```html:/sample/form.html（抜粋）
<form method="post" action="#" th:action="@{/sample/form}" th:object="${testForm}">
```

#### ① Controller のソースコード（抜粋）

データの送信を受けると、Controller の create メソッドに処理が渡されます。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//中略
	@PostMapping("/form")
	public String create(TestForm testForm) {
		String sql = "INSERT INTO test_table(name, old) VALUES(?, ?);";
		jdbcTemplate.update(sql, testForm.getName(), testForm.getOld());
		return "redirect:/sample";
	}
}
```

**create メソッド** の中身を見てみると、最初の2行で、次の処理を行っています。
・[JdbcTemplateクラス](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html)を使用してデータベースに接続（使用メソッドは update）
・Client から受け取った **testForm** のデータを元に SQL 文を実行して、データベースに新たなレコードを登録

どういう仕組みで Client から送信されたデータが **testForm** に格納されるのかはいまいち分かりませんが、引数に設定することでデータの取得ができます。

最後の `return` では、リダイレクト先として `/sample` を指定しています。
これにより、クライアントから自動的にリクエストURL `/sample`（HTTP メソッドは GET） へのアクセスが実行され、Controller の index メソッドが実行され、一覧ページが表示されることになります。

#### ② データの流れのイメージ

登録（CREATE）におけるデータの流れを図にすると、次のようになります。
ここでは、create メソッドの引数である <font color="red">**testForm**</font> がデータ受け渡しの役割を担っています。

![2021-04-24 113843.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/dc883cd0-ef13-60a6-b4dd-f1e62fed144f.png)

## 5-3. 更新機能（UPDATE）

次に、CRUD の **Update**（更新）についてです。
まず、最初に編集フォームを表示する必要があるので、その部分から確認していきます。

### 5-3-1. 編集フォームの表示

編集フォームの表示するには、ユーザーが編集を行うデータを、データベースから取得する必要があります。
データを特定するために、リクエスト URL の一部（`id` の部分）を使用し、フォームの表示するデータを受け渡すために、フォームクラス（`TestForm.java`）を使用します。
![2021-04-24 132143.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0dcbb171-20b7-8115-ef0d-d753a9843c6f.png)

#### ① Controller のソースコード（抜粋）

編集フォームを表示する場合、ユーザーは、リクエストURL「**/sample/edit/{id}**」、HTTPメソッド「**GETメソッド**」でアクセスすることになります。
この場合は、**edit メソッド**に処理が渡されます。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//編集フォームの表示
	@GetMapping("/edit/{id}")
	public String edit(@ModelAttribute TestForm testForm, @PathVariable int id) {
		String sql = "SELECT * FROM test_table WHERE id = " + id;
		Map<String, Object> map = jdbcTemplate.queryForMap(sql);
		testForm.setId((int)map.get("id"));
		testForm.setName((String)map.get("name"));
		testForm.setOld((int)map.get("old"));
		return "sample/edit";
	}
}
```

アノテーション`＠GetMapping("/edit/{id}")` のパスのうち、波括弧で囲んだ **{id}** の部分は、`＠PathVariable` を使用することで変数として受け取ることができます。

引数に指定しているフォームクラス testForm には、アノテーション`＠ModelAttribute`を付けて **Model** に追加しています。

**edit メソッド** の中身を見てみると、最初の2行で次の処理を行っています。
・[JdbcTemplateクラス](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html)を使用してデータベースに接続（使用メソッドは queryForMap）
・リクエスト URL に付された **{id}** を元に編集対象となるレコードを取得し **map** に格納

次の3行で、**map** のデータの要素を1つずつ **testForm** に格納しています。
この testForm に格納されたデータが、**Model** を介して View に渡されることになります。 

最後の `return` では、一覧表示に使用するテンプレートを `sample/edit.html` と指定しています。

#### ② View のソースコード（抜粋）

Controller から命令を受けた View は、`/src/main/resources/templates` フォルダから **sample/edit.html** を探し出します。
**Model** から取得したフォームクラスのインスタンス `testForm` を、以下のようにセットして画面を作成します（Thymeleaf を使用）。

```html:/sample/edit.html（抜粋）
<form method="post" action="#" th:action="@{'/sample/edit/' + ${testForm.id}}" th:object="${testForm}">
    <label for="name">名前</label>
    <input type="text" id="name" name="name" th:value="${testForm.name}"><br>
    <label for="old">年齢</label>
    <input type="text" id="old" name="old" th:value="${testForm.old}"><br>
    <input type="submit" value="送信">
</form>
```

#### ③ データの流れのイメージ

データの流れを図にすると、次のようになります。
ここでは、edit メソッドの引数である <font color="red">**id**</font> 及び <font color="red">**testForm**</font> が、データの受け渡しを担っています。
![2021-04-25 151543.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/8a982d92-0422-dd72-1725-668bfea21123.png)

### 5-3-2. データベースの更新

次に、ユーザーからのデータ更新のリクエストを受けた場合の処理になります。これは、CRUD の **Update** の部分となります。
ユーザーが、フォーム上でデータを修正して送信ボタンを押すと、次のように、リクエストURLは「**/sample/edit/{id}**」、HTTP メソッドは「**POST**」でデータが送信されます。

```html:/sample/edit.html（抜粋）
<form method="post" action="#" th:action="@{'/sample/edit/' + ${testForm.id}}" th:object="${testForm}">
```

#### ① Controller のソースコード（抜粋）

データの送信を受けると、Controller の update メソッドに処理が渡されます。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//編集データの保存
	@PostMapping("/edit/{id}")
	public String update(TestForm testForm, @PathVariable int id) {
		String sql = "UPDATE test_table SET name = ?, old = ? WHERE id = " + id;
		jdbcTemplate.update(sql, testForm.getName(), testForm.getOld());
		return "redirect:/sample";
	}
}
```

**update メソッド** の中身を見てみると、最初の2行で次の処理を行っています。
・[JdbcTemplateクラス](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html)を使用してデータベースに接続（使用メソッドは update）
・Client から受け取った **id** 及び **testForm** のデータを元に SQL 文を実行してデータベースのレコードを更新

最後の `return` では、リダイレクト先として `/sample` を指定しています。
これにより、一覧ページが表示されることになります。

#### ② データの流れのイメージ

更新（UPDATE）におけるデータの流れを図にすると、次のようになります。
ここでは、update メソッドの引数である  <font color="red">**id**</font> 及び <font color="red">**testForm**</font> がデータ受け渡しの役割を担っています。

![2021-04-24 114031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/6c526496-376f-a33c-8ceb-e3825566760c.png)

## 5-4. 削除機能（DELETE）

最後に、ユーザーからのデータ削除のリクエストを受けた場合の処理になります。これは、CRUD の **Delete** の部分となります。

ユーザーが、一覧表示画面（`/sample`）の**削除**ボタンを押すと、次のように、リクエストURLは「**/sample/delete/{id}**」、HTTP メソッドは「**POST**」でリクエストが送信されます。

```html:/sample/index.html（抜粋）
<form action="#" th:action="@{'/sample/delete/' + ${test.id}}" method="post">
    <button>削除</button>
</form>
```

#### ① Controller のソースコード（抜粋）

データの送信を受けると、Controller の delete メソッドに処理が渡されます。

```java:TestController.java（抜粋）
@Controller
@RequestMapping("/sample")
public class TestController {
	//データの削除
	@PostMapping("/delete/{id}")
	public String delete(@PathVariable int id) {
		String sql = "DELETE from test_table WHERE id = " + id;
		jdbcTemplate.update(sql);
		return "redirect:/sample";
	}
}
```

**delete メソッド** の中身を見てみると、最初の2行で次の処理を行っています。
・[JdbcTemplateクラス](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html)を使用してデータベースに接続（使用メソッドは update）
・リクエスト URL から取得した **id** を元に SQL 文を実行して、データの削除を実行

最後の `return` では、リダイレクト先として `/sample` を指定しています。
これにより、一覧ページが表示されることになります。

#### ② データの流れのイメージ

削除（DELETE）におけるデータの流れを図にすると、次のようになります。
ここでは、delete メソッドの引数である  <font color="red">**id**</font> がデータ受け渡しの役割を担っています。
![2021-04-24 114108.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/f4b20760-420a-7daa-81c7-7dd943454850.png)

# さいごに

以上、学習のアウトプットとして書いてみましたが、謎は深まるばかりです。
お気づきのことがあれば、ご教示いただけると幸いです。