Spring BootではJSPではなくThymeleafが推奨されているのでチートシート作った。なお、表記中のサンプルはController側は全てController.java、View側は全てlist.htmlとしている。
値を表示する
<p th:text="${id}"></p>
値を結合する
<p th:text="'one ' + 'two ' + 'three ' + 'id = ' + ${param.id[0]}"></p>
値を結合する(リテラル置換)
値を結合する、のやり方でもいいがリテラル置換というもっとシンプルな書き方も用意されている。"|テキストの内容|"
で記述可能、${}
の変数式も組み込むことができる。
<p th:text="|one two three = ${customer.id}|"></p>
HTMLタグをサニタイズしないようにする
Thymeleafではth:textはサニタイズしてくれる。ただ、状況によってサニタイズしたくない場合は、th:utextを利用する。ただし利用する場合はXSS攻撃を理解したうえで利用すること。
model.addAttribute("msg", "<h1>This is Message!!</h1><br />");
<p th:utext="${msg}"></p>
ローカル変数を定義する
th:with="変数名=値"
で変数を定義して値を代入できる。この変数は定義されたタグ内部でのみ利用可能。
<div th:with="x=1,y=2">
<p th:text="${x}"></p>
<p th:text="${y}"></p>
</div>
メッセージ式
プロパティファイルから値を取り出して表示する。${}
が変数式に対してメッセージ式は#{}となる。resourcesフォルダ配下にmessages.propertiesを作成しメッセージを定義する。
content.title=This is title
content.message=This is message
View側では以下のようにすることでアクセスができる。
<p th:text="#{content.title}"></p>
<p th:text="#{content.message}"></p>
パラメータへアクセスする
/index?id=123のような形でリクエストを飛ばした際にテンプレート内でパラメータへアクセスしたい時に利用される。paramという変数が標準で利用できるので、param.idという形でアクセスする。ただし、通常は配列になっているのでparam.id[0]のような形で利用する。なお、この際は最初の要素(0)へアクセスすることで値へアクセスできる。
<p th:text="${param.id[0]}"></p>
配列になっているのは、/index?id=123&id=456というように同じパラメータ名で複数の値を送る場合にも対応できるようにするため。以下のようにすることで456がとれる。
<p th:text="${param.id[1]}"></p>
リンク式とhref
<p><a th:href="@{'/customers/edit/' + ${param.id[0]}}">link</a></p>
オブジェクト内のフィールドの値を表示する1
customerというオブジェクトのidフィールドの値を表示する例。以下の場合getId()というgetterメソッドが必要。
<p th:text="${customer.id}"></p>
オブジェクト内のフィールドの値を表示する2
オブジェクト内のフィールドの値を表示する1のやり方だと、オブジェクト名が変わった時に修正が面倒になってくる。そのため以下のようにth:object="${customer}"という形でオブジェクトを宣言したタグの内部で*{フィールド名}とする書き方もできる。この場合も、getId()、getNameというgetterメソッドが必要。
<div th:object="${customer}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
</div>
算術演算子
「+」,「-」,「*」,「/」,「%」が利用可能。
<p th:text="11 + 5"></p>
<p th:text="11 - 5"></p>
<p th:text="11 * 5"></p>
<p th:text="11 / 5"></p>
<p th:text="11 % 5"></p>
比較演算子
「>」,「<」,「>=」,「<=」が利用可能。ただし、< と > を使用すべきではないので、<
と>
を使用する。
<p th:text="11 > 5"></p>
<p th:text="11 < 5"></p>
<p th:text="11 >= 5"></p>
<p th:text="11 <= 5"></p>
以下の通り文字列エイリアスもある。
gt (>), lt (<), ge (>=), le (<=), not (!)
等価演算子
「==」、「!=」が利用可能。
<p th:text="11 == 11"></p>
<p th:text="11 != 5"></p>
以下の通り文字列エイリアスもある。
eq (==), neq/ne (!=)
条件式
三項演算子のように以下の形で条件式を記述できる。
model.addAttribute("isEven", 50 % 2 == 0);
model.addAttribute("even", "even!!");
model.addAttribute("odd", "odd!!");
<p th:text="${isEven} ? ${even} : ${odd}"></p>
条件分岐
th:if
th:if="条件"でtrueとなった場合、このタグおよび内部にあるタグを表示する。
真偽値以外にtrueと判断されるものには以下のものがある。
- true値
- 0以外の数値
- "0"、"off"、"no"といった値以外のテキスト
<div th:if="${isEven}">
<input type="text" />
</div>
th:unless
th:unless="条件"でfalseとなった場合、このタグおよび内部にあるタグを表示する。
真偽値以外にfalseと判断されるものには以下のものがある。
- false値
- null
- 0以外の数値
- "0"、"off"、"no"といったテキスト
<div th:unless="${isEven}">
<input type="text" />
</div>
多項分岐
th:switchが使える。どこにも一致しなければth:case="*"となる(javaでいうdefaultみたいなもの)。
<div th:switch="${month}">
<p th:case="1" th:text="|${month}月|"></p>
<p th:case="2" th:text="|${month}月|"></p>
<p th:case="3" th:text="|${month}月|"></p>
<p th:case="*">対象なし</p>
</div>
繰り返し(ループ)
th:each="変数 : ${コレクション}"
で記述できる。${コレクション}
の値を1つずつ取り出し変数に代入し、以降の処理の中で変数.フィールドの形で値へアクセスできる。javaでいう拡張for文のようなイメージ。
List<Customer> customers = new ArrayList<Customer>();
customers.add(new Customer(1 , "Miura", "Kazuyoshi"));
customers.add(new Customer(2 , "Kitazawa", "Tsuyoshi"));
customers.add(new Customer(3 , "Hashiratani", "Tetsuji"));
model.addAttribute("customers", customers);
<tr th:each="customer : ${customers}">
<td th:text="${customer.id}"></td>
<td th:text="${customer.lastName}"></td>
<td th:text="${customer.firstName}"></td>
</tr>
オブジェクト内のフィールドの値を表示する2と組み合わせて以下のようにも記述できる。
<tr th:each="customer : ${customers}" th:object="${customer}">
<td th:text="*{id}">100</td>
<td th:text="*{lastName}"></td>
<td th:text="*{firstName}"></td>
</tr>
ステータス変数
th:each
を利用する場合、繰り返し処理中のステータスを知るためのステータス変数というものが用意されている。ステータス変数を利用する場合、それ用の変数をもう1つ用意する必要がある、以下の例ではstatを追加。
<tr th:each="customer, stat : ${customers}" th:object="${customer}">
<td th:text="*{id}">100</td>
<td th:text="*{lastName}"></td>
<td th:text="*{firstName}"></td>
<td th:text="${stat.index}"></td>
</tr>
他には以下のようなものがある。
ステータス変数 | 内容 |
---|---|
index | 0始まりの現在の「繰り返しインデックス」 |
count | 1始まりの現在の「繰り返しインデックス」 |
size | 繰り返し変数の全要素数 |
current | 現在の要素オブジェクト |
even | 現在の繰り返し位置が偶数の場合true |
odd | 現在の繰り返し位置が奇数の場合true |
first | 現在の繰り返し処理が最初の場合はtrue |
last | 現在の繰り返し処理が最後の場合はtrue |
プリプロセッシング
__${変数}__
という形(前後をアンダースコア2つで囲む形)で宣言すると、この部分は事前に評価される。そのため事前に評価して値を動的に変えることができる。例えば、以下のようなコードがあった場合、${customers.get(${anyNumber})}
の期待する結果は、${customers.get(1)}
だが実際は${customers.get(${anyNumber})}
となり、エラーとなってしまう。
List<Customer> customers = new ArrayList<Customer>();
customers.add(new Customer(1 , "Miura", "Kazuyoshi"));
customers.add(new Customer(2 , "Kitazawa", "Tsuyoshi"));
customers.add(new Customer(3 , "Hashiratani", "Tetsuji"));
model.addAttribute("customers", customers);
model.addAttribute("anyNumber", 1);
<div th:object="${customers.get(${anyNumber})}">
<p th:text="*{id}"></p>
</div>
つまり、${anyNumber}
の部分を事前に評価してあげる必要がある。そういった場合に利用するのがプリプロセッシングである。冒頭で述べた通り、これは__${anyNumber}__
とすることで実現される。
<div th:object="${customers.get(__${anyNumber}__)}">
<p th:text="*{id}"></p>
</div>
インライン処理
Thymeleafでは値の表示をth:textで行うが、毎回th:textと記述するのは面倒。こういった場合にインライン処理が使える。th:inline="text"とするとその内部のタグではth:textは省略できて、[[${変数}]]でアクセスできる。
List<Customer> customers = new ArrayList<Customer>();
customers.add(new Customer(1 , "Miura", "Kazuyoshi"));
customers.add(new Customer(2 , "Kitazawa", "Tsuyoshi"));
customers.add(new Customer(3 , "Hashiratani", "Tetsuji"));
model.addAttribute("customers", customers);
<tr th:inline="text" th:each="customer : ${customers}">
<td>[[${customer.id}]]</td>
<td>[[${customer.lastName}]]</td>
<td>[[${customer.firstName}]]</td>
</tr>
Javascriptのインライン処理
インライン処理はJavascriptの中でも利用できるが、記述方法が通常のインラインと違い以下のようにコメントアウトする形で記述する。
<script th:inline="javascript">
alert(/*[[&(変数)]]*/);
</script>
テンプレートフラグメント(include)
Webページを作成する際、ヘッダー、フッター、メニューといった部品を別ファイルとして用意しそれらを組み合わせて(includeして)1つのページを作成することがよくある。Thymeleafではテンプレートフラグメントという機能を使ってこういったことを実現することができる。
まずは、組み込まれるhtmlを「/WEB-INF/templates/」配下に作成する。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
</head>
<body>
<table th:fragment="frag_table">
<tr>
<td>組み込まれるパーツ</td>
</tr>
</table>
</body>
</html>
<table th:fragment="frag_table">
でこのテーブルにfrag_tableという名前でフラグメントをつける。組み込む側のhtmlでは以下のように
「th:include="組み込みたいフラグメントが存在するhtmlファイル名 :: フラグメント"」
の形で組み込みたい場所にフラグメントを指定する。
<div th:include="header :: frag_table"></div>
こうすることでheader.htmlのフラグメントをつけたtableがlist.htmlに組み込まれる。JSP等のincludeは組み込みたいファイルを指定するが、Thymeleafのフラグメントは組み込みたい部分はどのファイルのどの部分、という形で指定できるから便利。
ユーティリティオブジェクト
Thymeleafでは標準で、よく使われるクラスのオブジェクトを「#クラス名」という定数として定義してある。これらを利用して変数式の中に直接記述できる。
定数 | クラス |
---|---|
#strings | Stringクラスのオブジェクト |
#numbers | Numberクラスのオブジェクト |
#bools | Booleanクラスのオブジェクト |
#dates | Dateクラスのオブジェクト |
#calendars | Calendarクラスのオブジェクト |
#objects | Objectクラスのオブジェクト |
#arrays | Arrayクラスのオブジェクト |
#lists | Listクラスのオブジェクト |
#maps | Mapクラスのオブジェクト |
#sets | Setクラスのオブジェクト |
<p th:text="${#strings.toUpperCase('Hello Thymeleaf')}"></p>
クラスをnewしてインスタンスを生成する
<p th:text="${new java.util.Date().toString()}"></p>
日付をフォーマットする
<p th:text="${#dates.format(new java.util.Date(),'yyyy/MM/dd')}"></p>
ThymeleafのキャッシュをOFFにする
application.properties or application.ymlに以下の設定を入れる。
spring.thymeleaf.cache=false
spring.thymeleaf.cache: false
参考
http://www.thymeleaf.org/
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html
SpringBootプログラミング入門