ループ処理(th:each)の基本を完全ガイド!Thymeafの繰り返し処理の使い方
新人
「Spring MVCで複数のデータを一覧表示したいんですが、どうすればいいですか?」
先輩
「Thymeleafのth:eachを使えば簡単にループ処理でリストを表示できるんだ。」
新人
「th:eachって何ですか?どんなふうに使うんですか?」
先輩
「それじゃあ、基本的な使い方を一緒に見ていこう!」
1. ループ処理とは?
ループ処理とは、同じ処理を繰り返し実行する方法です。例えば、商品の一覧やユーザーのリストなど、複数のデータを表示するときに便利です。プログラミングにおいては非常に基本的な考え方であり、forやwhileなどの構文を使って実現します。
2. th:eachとは何か?
th:eachは、Thymeleafでループ処理を実現するための属性です。Spring MVCでコントローラからリストデータを渡すことで、HTML内で繰り返し要素を生成できます。
以下は、th:eachを使った簡単なリスト表示の例です。
<ul>
<li th:each="item : ${items}" th:text="${item}"></li>
</ul>
このコードでは、${items}というリスト内の要素を順番に取り出し、各要素をリスト項目として表示しています。
3. th:eachを使うメリット
th:eachを使うことで、HTML内で動的にデータを表示できるようになります。特に以下のようなメリットがあります。
- コードが簡潔になり、メンテナンスがしやすくなる
- コントローラから渡されたデータを自動的に繰り返し表示できる
- JavaコードとHTMLの分離ができ、コードの可読性が向上する
例えば、ユーザー一覧や商品カタログの表示に非常に便利です。Spring MVCとThymeleafを組み合わせることで、動的なWebアプリケーションの作成が容易になります。
4. th:eachを使ったリスト表示の基本的な実例
ここでは、th:eachを使ってユーザー名のリストを表示する実例を紹介します。Spring MVCのコントローラからデータを渡し、HTMLでリストを表示します。
【コントローラの作成】
@Controller
public class UserController {
@GetMapping("/users")
public String showUsers(Model model) {
List<String> users = List.of("田中太郎", "山田花子", "佐藤次郎");
model.addAttribute("users", users);
return "user-list";
}
}
【HTMLファイル(user-list.html)の作成】
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ユーザー一覧</title>
</head>
<body>
<h2>ユーザー一覧</h2>
<ul>
<li th:each="user : ${users}" th:text="${user}"></li>
</ul>
</body>
</html>
この例では、コントローラからusersという名前でリストを渡し、th:eachを使ってHTML上に表示しています。画面には以下のように表示されます。
田中太郎
山田花子
佐藤次郎
5. インデックスを利用した表示方法
th:eachでは、リスト内の要素だけでなくインデックス番号(要素の順番)を取得することもできます。これは、項番を表示したいときに便利です。
【HTMLでインデックスを使った例】
<table border="1">
<thead>
<tr>
<th>番号</th>
<th>ユーザー名</th>
</tr>
</thead>
<tbody>
<tr th:each="user, iterStat : ${users}">
<td th:text="${iterStat.index + 1}"></td>
<td th:text="${user}"></td>
</tr>
</tbody>
</table>
このコードでは、iterStatという変数でループの状態を取得し、iterStat.indexを使ってインデックス番号を表示しています。結果は次のようになります。
1 田中太郎
2 山田花子
3 佐藤次郎
これにより、ユーザーリストに連番をつけて表示することができます。
6. ネストしたループ処理の方法
データの中にさらにリストがある場合、th:eachをネスト(入れ子構造)してループ処理を実行することができます。例えば、各ユーザーが複数の趣味を持っている場合の表示例を紹介します。
【コントローラの作成】
@Controller
public class UserController {
@GetMapping("/user-hobbies")
public String showUserHobbies(Model model) {
Map<String, List<String>> userHobbies = new LinkedHashMap<>();
userHobbies.put("田中太郎", List.of("読書", "ジョギング"));
userHobbies.put("山田花子", List.of("映画鑑賞", "料理"));
userHobbies.put("佐藤次郎", List.of("釣り", "サイクリング"));
model.addAttribute("userHobbies", userHobbies);
return "user-hobbies";
}
}
【HTMLファイル(user-hobbies.html)の作成】
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>ユーザーと趣味一覧</title>
</head>
<body>
<h2>ユーザーとその趣味</h2>
<ul>
<li th:each="entry : ${userHobbies}">
<strong th:text="${entry.key}"></strong>
<ul>
<li th:each="hobby : ${entry.value}" th:text="${hobby}"></li>
</ul>
</li>
</ul>
</body>
</html>
この例では、最初のth:eachでユーザー名を取り出し、内側のth:eachで趣味リストをループしています。結果は以下のように表示されます。
田中太郎
- 読書
- ジョギング
山田花子
- 映画鑑賞
- 料理
佐藤次郎
- 釣り
- サイクリング
このようにネストしたループを使うことで、階層構造を持つデータも簡単に表示することができます。
7. th:eachを使う際のよくあるエラーとその対処法
Thymeleafのth:eachを使用する際、初心者がよくつまずくエラーがあります。ここでは、よくあるエラーとその解決方法について詳しく解説します。
エラー1: th:eachで表示されない
th:eachでループが動作しない場合、最も多い原因はコントローラでデータを正しく渡していないことです。
// 誤り例: モデルに属性がない、名前が異なる
@GetMapping("/users")
public String showUsers(Model model) {
return "user-list"; // users属性が渡されていない
}
解決策: コントローラでmodel.addAttribute("users", users)を正しく記述してください。
@GetMapping("/users")
public String showUsers(Model model) {
List<String> users = List.of("田中太郎", "山田花子");
model.addAttribute("users", users);
return "user-list";
}
エラー2: 変数名の不一致
HTML側でth:each="item : ${items}"としているのに、コントローラ側でmodel.addAttribute("users", users)としている場合、データが表示されません。
解決策: HTMLとコントローラの変数名を一致させましょう。
エラー3: nullポインタ例外
リストがnullの場合、th:eachでエラーが発生します。
解決策: 空リストを返すか、nullチェックを行います。
List<String> users = Optional.ofNullable(getUsers()).orElse(List.of());
8. th:eachを使ったベストプラクティスと注意点
より保守性が高く、バグの少ないコードを書くために、以下のポイントを押さえましょう。
1. 適切な変数名を使う
th:each="user : ${users}"のように、ループ内の変数名は意味のあるものにしましょう。可読性が向上します。
2. インデックスを活用する
インデックスを利用して番号付きリストや奇数偶数行の色分けが可能です。
<tr th:each="user, iterStat : ${users}" th:class="${iterStat.even}? 'even' : 'odd'">
<td th:text="${iterStat.index + 1}"></td>
<td th:text="${user}"></td>
</tr>
3. Null安全性を確保する
コントローラでリストがnullにならないように処理をしましょう。
4. データサイズに注意
大量のデータを一度に表示するとブラウザが重くなるため、ページネーションを導入するのが理想です。
9. 実践!簡単な商品一覧表示アプリの作成例
最後に、th:eachを使った簡単な商品一覧表示アプリを作成してみましょう。
【商品クラスの作成】
public class Product {
private String name;
private int price;
public Product(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public int getPrice() { return price; }
}
【コントローラの作成】
@Controller
public class ProductController {
@GetMapping("/products")
public String showProducts(Model model) {
List<Product> products = List.of(
new Product("ノートパソコン", 120000),
new Product("スマートフォン", 80000),
new Product("イヤホン", 5000)
);
model.addAttribute("products", products);
return "product-list";
}
}
【HTMLファイル(product-list.html)の作成】
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>商品一覧</title>
</head>
<body>
<h2>商品一覧</h2>
<table border="1">
<thead>
<tr>
<th>番号</th>
<th>商品名</th>
<th>価格 (円)</th>
</tr>
</thead>
<tbody>
<tr th:each="product, iterStat : ${products}">
<td th:text="${iterStat.index + 1}"></td>
<td th:text="${product.name}"></td>
<td th:text="${product.price}"></td>
</tr>
</tbody>
</table>
</body>
</html>
上記のコードを実行すると、以下のような商品一覧が表示されます。
1 ノートパソコン 120000
2 スマートフォン 80000
3 イヤホン 5000
【ポイント】
- 商品リストは
th:eachでループ処理しています。 - インデックスを利用して連番を表示しています。
- 商品名と価格を正しく取得して表示しています。
Pleiades上でGradleを用いて実行すれば、すぐに確認ができます。依存関係もPleiadesのチェック機能で簡単に追加できるため、初心者でも取り組みやすいです。
まとめ
ここまでThymeleafのth:eachを中心に繰り返し処理の基本から応用までを段階的に確認してきましたが実際に手を動かしながら学ぶことで繰り返し処理がどれほど多くの場面で役に立つのかを実感できたはずです。とくにリストデータを扱う画面ではユーザー一覧商品一覧カテゴリ一覧など多くの場面で繰り返し処理が登場しそのたびに同じようなHTMLコードを書かずに済むという利点があります。th:eachはSpringMVCとThymeleafの組み合わせによってサーバー側のデータをシンプルかつ自然な形で画面に反映できるためWebアプリケーション開発において欠かせない仕組みです。またコントローラで渡したモデル属性をそのままHTMLに反映できるため初心者でも理解しやすく複数データの出力に慣れることで画面設計そのものを柔軟に考える力が身に付きます。
th:eachは単純なループ表示だけでなくインデックスを利用した番号付けや奇数偶数行の色分け入れ子構造のデータ表示など多彩な表現に対応できるところも魅力です。特にiterStatを活用することで番号の表示ループ状態の取得行ごとのスタイル変更など視認性を向上させる工夫が簡単にできるため実務でも頻繁に利用されるテクニックとなっています。データが増えたときにも柔軟に対応できる点はテンプレートエンジンとしてのThymeleafの強みでありスクリプトを使わずにテンプレートだけで多くの処理が完結するため保守性や可読性が高まります。またコントローラ側の変数名とHTML側の参照名を一致させることやnullにならないリストを渡すことなど基本的なルールを守ることでエラーの発生を最小限に抑えることができ安定した開発にもつながります。
実践例として紹介した商品一覧表示やユーザーごとの趣味一覧などは現場でもよく使われるパターンであり特に入れ子構造のループ処理はデータベースのテーブル構造とも相性が良いため業務システム構築の際に必ず必要になる知識です。Thymeleafを使うことでテンプレートの中で自然にループを表現できHTML構造を崩さずにきれいな形でデータを表示できるためフロントエンドとサーバーサイドの連携がスムーズになります。さらにSpringMVCと合わせて利用することでモデル属性を明示的に渡しながら視覚的にも理解しやすいテンプレートを作ることができプロジェクトメンバー全員が把握しやすい構造を維持できます。
また今回紹介したエラー対処法の部分は実務において特に重要であり変数名の不一致やnullリストによる例外などは非常に起きやすい問題であるため早い段階で身につけておくことでトラブルを防ぎ開発効率を高めることができます。特にモデルへ属性を追加し忘れるミスはよくあるためコントローラとHTMLの関係を常に確認しながら開発する習慣を身につけておくとよいでしょう。ページネーションデータサイズの最適化ネスト構造の整理などのポイントも今後より複雑な画面を作る際に役立ちます。
最後に復習としてth:eachを使ったコンパクトなサンプルコードを示します。基本構造をもう一度確認しながらループ処理の理解を深めてみてください。
ループ処理のサンプルコード
<ul>
<li th:each="item, iterStat : ${items}">
<span th:text="${iterStat.index + 1}"></span> -
<span th:text="${item}"></span>
</li>
</ul>
@GetMapping("/sample-loop")
public String sampleLoop(Model model) {
List<String> items = List.of("赤い花", "青い空", "白い雲");
model.addAttribute("items", items);
return "sample-loop";
}
このようにコントローラからリストを渡しテンプレートでth:eachを使って繰り返し表示するという基本パターンを理解しておくことで実務でも多くの画面をスムーズに実装できるようになります。データの扱い方とテンプレートの仕組みをしっかり学んでおくことで今後のSpringMVC開発がより円滑に進みます。
生徒:きょうはth:eachの仕組みがかなり理解できた気がします特にインデックスの使い方が便利でした。
先生:その感想はとても良いねインデックスを活用できると画面表示に幅が出て実践的な一覧画面を作れるようになるよ。
生徒:ネストしたループも思ったより自然に書けて驚きましたデータの階層がそのまま表現できるんですね。
先生:その通り階層データを扱う場面は多いからネストを理解しておくと今後必ず役に立つよ。
生徒:エラーの原因も知れてよかったです変数名の不一致はよくやってしまいそうなので気をつけます。
先生:最初は誰でも同じミスをするから大丈夫大事なのは仕組みを理解して丁寧に確認する習慣をつけることだね。
生徒:次はページネーションも試してみたいですもっと実践的な一覧画面を作れるようになりたいです。
先生:いいねぜひ挑戦してみようth:eachに慣れた今ならきっとスムーズに理解できるはずだよ。