Thymeleafの使い方一例

# Thymeleaf
Thymeleafについて、分からないことが多すぎたため公式ページを確認したが、それでも分からない事が多いので、他の解説しているページ等を参考にまとめたページ。自分が使用することになった内容に重点を置いて書いてます。基本は次の公式ページを参考にしていますが、公式以外を参考にした部分はリンクを張っています。

https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf_ja.html#%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%80%E3%83%BC%E3%83%89%E5%BC%8F%E6%A7%8B%E6%96%87

公式ではないですが、次のチートシートがとても分かりやすく纏められていました。

https://qiita.com/NagaokaKenichi/items/c6d1b76090ef5ef39482

## スタンダード式構文



<ul>
<li>単純式:
<ul>
<li>変数式: <code>${...}</code></li>
<li>選択変数式: <code>*{...}</code></li>
<li>メッセージ式: <code>#{...}</code></li>
<li>リンクURL式: <code>@{...}</code></li>
</ul></li>
<li>リテラル
<ul>
<li>テキストリテラル: <code>'one text'</code>, <code>'Another one!'</code>,…</li>
<li>数値リテラル: <code>0</code>, <code>34</code>, <code>3.0</code>, <code>12.3</code>,…</li>
<li>真偽値リテラル: <code>true</code>, <code>false</code></li>
<li>Nullリテラル: <code>null</code></li>
<li>リテラルトークン: <code>one</code>, <code>sometext</code>, <code>main</code>,…</li>
</ul></li>
<li>テキスト演算子:
<ul>
<li>文字列結合: <code>+</code></li>
<li>リテラル置換: <code>|The name is ${name}|</code></li>
</ul></li>
<li>算術演算子:
<ul>
<li>バイナリ演算子: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>%</code></li>
<li>マイナス符号 (単項演算子): <code>-</code></li>
</ul></li>
<li>論理演算子:
<ul>
<li>二項演算子: <code>and</code>, <code>or</code></li>
<li>論理否定演算子 (単項演算子): <code>!</code>, <code>not</code></li>
</ul></li>
<li>比較と等価:
<ul>
<li>比較演算子: <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code> (<code>gt</code>, <code>lt</code>, <code>ge</code>, <code>le</code>)</li>
<li>等価演算子: <code>==</code>, <code>!=</code> (<code>eq</code>, <code>ne</code>)</li>
</ul></li>
<li>条件演算子:
<ul>
<li>If-then: <code>(if) ? (then)</code></li>
<li>If-then-else: <code>(if) ? (then) : (else)</code></li>
<li>Default: <code>(value) ?: (defaultvalue)</code></li>
</ul></li>
</ul>

## 単純式
### 変数式: <code>${...}
- リクエストパラメータから取得
リクエストパラメータ(postまたはgetで送られてくるデータ)に`name=Tanaka`がある場合
`${param.name[0]}`で取得できる。
リクエストパラメータは同一名称で複数送れるため、配列で保存される。
- リクエストスコープから取得
リクエストスコープに`name=Tanaka`が保存されている場合
`${name}`で`Tanaka`が取得できる。

- 式のユーティリティオブジェクト
`#ユーティリティオブジェクト`で複数のオブジェクトが用意されており、変数式の中に書くことで使える。詳細は[Thymeleafの公式ページ](https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf_ja.html#appendix-b%E5%BC%8F%E3%83%A6%E3%83%BC%E3%83%86%E3%82%A3%E3%83%AA%E3%83%86%E3%82%A3%E3%83%BC%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88)に載っているので、ここではどんなものかイメージ出来るように数個記載する。
  - #stringsユーティリティメソッド一例
`${#strings.toUpperCase(name)} `これで変数`name`の値を大文字にする
`name`を文字列として扱う場合は、`'name'`のようにテキストリテラルとして書く

  - #arraysユーティリティメソッド一例
`${#lists.isEmpty(list)}`これでlistが空かどうかチェックできる

  - #idsユーティリティメソッド一例
下記のサイトに分かりやすく書かれていたが、調べる前は読んでも理解できなかったので、忘れないように解説を残す。サイトに書かれていたコードとリンクは、解説後に記載する。
1. `${#numbers.sequence(1,3)`これは`#numbers`ユーティリティを使ったもの。`{#numbers.sequence(from,to)}`でfromからtoまでの整数の配列が作成される。
2. `th:each="seq : ${#numbers.sequence(1,3)}"`では作成された配列の値が変数`seq`に代入され、`th:each`を書いたタグ内で繰り返し処理される。
3. `th:id="${#ids.seq('id_hobby_')}"`これは`#ids.seq('someId')`ユーティリティで、id属性値にカウンターの値を加える動作になる。通常`th:id属性`に使用される。この例では`id_hobby_1`、`id_hobby_2`といったようなカウンターの値を加えた動作になる。
4. `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')`ユーティリティを使用する。

~~~html:template
<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>
~~~
~~~html:render
<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>
~~~

https://qiita.com/rubytomato@github/items/ac65c2203d16d1a1bbd7

:::note info
`#ids.prev`又は`#ids.next`メソッドで参照するidは通常`#ids.seq('someId')` 関数で作成されるidを使用する。`#ids.seq('someId')` 関数の前で指定するときは`#ids.prev`、後で使用するときは`#ids.next`を使う。
また、`input`の部品に`th:field属性`を付与した場合は内部的に`#ids.seq`メソッドと同等の処理を実行してidが生成される。このため、<input>タグ内に`th:field属性`を付与した場合は`#ids.seq`メソッドを使用しなくて良い。
https://macchinetta.github.io/server-guideline-thymeleaf/current/ja/ArchitectureInDetail/WebApplicationDetail/Validation.html#validation-ids-prev-method
:::
:::note iinfo
上記のノートではth:field属性を付与すると、内部的に#ids.seq`<input>タグ`の`部品text`に`th:field属性`を指定したtemplateコードは、`name`、`id`、`value`属性を明記したrenderコードと同様の内容になる。
~~~html:template
<input type="text" th:field="*{datePlanted}" />
~~~
~~~html:render
<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />
~~~
https://www.thymeleaf.org/doc/tutorials/3.1/thymeleafspring.html
:::

### 選択変数式: <code>*{...}
変数式`${...}`とほとんど同じだが`th:object`で指定したオブジェクトから値を探す。
指定したオブジェクトに値がない場合、`${...}`と同じ意味になる。

#### 変数式${…}の中で選択変数式を使う
`${*{…}}`はエラーとなり使用できない。
`#object`を変数式内で使用するとth:objectで設定したオブジェクトを指せる。
~~~html
<div th:object="${hogehoge}">
  <p>FirstName: <span th:text="${#object.firstName}"></span>.</p>
</div>
~~~

### メッセージ式: <code>#{...}
別のファイル（通常は.propertiesファイル）に書かれたメッセージと紐づけが出来る。
xxx.propertiesファイルに`user.name=Tanaka`が保存されていると
`#{user.name}`で`Tanaka`が取得できる。

### リンクURL式: <code>@{...}
`<a th:href=@{...}>`のように、`<a>`タグと`th:href`属性とセットで使用する。
次コードのように、URLパラメータとして使うことも可能。
~~~html
<!-- 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が適用されるようにするためです。
こうすると、テンプレートをそのままブラウザで開いて、お客様に見せて打ち合わせなどができます。

https://masatoshitada.hatenadiary.jp/entry/2016/12/11/100528

~~~html
<!-- 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})`がリンクしている。
１つ前のコードでは、`(orderId=${o.id})`が`?orderID=3`に変わっていたが、このコードでは`{orderId}`に`${o.id}`の結果である`3`が代入されている。
記述が似ているが結果は違うので注意が必要だと感じた。

## テキスト演算子
### リテラル置換
変数式を使った文字列を作成するとき`+`を使わず簡単に書くことができる。
`| |`内に書いた文字はそのまま文字として、`${}`や`*{}`のような変数式は結果が文字として表示される。


~~~html
<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')}"`

https://blog.tagbangers.co.jp/2015/01/18/thymeleaf-environment-properties

## 属性に値を設定する
任意の属性に値を設定するには`th:attr`属性を使う必要があるが、特定の属性には`th:*`属性がたくさん用意されており、通常は`th:*`属性で対応できる。公式には数個の使用例が記載されている。
~~~html
<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>
~~~
参考だが、１行目を`th:attr`属性で書くとこのようになる。（普通は上記のth:valueを使う)
~~~html
<input type="submit" value="Subscribe me!" th:attr="value=#{subscribe.submit}"/>
~~~

## th:if、th:unless属性
`th:if`の結果が`true`の場合、`th:if`タグ内が実行され、`false`の場合は実行されない。
次の公式のコードを参考に説明する。
~~~html
<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`と反対の動作をする属性で、上記のコードは下記のように書ける。
~~~html
<a href="comments.html"
   th:href="@{/comments(prodId=${prod.id})}"
   th:unless="${#lists.isEmpty(prod.comments)}">view</a>
~~~

## オブジェクトを使ってコントローラとビューで値を共有する
次のページに記載しています。

https://qiita.com/sanmura/items/76bdf5709c4d20eb95dd

## 定型文
~~~html
<html xmlns:th="http://www.thymeleaf.org">
~~~
IDEが`th:*属性`に対してエラーを出さないようにする定型文。テンプレートに対して意味はない。

# 公式で確認できなかった属性やユーティリティメソッド等
Thymeleaf公式ページでは確認できなかったが、使用できる属性やユーティリティメソッド等をまとめてます。
## エラー関係
次のサイトが参考になった。使用例のコードも記載されています。
>`th:errorclass` : エラー時のみ設定されるクラス属性。テキストの枠を赤くしたりなどなど
`#fields.hasErrors(フィールド名)` : エラーが発生したかどうか。
`th:errors(フィールド名)` : エラーメッセージの表示。

https://qiita.com/yakumo3390/items/6b3fcc9e00f7a682660c#%E3%82%A8%E3%83%A9%E3%83%BC%E8%A1%A8%E7%A4%BA