商品情報を表示する
この章のゴール
- Controller から View にデータを渡せるようになる
- Thymeleaf の基本(変数展開、繰り返し、条件分岐)を理解する
- Java のオブジェクトを使ってコードを整理できるようになる
1. 前章の課題を振り返る
前の章では /product/{id} にアクセスすると
URL の ID に応じてコンソールに出力されることを確認した。
ただし、表示されるページ内容は固定だった。
たとえば /product/1 と /product/2 にアクセスしても同じ内容だった。
この章では、id に応じて 異なる商品情報を表示できるようにする。
2. Controller から View に値を渡す
Spring では、Model に値を登録することで View に渡せる。
model.addAttribute("キー", 値) の形で指定し、Thymeleaf で表示できる。
ProductController の修正
前章で作成した ProductController に、Model を利用するコードを追加する。
📘 ポイント
Modelに登録した値は View(HTML)で${キー}として使える。- ここでは仮のデータをべた書きしている。
- ID が 1、2 以外の場合は「未登録の商品」として表示する。
3. 商品詳細ページ(detail.html)を修正する
src/main/resources/templates/product/detail.html を修正し、
Model で渡した値を Thymeleaf で表示する。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title th:text="'商品詳細 - ' + ${name}">商品詳細</title>
</head>
<body>
<h1>商品詳細ページ</h1>
<p>商品ID:[[${id}]]</p>
<p>商品名:[[${name}]]</p>
<p>価格:[[${#numbers.formatDecimal(price, 0, 'COMMA', 0, 'POINT')}]]円</p>
<a href="/products">▶ 商品一覧へ戻る</a>
</body>
</html>
📘 ポイント
[[${...}]]で変数を埋め込む。#numbers.formatDecimalにより金額をカンマ区切りで表示できる。- この時点で
/product/1と/product/2にアクセスすると表示が変わる。
4. 商品一覧ページを動的にする
同様に、/products の一覧ページも動的にしてみる。
ここでは Thymeleaf の th:each(繰り返し)を使う。
ProductController に一覧データを追加
com.example.ecsample.controller.ProductController の showList メソッドを以下のように修正。
list.html の修正
src/main/resources/templates/product/list.html を以下のように修正。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>商品一覧</title>
</head>
<body>
<h1>商品一覧ページ</h1>
<ul>
<li th:each="product : ${products}">
<a th:href="'/product/' + ${product[0]}">
[[${product[1]}]]([[${#numbers.formatDecimal(product[2], 0, 'COMMA', 0, 'POINT')}]]円)
</a>
</li>
</ul>
<a href="/">▶ トップページに戻る</a>
</body>
</html>
📘 ポイント
th:eachはコレクションや配列をループする。product[0]は ID、product[1]は商品名、product[2]は価格。/product/{id}にリンクして詳細ページに遷移できる。
5. Productクラスを作成してリファクタリングする
これまでの商品データは、配列で直接値を持たせていた。
たとえば次のように、何が何の値かが 見ただけでは分かりにくい 状態だった。
String[][] products = {
{"1", "コーヒーカップ", "1200"},
{"2", "ティーポット", "2400"},
{"3", "マグカップ", "1500"}
};
このように数値や文字列を並べると、
"1" が ID なのか価格なのか、コードを読まないと判断できない。
フィールドが増えるたびに修正箇所も増え、ミスが起きやすい。
また、ビュー側でも「product[0] がIDで product[2] が価格」と覚えていなければならず、
修正や拡張の際に間違いが起きやすい。
💡 改善:商品を「1つのオブジェクト」として扱う
そこで、商品を「1つのまとまり」として表すために、Product クラスを定義する。
これにより、product.getName() や product.getPrice() のように
意味のある名前でデータを扱えるようになる。
また、Thymeleaf では [[${product.name}]] のように書くと、
自動的に product.getName() を呼び出して値を取得できる。
Product.java の作成
src/main/java/com/example/ecsample/entity/Product.java を作成する。
package com.example.ecsample.entity;
public class Product {
private int id;
private String name;
private int price;
public Product(int id, String name, int price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() { return id; }
public String getName() { return name; }
public int getPrice() { return price; }
}
ProductController の修正
リストや詳細ページの処理を Product オブジェクトで表現するように変更する。
detail.html の修正
Thymeleaf では、[[${product.field}]] で Product の getter を呼び出せる。
これにより、より意味のあるコードで表示できる。
list.html の修正
th:each を使って、List<Product> の内容をループ処理で表示できるようにする。
📘 ここでの学び
- 商品データをクラス化すると、コードの意味が明確になり、変更にも強くなる。
- Thymeleaf では
product.fieldの形で getter を呼び出せるため、テンプレートも読みやすい。 - これが オブジェクト指向 の基本的な考え方であり、
この後の章で Service層 に処理を分離して、さらに整理していく。
6. まとめ
Modelに値を追加して View に渡す方法を学んだ。- Thymeleaf で変数展開、繰り返し、条件分岐を実践した。
- Java クラスを導入し、オブジェクト指向で整理する流れを体験した。
7. Gitでコミットを作成する
ここまでの変更を保存し、コミットを取る。
git add .
git commit -m "Modelを使って商品情報を表示、Productクラスを導入してリファクタ"
練習問題
商品詳細ページに「在庫メッセージ」を表示しよう
仕様
- 各商品に在庫数を追加し、在庫数に応じて表示内容を変える。
- 表示メッセージの条件は次の通り:
| 在庫数 | 表示メッセージ |
|---|---|
| 0個 | 「在庫切れです」 |
| 1〜9個 | 「残りわずかです」 |
| 10個以上 | 「在庫あり」 |
実装ヒント
Productクラスにstockフィールドを追加し、getterを用意する。- コントローラで在庫数を設定した
Productオブジェクトを渡す。 - Thymeleaf の
th:if/th:unlessを使って在庫メッセージを条件分岐する。
出力例
URL:http://localhost:8080/product/1
表示:
<p>商品名:コーヒーカップ</p>
<p>価格:1,200円</p>
<p>在庫状況:残りわずかです</p>
💡 補足
Thymeleafでは、条件分岐を次のように書ける。
<p th:if="${product.stock == 0}">在庫切れです</p>
<p th:if="${product.stock > 0 and product.stock < 10}">残りわずかです</p>
<p th:if="${product.stock >= 10}">在庫あり</p>