Thymeleafとは

Thymeleaf」は、XHTMLとHTML5、そしてXMLをサポートしたJavaアプリケーション向けののテンプレートエンジンである。テンプレートエンジンとは、テンプレートと呼ばれる雛形と、個別に用意された入力データを合成して、その結果を出力するソフトウェアの総称。見た目を記述するコードと、ロジック/データを記述するコードが分離できることや、共通部分のコード量を減らすことができるなどといったメリットがある。特にWebアプリケーション開発においては、HTMLの出力に対してテンプレートエンジンを利用するケースも多い。

Thymeleafの場合は、XHTMLやHTML5によるWebアプリケーション向けのテンプレートの利用に加えて、XMLを出力するスタンドアロンアプリケーションにも適用することができる。また、Webアプリケーション開発においては「Spring MVC」とのインテグレーションをサポートする追加モジュールも提供されており、これを利用すればUIとデータモデルのよりシームレスな連携を実現することができる。

テンプレートには、入力データに置き換える部分を示すコードを埋め込んでおく必要がある。Thymeleafの場合は、特別なタグや属性を指定することによってこれを実現する。標準では、単純なテキストデータへの置き換えの他に、データモデル・オブジェクトが持つ変数や、複数の値を持つコンテナ・オブジェクト、そしてURL形式の文字列に置き換えるための文法が用意されている。それに加えて、独自の属性を定義することもできるようになっており、これらを利用することによって、汎用性の高い柔軟なテンプレートを、シンプルなコードで記述することが可能となる。

テンプレートファイルの作成

Thymeleafに標準で用意されている文法セットは「Standard Dialect」と呼ばれている。今回はServletによるWebアプリケーションにおいて、このStandard Dialectで作成したテンプレートを利用してみよう。

Thymeleafはこのページよりダウンロードできる。本稿執筆時点での最新版はバージョン1.0.0-beta4。配布ファイルを展開するとapidocs、dist、libの3つのフォルダがある。このうち、distにある「thymeleaf-1.0.0-beta4.jar」と、libにある3つのjarファイルが必要。また、Spring MVCと組み合わせて使用する場合には「thymeleaf-spring3-1.0.0-beta4.jar」が必要となる。

まずはテンプレートファイルと、データモデルとなるファイルを作成しよう。テンプレートファイルは、「hello.html」というファイル名で作成し、中身はXHTML形式で次のように記述する。

<!DOCTYPE html SYSTEM
          "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-1.dtd">


<html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:th="http://www.thymeleaf.org">

  <head>
    <title th:text="#{hello.title}">タイトル</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  </head>

  <body>
    <h2 th:text="#{hello.message}">メッセージ</h2>
  </body>
</html>

この場合、Thymeleaf用のカスタムタグライブラリに「th」というプレフィックスを設定しているので、「th:」に続くタグや属性が、テンプレートエンジンによって別の値に置き換えのために利用される。「th:text」はStandard Dialectに用意されたテキストデータへの置き換えのための属性であり、この属性が付けられたタグの部分が、属性値で指定されたデータへと置き換えられることになる。

th:text属性の値は「#{●●●}」という形式で記述する。「●●●」は挿入されるテキストデータを表すプロパティ名で、実際のテキストデータはプロパティファイルを使って定義する。プロパティファイルは、hello.html用のものであれば「hello.properties」という名前で作成し、次のようにプロパティ名とテキストデータの関連を記述する。

hello.title=Tymeleafのサンプル
hello.message=これはThymeleafを使ったサンプルです。

これで、「th:text="#{hello.title}"」属性を持つタグの内容が「Tymeleafのサンプル」に、「th:text="#{hello.message}"」属性を持つタグの内容が「これはThymeleafを使ったサンプルです。」に置き換えられることになる。

Servletによるテンプレートエンジンの利用

続いてサーバ側のServletプログラムを作成する。Thymeleafにおけるテンプレートの処理の核となるのが、TemplateEngineクラスとTemplateResolverクラスである。Servletコンテキストから利用する場合のTemplateResolverとしては、ServletContextTemplateResolverクラスが用意されている。まずは、次のようにしてServletContextTemplateResolverオブジェクトを生成し、テンプレートファイルのフォーマットやプレフィックス、サフィックスなどの設定を行う。

// TemplateResolverを作成
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setTemplateMode(TemplateMode.XHTML);  // テンプレートモード
resolver.setPrefix("/WEB-INF/templates/");  // プレフィックス
resolver.setSuffix(".html");                // サフィックス
resolver.setCacheTTLMs(3600000L);  // キャッシュの有効時間

テンプレートモードはXHTMLの他にXMLやHTML5、VALIDXHTMLなどがあり、いずれもTemplateModeクラスに定義されている。プレフィックスとサフィックスの設定は、テンプレートファイルの場所やファイル名を表すことになる。上記の設定の場合、「/WEB-INF/templates/xxxx.html」(xxxxは任意のファイル名。後述)がテンプレートファイルであることを表す。

次に、TemplateEngineオブジェクトを作成し、次のようにsetTemplateResolver()メソッドを使ってTemplateResolverオブジェクトをセットする。

// TemplateEngineを作成
TemplateEngine engine = new TemplateEngine();
engine.setTemplateResolver(resolver);

このTemplateEngineオブジェクトが、セットされたTemplateResolverを利用してテンプレート処理を実施することになる。テンプレート処理はTemplateEngineのprocess()メソッドで行うが、このメソッドの第2引数には処理を実行するためのコンテキストを定義したIContextインタフェースのインスタンスを渡す必要がある。Servletの場合は、このインタフェースのWeb用実装クラスとしてWebContextが用意されているので、これを利用して次のようにprocess()を呼び出せばよい。第1引数にはテンプレートファイルのファイル名を指定する。今回の例の場合、テンプレートを「hello.html」で作成し、サフィックスを「.html」としたので、process()に渡す文字列は「hello」となる。requestはHttpServletRequestオブジェクトである。

// WebContextを作成し、テンプレートの処理を実行
WebContext ctx = new WebContext(request, request.getLocale());
String result = engine.process("hello", ctx);

テンプレートを処理した結果はStringオブジェクトとして返されるので、あとはこれをそのままクライアントに送信すればよい。以下に、hello.htmlを処理するServletクラスのコード全体を掲載する。

package jp.co.mycom.toolde.Thymeleaf;


import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import org.thymeleaf.*;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;


@WebServlet(name="ThymeleafSample", urlPatterns={"/hello"})
public class ThymeleafSample extends HttpServlet {


  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");

    // TemplateResolverを作成
    ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
    resolver.setTemplateMode(TemplateMode.XHTML);  // テンプレートモード
    resolver.setPrefix("/WEB-INF/templates/");  // プレフィックス
    resolver.setSuffix(".html");                // サフィックス
    resolver.setCacheTTLMs(3600000L);  // キャッシュの有効時間

    // TemplateEngineを作成
    TemplateEngine engine = new TemplateEngine();
    engine.setTemplateResolver(resolver);

    // WebContextを作成し、テンプレートの処理を実行
    WebContext ctx = new WebContext(request, request.getLocale());
    String result = engine.process("hello", ctx);
    // System.out.println(result);

    // 結果をクライアントに送信
    PrintWriter out = response.getWriter();
    try {
      out.println(result);
    } finally {
      out.close();
    }
  }


  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    processRequest(request, response);
  }


  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    processRequest(request, response);
  }
}

「hello.html」と「hello.properties」は、TemplateResolverへの設定通り「/WEB-INF/templates/」に配置すればよい。ServletクラスのURLパターンを「"/hello"」としてあるので、プロジェクト名を「ThymeleafSample」とした場合、「http://hogehoge/ThymeleafSample/hello」へのリクエストでこのプログラムが実行されることになる。

Webブラウザからアクセスした結果はのようになり、テンプレートとして作成したXHTMLコードに、プロパティファイルに用意したテキストが挿入されていることが確認できる。

th:text属性を持つタグの内容が置き換えられている