Thymeleafを使用すると、データベース等から取得したデータを表示する動的なサイトを簡単に作ることができます。今回はデータをhtmlのテキストや属性に設定するときに使用するThymeleafの”選択変数式”について紹介します。
開発環境
・Spring Boot:2.6.2
・Thymeleaf:3.0.14.RELEASE
・Java:1.8
選択変数式について
まず選択変数式とは何か、そしてどんなメリットがあるのかを説明します。
選択変数式は単純式のひとつ
選択変数式はThymeleafで用意されている”単純式(Simple Expressions)“の一つです。
単純式はhtmlの属性に値やオブジェクトを渡す際に使用する式で、選択変数式の場合は最初に述べたように「データベース等から取得したデータ」を渡します。
また選択変数式の他に、下記の単純式が用意されています。
- 変数式(Variable Expressions)
- メッセージ式(Message Expressions)
- リンクURL式(Link URL Expressions)
- フラグメント式(Fragment Expressions)
詳細は各記事に記載しています。
使用するThymeleafの独自属性
選択変数式はThymeleafの独自属性とともに使用します。使用する独自属性の代表例と用途は下記のとおりです。
属性 | 用途 |
---|---|
th:object | 使用するオブジェクトを指定 |
th:value th:text 等 | 各属性、コンテンツの設定 |
th:field | id,name,value属性の自動設定 |
選択変数式はThymeleafで用意されている独自の属性を使用するため、xmlネームスペース(xmlns)を設定する必要があります。
<!--/* prefixには"th"がよく使用される */-->
<html xmlns:th="http://www.thymeleaf.org" >
上記の使い方は記載方法の項で説明します。
選択変数式のメリット①
一つ目のメリットは、記述がシンプルになり内容がわかりやすくなることです。
よく似たものに“変数式”がありますが、変数式と違う点として設定する値を「選択されたオブジェクトに格納されている値」に限定していることが挙げられます。
限定することで記述にどんな違いが出てくるのか確認してみましょう。以下の例ではJava側で入れ子のようになっているマップ変数をmodelに追加して出力しています。
○Java
// map、fruitMapは「java.util.Map」
fruitMap.put("name", "kiwi");
fruitMap.put("price", 200);
map.put("fruitMap", fruitMap);
// modelは「org.springframework.ui.Model」
model.addAttribute("map", map);
○html(変数式バージョン)
<!--/* map.fruitMapでマップ変数を取得し、その変数のキー'name'、'price'を使用してアクセスしている */-->
<p th:text="${map.fruitMap.name}"></p>
<p th:text="${map.fruitMap.price}"></p>
変数式を用いた記述ではModelに格納した値を取得するために、キー名を最初から最後まで(mapからname、priceまで)指定します。
○html(選択変数式バージョン)
<!--/* オブジェクトををmap.fruitMapに限定し、キー'name'、'price'を使用してアクセスしている */-->
<div th:object="${map.fruitMap}">
<p th:text="*{name}"></p>
<p th:text="*{price}"></p>
</div>
選択変数式の場合は、渡す値をmap.fruitMapに格納されている値に限定しているため、キー名の省略が可能となり、スッキリとした記載になります。
記述量が減るのはもちろんですが、変数式の記載と比べて、ある一つのデータが持っている二つの項目(名称、金額)を渡しているということが直感的にわかるようになりますね。
また今回は設定する値の数が少なかったため効果は薄く感じられますが、数が多くなるにつれて効果も大きくなります。
選択変数式のメリット②
二つ目のメリットは選択されたオブジェクトの使用範囲がわかりやすくなることです。
選択変数式はth:object属性をもつタグによって囲まれた範囲でのみ使用するため、その範囲でオブジェクトが使用されていることの証明にもなります。
<!--/* 下のdivタグの子要素以下でmap.fruitMapにアクセスすることがわかる */-->
<div th:object="${map.fruitMap}">
<p th:text="*{name}"></p>
<p th:text="*{price}"></p>
</div>
選択変数式の記載方法
選択変数式を使用するための記載方法を説明します。
基本
まず選択変数式を使う範囲を指定するため、th:object属性をもつ要素(例ではdivタグ)を用意します。この時、th:objectの値には要素内で使用するオブジェクトを指定します。
<div th:object="${map.fruitMap}">
<!--/* この中で選択変数式を使用する */-->
</div>
次に先ほど作った要素に子要素を追加し、設定する属性と選択変数式を記載します。選択変数式は先頭に“*”をつけて“{}”で変数名を囲むことで利用可能です。
<div th:object="${map.fruitMap}">
<p th:text="*{fruit}"></p>
<p th:text="*{price}"></p>
</div>
th:objectで囲んでいない場合は、選択変数式ではなく変数式として扱われます。つまり下の二つの記載の出力は同じになります。変数式「${…}」の代わりに「*{…}」を用いても問題ないですが、予期せぬ出力となることや選択変数式を使うメリットが薄くなってしまうことが考えられるため、なるべく使い分けたほうが良いでしょう。
<p th:text="*{name}"></p>
<p th:text="${name}"></p>
フォーム送信
選択変数式はフォーム送信を実装する際にも使用します。
フォーム送信で使用する場合は、formタグにth:objectを設定し、inputタグにth:fieldを設定します。(選択変数式はth:fieldの値に使用)
サーバ側は送信内容としてth:objectに指定したオブジェクトを受け取ることになります。th:fieldで指定した変数名はそのオブジェクトのフィールド名を示しており、一致するフィールドがあればオブジェクトに自動で格納(バインド)されます。
○Java
public class FruitForm {
// getter, setterの記載は省略
private String name;
private int price;
}
○html
<!--/* th:objectにはサーバ側で用意してあるFruitFormを指定 */-->
<form th:action="@{/index}" th:object="${fruitForm}" method="post">
<input type="text" th:field="*{name}">
<input type="number" th:field="*{price}"></p>
<input type="submit" value="送信">
</form>
記載方法は以上となります。設定する属性が変わっただけで基本と同じ記載方法なので簡単ですね。
おまけ:フォーム送信の動作イメージ
せっかくなので記載方法だけでなく、どのような工程を経てサーバ側に値が送られるのかも簡単に理解しておきましょう。
th:fieldはinputタグで使用される属性で、設定されているtypeによって多少異なりますが大体はidとnameに変数名、valueに変数の値を設定してくれるものです。
そのため、Thymeleafによって処理された後のhtmlは下記のようになります。th:fieldのおかげでname属性の値にfruitFormの変数名が設定されていることがわかりますね。
○html(処理後)
<!--/* index.html */-->
<form action="/index" method="post">
<input type="text" value="" id="name" name="name">
<input type="text" value="0" id="price" name="price">
<button type="submit">送信</button>
</form>
またinputタグの内容は「name : value」のセットで送信されることになるため、サーバ側には「変数名 : 入力内容」のセットで送信されることになります。(下図の場合は「name : apple」、「price : 150」の2データが送信される)
○画面
Java側の実装は下記のとおりです。Spring Boot側の詳細は省きますが、フォーム送信されるとメソッドの引数となっている格納用のオブジェクトにinputの内容が格納されます。
@PostMapping("/index")
public String index(Model model, FruitForm fruitForm) {
// このメソッドが呼ばれる時にはすでにinputの内容が格納されている
/**
処理省略
**/
return "index";
}
@ModelAttribute
private FruitForm fruitForm() {
return new FruitForm();
}
上記の場合は、fruitFormのnameとpriceにinputの値が格納された後、対象のメソッドであるindexが呼ばれるようなイメージですね。
まとめ
- 選択変数式はth:objectが設定されている要素の子要素で使用する単純式。
- th:objectに指定したオブジェクトがもつ変数名を使って”*{変数名}”と記載する。
- th:valueやth:textに使用した場合は変数式と同様にその属性に変数値を渡すことができる。
変数式よりも記載が短くなることや、オブジェクトを取り扱う範囲がわかりやすくなるメリットがある。 - th:fieldに使用した場合はその要素のidとnameに変数名、valueに変数の値を設定する。
フォーム送信によく使用するものなので、必ずマスターしましょう!
コメント