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(フィールド名)
: エラーメッセージの表示。