18
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-04-25

はじめに

Spring Boot のデータの流れをイメージで捉えるために、次のような骨組みだけのサンプルアプリを作って、データの受け渡しを一つ一つ確認していきます。
2021-04-24 131659.png
サンプルアプリには、Create(登録)、Read(閲覧)、Update(更新)、Delete(削除)の主要4機能を全て入れるようにしますが、本記事の趣旨とは関係のない余計なコードは排除して、最小限のコード量にします。

Service や Repository は作らず、データの処理は Controller のみで手短に済ませます。
そして、次のように簡略化した MVC のイメージ図に当てはめて、CRUD のそれぞれの機能を確認していきます(下図の詳細は後述)。
2021-04-25 114510.png

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

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

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

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

<目次>
1. データベースの用意(MySQL)
2. プロジェクト作成時の設定内容
3. 作成するファイルとソースコード
4. Spring MVC のイメージ
5. 機能ごとのデータの流れのイメージ

1. データベースの用意(MySQL)

先に、MySQL のデータベースを用意しておきます。
MySQL の部分は要点のみを書きますので、詳細については 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. プロジェクト作成時の設定内容

プロジェクト作成については、設定内容を中心に書いていきます。
細かいことは前回記事に書きましたので、必要に応じて参照してみてください。

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

ここでは、ビルドツール(Type)は Gradle を、Java バージョン(Java Version)は 11 を選択しています。
プジェクト名(Name)は適当に付けておきます。
2021-04-20 210308.png

Next」ボタンを押すと、下図のライブラリを選択する画面になります。
選択するのは、「JDBC API」「MySQL Driver」「Spring Boot DevTools」「Spring Web」「Thymeleaf」の5つとなります(細かいことはこちらを参照)。
2021-04-22 225753.png
Finish」をクリックすれば、プロジェクトが作成されます。

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

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

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

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

2021-04-22 231224_1.png

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

3-2. アプリケーションクラス(自動生成)

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

mainメソッドの中身は SpringApplicationrun メソッドが記載されているだけです。
これにより、アプリケーションが起動されます。

/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 のユーザーパスワードを記載します。

その他は、上記のままで大丈夫だと思います。設定内容の詳細はこちらを参照してください。

3-5. SQLスクリプト

SQLスクリプトには、プロジェクト起動時に実行されるSQL文を記載します。
schema.sqlおよびdata.sqlには、次のような初期設定を書いておきます。
(細かいことはこちらを参照してください)

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)を作成して分担して処理すべきところですが、ここでは作成していません。
(コントローラー作成に関する細かいことはこちらを参照してください)

/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がなくとも、このサンプルアプリは動きます。

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

参考
	@Autowired
	private JdbcTemplate jdbcTemplate;

<参考サイト>
Spring FrameworkでDIする3つの方法

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

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

上記の TestControllercreate メソッドを例に、ルールを見てみます。
まず、クラスの頭に付けているアノテーション @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のカラム)と対応させたフィールドを作成します。
フォームクラスには、コンストラクタがなくても大丈夫ですが、gettersetter は必須となりますので、作成しておきます。

/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. アプリケーションの起動

アプリケーションを起動してみます(起動方法の細かいことはこちらを参照してください)。
Package Explorer上のプロジェクト名(ここではCRUDSample)を右クリックして、「Run As」→「Spring Boot App」を選択します。
Console 画面に次のような表示がされていきます。
2021-04-25 111446.png
アプリケーションが起動したら http://localhost:8080/sample にアクセスします。
次のような画面が表示されたら成功です。
2021-04-24 131659.png

4. Spring MVC のイメージ

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

4-1. 理論上のMVC

Spring MVC の図を確認する前に、まず、理論上のMVCの図を見てみます。
一般的な MVC はだいたい次のような構造として説明されています。
2021-04-24 142143.png

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

4-2. Spring MVC

数多のサイトに掲載されている Spring MVC の図が多種多様なのは、結局、簡単に図式化できるような構造ではないからだろうと思います。
とはいえ、Spring MVC のイメージを掴まないとデータの流れが見えてこないので、簡単に作図しておきます。
このあたりのサイトを参考にしています)
2021-04-24 113207.png
図で見ると、Model の存在がいまいちよく分かりません。
個人的には、右側の Business ClassData Access が Model に見えて仕方ないのですが、あくまでイメージの問題なので、深く考えないようにします。

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

2021-04-25 110340.png

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

<参考サイト>
Web MVC framework
Spring Framework Learning 05

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

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

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

5-1. 一覧表示機能(READ)

まずは、CRUD の Read(読み込み)から確認していきます。
次の画面を表示するには、データベースから、登録されているデータの一覧を取得する必要があります。
2021-04-24 131659.png

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

① Controller のソースコード(抜粋)

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

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クラスを使用してデータベースに接続(使用メソッドは queryForList)
・SQL文の実行により取得した一覧データを、List オブジェクトである list に格納(参考

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

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

② View のソースコード(抜粋)

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

/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 メソッドの引数である Model がデータ受け渡しの役割を担っています。
2021-04-25 114510.png
Controller が直接 View にデータを渡しているのではなく、 Controller が Model にデータを格納して、View は Model にデータを取りに行くというイメージです。

5-2. 登録機能(CREATE)

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

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

次の入力フォームの表示では、データベースからデータを取得する必要はありません。
ここでは、フォームの入力データを保持するためのフォームクラス(TestForm.java)の使用が必要になります。
2021-04-24 132040.png

① Controller のソースコード(抜粋)

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

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 が追加されることになります(厳密なことはこちらの記事を参照してください)。
testForm には何らの値を入れていませんので、中身は空っぽのままです。View は、この空の testFormModel を介して取得することになります。

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

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

これは、「ハンドラメソッドの引数に、フレームワーク側がサポートしていないクラスがあると自動的に @RequestParam または @odelAttribute とみなされるため」とのことです(「ModelAttributeでフォームパラメータをオブジェクトにマッピングする」より)。

<参考サイト>
Spring MVC についてまとめてみるよ!!!
はじめてのSpring MVCアプリケーション
ModelAttributeでフォームパラメータをオブジェクトにマッピングする
@ModelAttribute を使う

② View のソースコード(抜粋)

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

/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 メソッドの引数である testForm が受け渡しされています。
2021-04-25 144615.png

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

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

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

① Controller のソースコード(抜粋)

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

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クラスを使用してデータベースに接続(使用メソッドは update)
・Client から受け取った testForm のデータを元に SQL 文を実行して、データベースに新たなレコードを登録

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

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

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

登録(CREATE)におけるデータの流れを図にすると、次のようになります。
ここでは、create メソッドの引数である testForm がデータ受け渡しの役割を担っています。

2021-04-24 113843.png

5-3. 更新機能(UPDATE)

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

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

編集フォームの表示するには、ユーザーが編集を行うデータを、データベースから取得する必要があります。
データを特定するために、リクエスト URL の一部(id の部分)を使用し、フォームの表示するデータを受け渡すために、フォームクラス(TestForm.java)を使用します。
2021-04-24 132143.png

① Controller のソースコード(抜粋)

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

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クラスを使用してデータベースに接続(使用メソッドは 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 を使用)。

/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 メソッドの引数である id 及び testForm が、データの受け渡しを担っています。
2021-04-25 151543.png

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

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

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

① Controller のソースコード(抜粋)

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

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クラスを使用してデータベースに接続(使用メソッドは update)
・Client から受け取った id 及び testForm のデータを元に SQL 文を実行してデータベースのレコードを更新

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

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

更新(UPDATE)におけるデータの流れを図にすると、次のようになります。
ここでは、update メソッドの引数である id 及び testForm がデータ受け渡しの役割を担っています。

2021-04-24 114031.png

5-4. 削除機能(DELETE)

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

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

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

① Controller のソースコード(抜粋)

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

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クラスを使用してデータベースに接続(使用メソッドは update)
・リクエスト URL から取得した id を元に SQL 文を実行して、データの削除を実行

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

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

削除(DELETE)におけるデータの流れを図にすると、次のようになります。
ここでは、delete メソッドの引数である id がデータ受け渡しの役割を担っています。
2021-04-24 114108.png

さいごに

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

18
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?