デザイナーさんたちとの協業を推し進める Thymeleaf

Thymeleaf

初めまして、吉澤です。

Web サービス、システムをつくるときに、画面デザインをデザイナーさん、HTML を HTML コーダーの方にお願いすることがあります。

書いてくれた HTML をプログラムに落とし込む作業は面倒で、一度プログラム用に変換した後のメンテナンスは苦労します。 開発者以外に表示箇所のプログラムを覚えてもらい、メンテナンスしてもらうというやり方もあるかと思いますが、苦労されることと想像します。皆さん、どうされているのでしょうか?

今日は僕が最近のシステムに導入している Java の Thymeleaf という HTML テンプレートエンジンを紹介します。

HTML テンプレートエンジンを利用することで、デザイナーさんたちと円滑に作業が進むことを期待しています。

Java には他にもテンプレートエンジンはありますが、僕が一押しと感じているのは以下の理由です。

  • 特定のフレームワークに依存していない (厳密には Servlet API に依存)
  • テンプレートファイルは HTML ファイルそのもの

さっそく実際の記述方法をみてください。 html に thymeleaf 用の名前空間を与えるだけで、後は通常通りの HTML になります。この HTML ファイルはブラウザで直接開いても、当たり前ですが普通にみることができます。 th:xxxx がプログラムで利用しているものになりますが、ブラウザには影響を与えません。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8"/>
    <link href="../../css/bootstrap.css" th:href="@{/css/bootstrap.css}" rel="stylesheet"/>
    <link href="../../css/base.css" th:href="@{/css/base.css}" rel="stylesheet"/>
    <script type="text/javascript" src="../../js/lib/jquery.js" th:src="@{/js/lib/jquery.js}"></script>
    <title>Thymeleaf</title>
</head>
<body>
    <div id="menu" th:include="common/nosign_header.html :: menu"></div>

    <div>
        <div>
            <div>
                <h1 th:text="${message}">Thymeleaf</h1>
            </div>

            <ul>
                <li th:each="item : ${items}" th:text="${item.text}">Item1</li>
                <li th:remove="all">Item2</li>
                <li th:remove="all">Item3</li>
                <li th:remove="all">Item4</li>
            </ul>
        </div>
    </div>
</body>
</html>

 この HTML に対して Servlet を介して、テンプレートエンジンの解析が行われると以下のような HTML で出力が行われます。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8"/>
    <link href="/thymeleaf/css/bootstrap.css" rel="stylesheet"/>
    <link href="/thymeleaf/css/base.css" rel="stylesheet"/>
    <script type="text/javascript" src="/thymeleaf/js/lib/jquery.js"></script>
    <title>Thymeleaf</title>
</head>
<body>
    <div id="menu">
        <div>
            <div>
                <div>
                    <a href="/thymeleaf/">Thymeleaf</a>
                </div>
            </div>
        </div>
    </div>

    <div>
        <div>
            <div>
                <h1>Hello Thymeleaf!</h1>
            </div>

            <ul>
                <li>車</li>
                <li>電車</li>
                <li>飛行機</li>
            </ul>
        </div>
    </div>
</body>
</html>

忌まわしい Servlet のコンテキストパスの解決も行ってくれています。

注意点としては XML として解析をするので、 HTML でなく XHTML として記述する必要があります。タグの閉じ忘れがあるとエラーになってしまうため、 HTML コーダーの方には事前に伝えておく必要があります。 Lint を通したり IDE やテキストエディタのサポートで事前に検証することも必要になってくるでしょう。(設定でキャッシュを無効にもできるので、実行しながら修正することも可能です)

※LEGACYHTML5 モードを採用することで XHTML でなくても動作します。

Thymeleaf はドキュメントが充実しており、一通りの使い方は Documentation – Thymeleaf: java XML/XHTML/HTML5 template engine のリンク先に記述されています。そのページにある PDF を手元に置いておくとよいでしょう。

今日は入門編として主に使うものを簡単に紹介してみます。

テキスト出力

デフォルトで HTML エスケープをして出力してくれます。 HTML エスケープして欲しくない場合は th:utext を利用しますが、デフォルトでエスケープしてくれることで XSS の問題を回避でき重要な機能です。

<span th:text="${message}">hogehoge</span>
<input type="text" name="username" th:value="${username}" />

特定条件で出力

th:if を指定し条件が成立する場合処理をさせることができます。子ノードに対しても処理を行わなくなります。
Java にはない unless 文も提供しています。

<span th:text="${message}" th:if="#{action.hasMessage}">hogehoge</span>

URL 出力

先ほどの例でも出しました。 @{ } で囲むことで Servlet コンテキストパスを自動解決してくれます。

<a href="index.html" th:href="@{/home}">Link</a>

綺麗な URL

REST チックにモデルの id などを URL に含めたい場合は __${ }__ を利用します。

<a href="user.html" th:href="@{/users/__${user.id}__/edit}">Username</a>

特定条件のときに class を追加

入力パラメーターがエラーで、赤文字でメッセージを表示するために error クラスを追加したい場合がありますが、そんなときは th:classappend を利用します。 th:class は置き換えになります。

<input type="text" th:classappend="${action.hasError('name')}? 'error'" />

繰り返しの状態管理

コレクションを一覧で出力するときに、行番号表示や奇数だけ色を変えたいという要望が時々あります。

繰り返しには th:each を利用しますが、インデックス、行番号、奇数といった状態が提供されています。

<ul>
    <li th:each="user,stat : ${users}" th:class="${stat.odd}? 'odd'" th:text="${stat.count}"></li>
</ul>

プログラムで処理するときに出力しない

デザイナーさんたちは画面を表現するために、一覧画面に数行記述してきます。

プログラムでは繰り返し処理を行うため、最初の行以外を削除してしまいますが
th:remove を利用することで出力を抑制できます。

これでデザイナーさんたちが記述した内容を削除して嫌われることもなくなりますね!

<ul>
    <li th:each="item : ${items}" th:text="${item.name}">Item1</li>
    <li th:remove="all">Item2</li>
    <li th:remove="all">Item3</li>
    <li th:remove="all">Item4</li>
    <li th:remove="all">Item5</li>
</ul>

他にもページ分割であったり、マクロであったり、 static メソッドの呼び出しであったり、独自カスタマイズなど紹介したい機能がたくさんありますが、今日はここまでにしたいと思います。


 いかがでしたでしょうか。 th:xxxx がついている箇所や JavaScript で操作する id,class には一定のルールを設けて削除せず相談してもらうことを XHTML 同様に決めておく必要はあるでしょう。しかしこのライブラリによってデザイナーさんたちとの協業を可能にし、距離を縮められると考え利用しています。

今回は Servlet と連携したサンプルを Github に置いてみました。

https://github.com/nulab/thymeleaf-servlet-example

clone して mvn eclipse:eclipse すると Eclipse でコードをいじれる形にしていますので、是非実際に触ってみてください。

なお Thymeleaf は開発が盛んで今はバージョン 1.1.5 ですが、直に 2.0 がリリースされるようです。また Spring Framework との連携も公式に提供されているので、 Spring Framework を利用されている方は一度連携を試してみるといいかもしれません。

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる