Thymeleafを使用すると、データベース等から取得したデータを表示する動的なサイトを簡単に作ることができます。今回はデータをhtmlのテキストや属性に設定するときに使用するThymeleafの”変数式“について紹介します。
開発環境
・Spring Boot:2.6.2
・Thymeleaf:3.0.14.RELEASE
・Java:1.8
変数式について
変数式は単純式のひとつ
変数式はThymeleafで用意されている”単純式(Simple Expressions)“の一つです。
単純式はhtmlの属性に値やオブジェクトを渡す際に使用する式で、変数式以外に下記のものが用意されています
- 選択変数式(Selection Variable Expressions)
- メッセージ式(Message Expressions)
- リンクURL式(Link URL Expressions)
- フラグメント式(Fragment Expressions)
これらについては別の記事にて説明します。
変数式のメリット
変数式を用いることで、Modelに格納した値をhtmlのテキストや各属性に動的に設定できます。
JavaScriptを使用しても実現は可能ですが、変数式を用いるとhtmlだけで記載が完結するためコードがシンプルでわかりやすくなります。
実際にpタグのテキストを変更するコードで比較してみましょう。
〇JavaScriptで実現する場合
<p id="fruit">apple</p>
const p = document.getElementById('fruit');
p.textContent = 'orange';
JavaScriptではgetElementByIdにて取得したpタグにtextContentで新たな値 ‘orange’ を設定しています。
〇Thymeleafで実現する場合
/* 文字列'orange'が設定された fruit が Model に格納されている場合 */
<p th:text="${fruit}">apple</p>
Thymeleafの実装はコメント行を除いた1行で記載が完了しており、テキストにfruitの値が設定されるということが理解しやすいと思います。
変数式の記載方法
基本
Thymeleafで実現する例で記載したように、先頭に”$“をつけて”{}“で変数名を囲みます。
また変数式はThymeleafで用意されている独自の属性を使用するため、下記の2行目のようにxmlネームスペース(xmlns)を設定する必要があります。
使用できる独自の属性はたくさんありますが、今回は一番シンプルな”text”という属性を使用します。”text”は画面に表示する値を渡したいときに使用する属性で、pタグではコンテンツ部分に相当します。
/* prefixには"th"がよく使用される */
<html xmlns:th="http://www.thymeleaf.org" >
/* headタグやbodyタグは省略 */
/* 基本の記載方法 prefix:属性="${変数名}" */
<p th:text="${fruit}"></p>
“{}”の中の記載方法はアクセスしたい変数の構造(リストやマップ等)によって変わってきます。ここからはそんな各変数に対する記載方法を説明します。(以降、xmlnsやhead、bodyタグは省略)
文字列や数値
変数に文字列や数値がそのまま格納されている場合は基本の記載方法でアクセスが可能です。
Java側から”fruit”と”price”という変数をmodelに設定してhtmlに渡しています。
// modelは「org.springframework.ui.Model」
model.addAttribute("fruit", "orange");
model.addAttribute("price", 100);
<p th:text="${fruit}"></p>
<p th:text="${price}"></p>
〇結果
リストの各要素
変数がリストになっている場合、”変数名[インデックス]“で各要素にアクセスが可能です。
Java側から”nameList”と”priceList”というリスト変数をmodelに設定してhtmlに渡しています。
// nameList、priceListは「java.util.List」
nameList.add("melon");
priceList.add(600);
nameList.add("water melon");
priceList.add(500);
// modelは「org.springframework.ui.Model」
model.addAttribute("nameList", nameList);
model.addAttribute("priceList", priceList);
<p th:text="${nameList[0]}"></p>
<p th:text="${priceList[0]}"></p>
<p th:text="${nameList[1]}"></p>
<p th:text="${priceList[1]}"></p>
〇結果
マップの各値
変数がマップになっている場合、”変数名.キー“で各値にアクセスが可能です。
Java側から”fruit”と”price”というキーを持ったマップ変数”fruitMap”をmodelに設定してhtmlに渡しています。
// mapは「java.util.Map」
map.put("fruit", "banana");
map.put("price", 90);
// modelは「org.springframework.ui.Model」
model.addAttribute("fruitMap", map);
<p th:text="${fruitMap.fruit}"></p>
<p th:text="${fruitMap.price}"></p>
〇結果
また”変数名.キー”のほかに”変数名[キー]“という記載でもアクセス可能です。そのため下記の記載でも同じ結果が出力されます。
<p th:text="${fruitMap[fruit]}"></p>
<p th:text="${fruitMap[price]}"></p>
リストに格納されているリストの各要素
リストの中に格納されたリストの各要素にアクセスしたい場合、”${リスト[インデックス][インデックス]}“と記載します。
Java側から”list1″の最初と2番目の要素にそれぞれ”list1_1″、”list1_2″を格納し、modelに設定してhtmlに渡しています。
// list1、list1_1、list1_2は「java.util.List」
list1_1.add("grape");
list1_1.add("muscat");
list1_2.add("apple");
list1_2.add("pear");
list1.add(list1_1);
list1.add(list1_2);
// modelは「org.springframework.ui.Model」
model.addAttribute("list", list1);
/* list[n]でリスト変数を取得し、その変数にインデックスを使用して各要素にアクセス */
<p th:text="${list[0][0]}"></p>
<p th:text="${list[0][1]}"></p>
<p th:text="${list[1][0]}"></p>
<p th:text="${list[1][1]}"></p>
〇結果
リストに格納されているマップの各値
リストの中に格納されたマップの各値にアクセスしたい場合、”${リスト[インデックス].キー}“(もしくは”${リスト[インデックス][キー]}“)と記載します。
「org.springframework.jdbc.core.JdbcTemplate」を使う際に、データベースからこの構造でレコードを取得することが多いため覚えておくと便利です。
Java側から”list”の最初と2番目の要素にそれぞれ”fruitMap”、”vegetableMap”を格納し、modelに設定してhtmlに渡しています。
// listは「java.util.List」
// fruitMap、vegetableMapは「java.util.Map」
fruitMap.put("fruit", "strawberry");
fruitMap.put("price", 180);
vegetableMap.put("vegetable", "carrot");
vegetableMap.put("price", 120);
list.add(fruitMap);
list.add(vegetableMap);
// modelは「org.springframework.ui.Model」
model.addAttribute("list", list);
/* list[n]でマップ変数を取得し、その変数のキー'fruit'、'vegetable'、'price'を使用してアクセス */
<p th:text="${list[0].fruit}"></p>
<p th:text="${list[0].price}"></p>
<p th:text="${list[1].vegetable}"></p>
<p th:text="${list[1].price}"></p>
〇結果
マップに格納されているリストの各要素
マップの中に格納されたリストの各要素にアクセスしたい場合、”${マップ.キー[インデックス]}“(もしくは”${マップ[キー][インデックス]}“)と記載します。
Java側から”map”に”fruitList”を格納し、modelに設定してhtmlに渡しています。
// fruitListは「java.util.List」
// mapは「java.util.Map」
fruitList.add("pineapple");
fruitList.add("mango");
map.put("list", fruitList);
// modelは「org.springframework.ui.Model」
model.addAttribute("map", map);
/* map.listでリスト変数を取得し、その変数にインデックスを使用して各要素にアクセス */
<p th:text="${map.list[0]}"></p>
<p th:text="${map.list[1]}"></p>
〇結果
マップに格納されているマップの各値
マップの中に格納されたリストの各要素にアクセスしたい場合、”${マップ.キー.キー}“(もちろんこちらも”.キー“を”[インデックス]“にしてもOK)と記載します。
Java側から”map”に”fruitMap”を格納し、modelに設定してhtmlに渡しています。
// map、fruitMapは「java.util.Map」
fruitMap.put("fruit", "kiwi");
fruitMap.put("price", 200);
map.put("fruitMap", fruitMap);
// modelは「org.springframework.ui.Model」
model.addAttribute("map", map);
/* map.fruitMapでマップ変数を取得し、その変数のキー'fruit'、'price'を使用してアクセスしている */
<p th:text="${map.fruitMap.fruit}"></p>
<p th:text="${map.fruitMap.price}"></p>
〇結果
オブジェクトのフィールド
オブジェクトのフィールドにアクセスする場合、そのオブジェクトに用意されたgetterメソッドを使用してアクセスします。ここで注意すべき点は記載する”{}”に記載する文字はフィールド名ではなくgetterメソッド名に合わせるということです。
クラス”Fruit”ではフィールドに”name”と”price”を用意していますが、フィールドとgetterメソッドどちらでアクセスしているかわかりやすいようにgetterメソッドの名前を少し変更しています。getterメソッドを呼び出す際には、getterメソッド名から’get’を取り除いた文字列を記載します。
public class Fruit {
// フィールド
private String name;
private int price;
// nameのgetter
public String getFruitName() {
return name;
}
// nameのsetter
public void setFruitName(String name) {
this.name = name;
}
// priceのgetter
public int getFruitPrice() {
return price;
}
// priceのsetter
public void setFruitPrice(int price) {
this.price = price;
}
}
Fruit fruit = new Fruit();
fruit.setFruitName = "lemon";
fruit.setFruitPrice = 150;
model.addAttribute("fruit", "fruit");
/* getterメソッドの'get'を取り除いた文字列を使用する(最初の文字のみ小文字にしてもよい) */
<p th:text="${fruit.fruitName}"></p>
<p th:text="${price.fruitPrice}"></p>
(getter名と変数名が異なる場合に)変数名を記載したり、最初以外の文字列の小文字/大文字を変更してしまうとエラーとなってしまうため注意しましょう。
〇結果
まとめ
変数式は”${…}”を使用し、以下のルールで変数にアクセスします。
- 文字列、数値の場合
- ${変数名}と記載する
- リスト、マップの場合
- ${リスト[インデックス]}、${マップ[キー]}と記載する
- マップ、オブジェクトのフィールドの場合
- ${マップ.キー}、${オブジェクト.getter名(‘get’の文字列を除いた)}と記載する
またマップやリストの複合型についてもアクセス方法を示しましたが、記載を細分化していけば上記3つのルールでアクセスが可能となります。
以上のことを踏まえれば、様々な構造の変数にアクセスが可能となります。動的なサイトを作成する際に非常に便利な機能なので、活用していきましょう!
コメント