変数を利用する
前回はJavaアプリケーション向けののテンプレートエンジン「Thymeleaf」を紹介した。Webアプリケーション開発でテンプレートエンジンを利用するメリットは、見た目のデザインとロジックを記述するコードが分離できるという点にある。その点、前回示したhello.htmlの例は、単にテキスト部分を別ファイルに抜き出しただけなので、ロジックの分離という観点には触れていない。
Thymeleafには、テンプレート中にサーバ側のJavaオブジェクトと関連付けられた変数を埋め込む機能が用意されている。これを利用することで、サーバサイドで生成や加工されたデータを、シームレスにページの表示の中に反映させることができるようになる。今回は、Thymeleafの標準文法セットである「Standard Dialect」でサポートされている変数の利用方法を紹介する。
まず、サーバ側のオブジェクトはAbstractContextクラス(前回の例で使用したWebContextの親クラス)のsetVariable()メソッドを利用してコンテキストにセットする。第一引数に、テンプレートファイルで利用するための変数名を、第二引数に関連付けるオブジェクトを渡す。次の例は、現在時刻のDateオブジェクトを、"date"という変数名と関連付けてセットした例である。Servletのプログラム全体は前回の例を参照していただきたい。
// WebContextを作成テンプレートの処理を実行
WebContext ctx = new WebContext(request, request.getLocale());
// オブジェクトをセット
Calendar calendar = Calendar.getInstance();
ctx.setVariable("date", calendar.getTime());
// テンプレートの処理を実行
String result = engine.process("variable", ctx);
テンプレートファイルでは、${●●●}という文法でサーバのオブジェクトと関連付けられた変数を利用することができる。たとえば、th:text属性の値として以下のように「#{date}」を指定すれば、divタグの部分が上のコードのDateオブジェクトの値(toString()の結果)に置き換えられることになる。
<body>
<h2>変数の使用</h2>
<div style="font-size:20px"><strong>
<p>時刻: <span th:text="${date}">時刻</span></p>
</strong></div>
</body>
Webブラウザからアクセスして表示するとのようになり、リロードするたびに時刻が変わることが確認できる。
プロパティを持つオブジェクトの場合
プロパティを持ったオブジェクトを使用する場合、${hoge.piyo}のような形式でプロパティ値を参照できるようになっている。例えば、次のようにidとpasswordを持ったAccountクラスがあるとする。
public class Account {
private String id;
private String password;
public Account(String id, String password) {
this.id = id;
this.password = password;
}
// Getter/Setterは省略
}
このAccountのインスタンスを作って、「account」という変数名に関連付けてコンテキストにセットする。
Account account = new Account("mycom", "hogehoge");
ctx.setVariable("account", account);
この場合、テンプレートファイルでは次のように「${account.id}」でAccountオブジェクトのidプロパティの値を、「${account.password}」でpasswordプロパティの値を利用できる。
<body>
<h2>変数の使用 その2</h2>
<div style="font-size:20px"><strong>
<p>ユーザID: <span th:text="${account.id}">ユーザID</span></p>
<p>パスワード: <span th:text="${account.password}">パスワード</span></p>
</strong></div>
</body>
Webブラウザでの表示例はのようになる。
繰り返し構文の利用
これまで使ってきたth:text属性は、シンプルにテキストを埋め込むためのものである。Thymeleafには、もう少し便利な属性もいくつか用意されている。たとえば、th:eachはfor-eachのようにコードの繰り返し部分を簡潔に記述するための文法をサポートする。まず、Servlet側で次のように複数のオブジェクトを保持したListオブジェクトをコンテキストにセットしたとする。
List<Account> accounts = new ArrayList<Account>();
accounts.add(new Account("user1", "hogehoge"));
accounts.add(new Account("user2", "piyopiyo"));
accounts.add(new Account("user3", "hogepiyo"));
ctx.setVariable("accounts", accounts);
このListオブジェクトが持つデータをすべて表示したい場合、th:each属性を利用すれば、次のような文法で繰り返し処理によって記述することが可能となる。
<body>
<h2>繰り返しの使用</h2>
<div style="font-size:20px">
<table border="1px">
<tr><th>ユーザID</th><th>パスワード</th></tr>
<tr th:each="account: ${accounts}">
<td th:text="${account.id}">ユーザID</td>
<td th:text="${account.password}">パスワード</td>
</tr>
</table>
</div>
</body>
まず、元になるListオブジェクトのための変数名は「${accounts}」である。th:eachの値として「account: ${accounts}」を指定すると、${accounts}が持つそれぞれのオブジェクトが、順番にaccount変数に格納される。この場合、th:each属性はtrタグに指定してあるので、その子要素の中でaccount変数がローカル変数のように使用できるようになる。accountはAccountオブジェクトと関連付けられたものなので、先ほどの例と同じように${account.id}などが利用できるというわけだ。あとは、for-eachのようにListの最後の要素まで同じ処理が繰り返し行われる。
つまりクライアントに贈られるHTMLコードの中では3つ分のtrタグに置き換わることになる。Webブラウザでアクセスすると、のようにテーブルに3行分のデータが表示されることが確認できる。
この繰り返し構文は、java.util.Iteratableインタフェースかjava.util.Mapインタフェースをimplementsしたクラスのオブジェクトで利用することができる。
th:objectによるプロパティの参照
続いて、Accountオブジェクトのプロパティを参照する別の例を紹介しよう。サーバ側のプログラムは、ひとつ前の例に戻って、次のようにAccountオブジェクトをWebContextにセットしたものとする。
Account account = new Account("mycom", "hogehoge");
ctx.setVariable("account", account);
このとき、テンプレートにおいてth:object属性を使うことによって、Accountの各プロパティを「*{id}」や「*{password}」といった短い変数名で利用できるようになる。以下に例を示す。
<body>
<h2>『*』による変数への参照</h2>
<div style="font-size:20px" th:object="${account}">
<strong>
<p>ユーザID: <span th:text="*{id}">ユーザID</span></p>
<p>パスワード: <span th:text="*{password}">パスワード</span></p>
</strong>
</div>
</body>
まず、th:object属性の値として変数「${account}」を使用する。すると、このdivタグの子要素の中では、${account}と関連付けられたAccountオブジェクトの各プロパティを参照する変数として、プロパティ名を使った「*{id}」や「*{password}」が使用できる(「$」ではなく「*」である点に注意)。
Webブラウザでの表示例は、${account.id}などを利用した場合と同じでのようになる。