別ファイルの内容を読み込む
ヘッダーとかフッターを各HTMLにベタで書かないで一カ所にまとめたいこと、ありますよね!(迫真)
そんなとき便利なのがth:includeです。
こんな感じのディレクトリ構成でファイルがあるとします。
templates ├common |└footer.html └index.html
今回はindex.htmlからfooter.htmlの内容を読み込んでみます!
まずfooter.htmlから。
<footer th:fragment="common_footer"> 共通フッター </footer>
th:fragmentと書いて、値にはこのfooter要素を別ファイルから読み込むときに使用する名前を記述します。
次はindex.htmlです。
<div th:include="common/footer :: common_footer"></div>
th:includeと書き、値には「読み込むファイルの.htmlを抜いたパス :: th:fragmentに指定した値」というフォーマットで記述をします。
div要素に書いてるのは大人の事情です。すぐ説明します。
さてこれで表示してみるとどうなるでしょうか。footer.htmlの内容が表示されるんでしょうか!
気になる結果は!
<div> 共通フッター </div>
_人人 人人_
> 突然のdiv <
 ̄Y^Y^Y^Y ̄
footerだと思った?残念!divちゃんでした!
th:includeを使った場合、これを記述したタグが優先される形になってしまいます。
基本的には呼び出し先と呼び出し元で同じタグを指定するとは思うんですが、こういうときのために解決策もあります。
th:includeの代わりにth:substitutebyを使ってみます。
<div th:substituteby="common/footer :: common_footer"></div>
こうするとfooter.htmlに書いた通りの内容が表示される結果になります。
こんな感じで共通の要素を一つのファイルに集約出来るは出来るんですが、thymeleafはfreemarkerなどと違ってHTMLタグありきです。
たとえば、CSSの読み込みのためにlink要素を複数呼び出したいときはどうすればいいでしょうか。
link要素それぞれにth:fragmentを書くのが正攻法だと思いますが、ちょっとめんどくさいです。
なので、複数のlink要素を大きな一つの要素で囲ってそれをincludeしてしまえばよさげです。
でもlinkって基本的にはheadに記述するものですよね。divとかspanで囲うのはナンセンスです。
というわけでheadで囲ってみます。
<head th:fragment="common_link"> <link ref="http://tm8r.com/css/test1.css" rel="stylesheet"/> <link ref="http://tm8r.com/css/test1.css" rel="stylesheet"/> </head>
こんなかんじでしょうか!
呼び出し元はこんなかんじ。
<head> <link th:substituteby="common/head :: common_link"/> </head>
ただこれだとheadの中にheadがあるみたいな感じになってしまいます…。
これを解決すべく呼び出し先をちょっと変更してみます。
<head th:fragment="common_link" th:remove="tag"> <link ref="http://tm8r.com/css/test1.css" rel="stylesheet"/> <link ref="http://tm8r.com/css/test1.css" rel="stylesheet"/> </head>
前回の記事で書いたth:removeを使ってみました!
これでタグが削除されるので、呼び出し元に表示されるのはlink要素二つだけという結果になります…!
だいぶイケてないですが一応実現できるはできるという感じです…!
ちなみに呼び出し元でth:substitutebyではなくth:includeを使ってしまうと呼び出し先のth:removeが実行されないので、最後にlink要素が閉じられてしまうみたいな挙動になってちょっと上手くいきません。
悩みを解決してくれる気がしないでもないプラグインがあったので一応おいておきます。
ultraq/thymeleaf-layout-dialect · GitHub
ためしてないですけど!
デフォルト値を設定する
条件分岐の話のときに書き忘れました!
たとえばfreemarkerだと以下のような感じでデフォルト値(変数が存在しない場合の値)を指定できました。
${str!'default'}
これをthymeleafでやる場合、以下のような記述になります。
<span th:text="${str}?: 'default'">hoge</span>
かんたんですね。記述量もfreemarkerと大して変わらない!
若干用途は異なりますが、こんなこともできます。
<span th:text="${str == null}? 'null' : 'not null'">hoge</span>
べんり!
次回こそはutilityあたりを!
あとmessageとか!
freemarkerとの比較とかもやってみようかと思ってたり思ってなかったりします。
したらな!