Thymeleaf
Thymeleafについて、分からないことが多すぎたため公式ページを確認したが、それでも分からない事が多いので、他の解説しているページ等を参考にまとめたページ。自分が使用することになった内容に重点を置いて書いてます。基本は次の公式ページを参考にしていますが、公式以外を参考にした部分はリンクを張っています。
公式ではないですが、次のチートシートがとても分かりやすく纏められていました。
スタンダード式構文
- 単純式:
- 変数式:
${...} - 選択変数式:
*{...} - メッセージ式:
#{...} - リンクURL式:
@{...}
- 変数式:
- リテラル
- テキストリテラル:
'one text','Another one!',… - 数値リテラル:
0,34,3.0,12.3,… - 真偽値リテラル:
true,false - Nullリテラル:
null - リテラルトークン:
one,sometext,main,…
- テキストリテラル:
- テキスト演算子:
- 文字列結合:
+ - リテラル置換:
|The name is ${name}|
- 文字列結合:
- 算術演算子:
- バイナリ演算子:
+,-,*,/,% - マイナス符号 (単項演算子):
-
- バイナリ演算子:
- 論理演算子:
- 二項演算子:
and,or - 論理否定演算子 (単項演算子):
!,not
- 二項演算子:
- 比較と等価:
- 比較演算子:
>,<,>=,<=(gt,lt,ge,le) - 等価演算子:
==,!=(eq,ne)
- 比較演算子:
- 条件演算子:
- If-then:
(if) ? (then) - If-then-else:
(if) ? (then) : (else) - Default:
(value) ?: (defaultvalue)
- If-then:
単純式
変数式: ${...}
-
リクエストパラメータから取得
リクエストパラメータ(postまたはgetで送られてくるデータ)にname=Tanakaがある場合
${param.name[0]}で取得できる。
リクエストパラメータは同一名称で複数送れるため、配列で保存される。 -
リクエストスコープから取得
リクエストスコープにname=Tanakaが保存されている場合
${name}でTanakaが取得できる。 -
式のユーティリティオブジェクト
#ユーティリティオブジェクトで複数のオブジェクトが用意されており、変数式の中に書くことで使える。詳細はThymeleafの公式ページに載っているので、ここではどんなものかイメージ出来るように数個記載する。-
#stringsユーティリティメソッド一例
${#strings.toUpperCase(name)}これで変数nameの値を大文字にする
nameを文字列として扱う場合は、'name'のようにテキストリテラルとして書く -
#arraysユーティリティメソッド一例
${#lists.isEmpty(list)}これでlistが空かどうかチェックできる -
#idsユーティリティメソッド一例
下記のサイトに分かりやすく書かれていたが、調べる前は読んでも理解できなかったので、忘れないように解説を残す。サイトに書かれていたコードとリンクは、解説後に記載する。
-
-
${#numbers.sequence(1,3)これは#numbersユーティリティを使ったもの。{#numbers.sequence(from,to)}でfromからtoまでの整数の配列が作成される。 -
th:each="seq : ${#numbers.sequence(1,3)}"では作成された配列の値が変数seqに代入され、th:eachを書いたタグ内で繰り返し処理される。 -
th:id="${#ids.seq('id_hobby_')}"これは#ids.seq('someId')ユーティリティで、id属性値にカウンターの値を加える動作になる。通常th:id属性に使用される。この例ではid_hobby_1、id_hobby_2といったようなカウンターの値を加えた動作になる。 -
th:for="${#ids.prev('id_hobby_')}"は#ids.prev('someId')ユーティリティで、通常は<label>タグ内のth:for属性に使用される。#ids.seq('someId')関数で生成されたidをラベルから参照できるようになる。例では直前に書かれたth:id="${#ids.seq('id_hobby_')}"で生成されたidがid_hobby_1の時、th:for="${#ids.prev('id_hobby_')}"も同様の値id_hobby_1になる。後ろにあるidを参照するときはids.next('someId')ユーティリティを使用する。
<form>
<th:block th:each="seq : ${#numbers.sequence(1,3)}">
<input type="text" name="hobby" th:id="${#ids.seq('id_hobby_')}" value="" />
<label th:text="|hobby_${seq}|" th:for="${#ids.prev('id_hobby_')}">field</label>
</th:block>
</form>
<form>
<input type="text" name="hobby" value="" id="id_hobby_1">
<label for="id_hobby_1">hobby_1</label>
<input type="text" name="hobby" value="" id="id_hobby_2">
<label for="id_hobby_2">hobby_2</label>
<input type="text" name="hobby" value="" id="id_hobby_3">
<label for="id_hobby_3">hobby_3</label>
</form>
#ids.prev又は#ids.nextメソッドで参照するidは通常#ids.seq('someId') 関数で作成されるidを使用する。#ids.seq('someId') 関数の前で指定するときは#ids.prev、後で使用するときは#ids.nextを使う。
また、inputの部品にth:field属性を付与した場合は内部的に#ids.seqメソッドと同等の処理を実行してidが生成される。このため、タグ内にth:field属性を付与した場合は#ids.seqメソッドを使用しなくて良い。
https://macchinetta.github.io/server-guideline-thymeleaf/current/ja/ArchitectureInDetail/WebApplicationDetail/Validation.html#validation-ids-prev-method
上記のノートではth:field属性を付与すると、内部的に#ids.seq<input>タグの部品textにth:field属性を指定したtemplateコードは、name、id、value属性を明記したrenderコードと同様の内容になる。
<input type="text" th:field="*{datePlanted}" />
<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />
https://www.thymeleaf.org/doc/tutorials/3.1/thymeleafspring.html
選択変数式: *{...}
変数式${...}とほとんど同じだがth:objectで指定したオブジェクトから値を探す。
指定したオブジェクトに値がない場合、${...}と同じ意味になる。
変数式${…}の中で選択変数式を使う
${*{…}}はエラーとなり使用できない。
#objectを変数式内で使用するとth:objectで設定したオブジェクトを指せる。
<div th:object="${hogehoge}">
<p>FirstName: <span th:text="${#object.firstName}"></span>.</p>
</div>
メッセージ式: #{...}
別のファイル(通常は.propertiesファイル)に書かれたメッセージと紐づけが出来る。
xxx.propertiesファイルにuser.name=Tanakaが保存されていると
#{user.name}でTanakaが取得できる。
リンクURL式: @{...}
<a th:href=@{...}>のように、<a>タグとth:href属性とセットで使用する。
次コードのように、URLパラメータとして使うことも可能。
<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
<!-- Will produce '/gtvg/order/details?orderId=4' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id + 1})}">view</a>
ここでは、detailsの後にURLパラメータを追加している。?orderID=3のように変わる。
2つ目の式のように、変数式の中に算術演算子を使うことも可能。
href属性とth:href属性を併記する理由、動作は次のサイトが参考になった。
href属性は、サーバーを通さずに直接ブラウザでHTMLを開いたときに利用されます。そして、サーバー上で実行したときには、href属性の値はth:href属性の値で上書きされます。なぜ、上書きされて消えてしまうhref属性を書くのかというと、直接ブラウザでHTMLを開いてもCSSが適用されるようにするためです。
こうすると、テンプレートをそのままブラウザで開いて、お客様に見せて打ち合わせなどができます。
<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
上記のコードはURL内の{orderId}と(orderId=${o.id})がリンクしている。
1つ前のコードでは、(orderId=${o.id})が?orderID=3に変わっていたが、このコードでは{orderId}に${o.id}の結果である3が代入されている。
記述が似ているが結果は違うので注意が必要だと感じた。
テキスト演算子
リテラル置換
変数式を使った文字列を作成するとき+を使わず簡単に書くことができる。
| |内に書いた文字はそのまま文字として、${}や*{}のような変数式は結果が文字として表示される。
<div th:object="${hogehoge}">
<span th:text="|The name is ${hogehoge.name}|"></span>
<span th:text="|The name is *{name}|"></span>
</div>
その他の使い方
Bean値を使用
@の後にBean名を書くと、そのBeanを使うことができる。
環境変数を取得
${@environment.getProperty('property.key')}
propertyやymlファイルの値を取得できる。
テキスト演算子の文字列結合と併用しても、property.keyを囲っている''は書き換え不要。
例えば文字に環境変数を結合したいとき下記のように書ける。
"'hoge' + 'hogehoge' + ${@environment.getProperty('property.key')}"
属性に値を設定する
任意の属性に値を設定するにはth:attr属性を使う必要があるが、特定の属性にはth:*属性がたくさん用意されており、通常はth:*属性で対応できる。公式には数個の使用例が記載されている。
<input type="submit" value="Subscribe me!" th:value="#{subscribe.submit}"/>
<form action="subscribe.html" th:action="@{/subscribe}">
<li><a href="product/list.html" th:href="@{/product/list}">Product List</a></li>
参考だが、1行目をth:attr属性で書くとこのようになる。(普通は上記のth:valueを使う)
<input type="submit" value="Subscribe me!" th:attr="value=#{subscribe.submit}"/>
th:if、th:unless属性
th:ifの結果がtrueの場合、th:ifタグ内が実行され、falseの場合は実行されない。
次の公式のコードを参考に説明する。
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
これは、#lists.isEmpty(prod.comments)でprod.commentsが空か否か判断し、空の場合はtrueになるが、notが付いているのでfalseになる。つまり、prod.commentsが空の場合は何も表示されないが、空でない場合はリンクth:href="@{/product/comments(prodId=${prod.id})}"が表示される。
補足:notは!と書いても良い。
th:unlessはth:ifと反対の動作をする属性で、上記のコードは下記のように書ける。
<a href="comments.html"
th:href="@{/comments(prodId=${prod.id})}"
th:unless="${#lists.isEmpty(prod.comments)}">view</a>
オブジェクトを使ってコントローラとビューで値を共有する
次のページに記載しています。
定型文
<html xmlns:th="http://www.thymeleaf.org">
IDEがth:*属性に対してエラーを出さないようにする定型文。テンプレートに対して意味はない。
公式で確認できなかった属性やユーティリティメソッド等
Thymeleaf公式ページでは確認できなかったが、使用できる属性やユーティリティメソッド等をまとめてます。
エラー関係
次のサイトが参考になった。使用例のコードも記載されています。
th:errorclass: エラー時のみ設定されるクラス属性。テキストの枠を赤くしたりなどなど
#fields.hasErrors(フィールド名): エラーが発生したかどうか。
th:errors(フィールド名): エラーメッセージの表示。