URLのテンプレート化

前回に引き続き、Javaアプリケーション用テンプレートエンジン「Thymeleaf」の使い方を紹介する。標準の文法セットである「Standard Dialects」に用意された文法として#{●●●}と${●●●}、そして*{●●●}という3種類を取り上げたが、Standard Dialectsにはもうひとつ「@{●●●}」という記述方法が存在する。これはURL形式の文字列を生成するための構文である。

例えば次のように記述したとする。

@{/hoge/piyo}

テンプレートエンジンで処理を行った結果、この部分はコンテキストルート以下の「/hoge/piyo」というパスに置き換えられる。この記述法の大きなメリットは、次のように${●●●}と組み合わせることで、パラメータとしてサーバ側のオブジェクトの値を渡すことができるという点である。

@{/hoge/piyo(parameter=${param1}}

この例の場合、もし変数param1の値が「foo」であったとすれば、生成されるURLは「/hoge/piyo?parameter=foo」となり、param1が「bar」であれば、URLは「/hoge/piyo?parameter=bar」となる。このように動的にURLを生成することができる。

この構文は、aタグのth:href属性や、fromタグのth:action属性とセットで使用される。th:hrefはaタグのリンク先を指定するためのもの属性であり、次のように記述する。

<div style="font-size:20px"><strong>
    <a href="link.html"
       th:href="@{http://localhost:8080/ThymeleafSample/link.html(par=${param})}">リンク</a>
</strong></div>

${param}の部分はサーバ側のコンテキストに設定されたparamの値に置き換わる。例えばサーバ側プログラムでparamの値を次のように設定したとする。

// WebContextを作成
WebContext ctx = new WebContext(request, request.getLocale());
// オブジェクトをセット
ctx.setVariable("param", "value");
// テンプレートの処理を実行
String result = engine.process("link", ctx);

すると、テンプレートエンジンの処理によって生成されるHTMLコードは以下のようになる。

<div style="font-size:20px"><strong>
    <a href="http://localhost:8080/ThymeleafSample/link.html?par=value" shape="rect">リンク</a>
</strong></div>

formタグのアクションを指定する場合でも、th:action属性で同様の記法を利用することができる。

Thymeleafをスタンドアロンプログラムで利用する

これまでの例では、Webアプリケーション(Servlet)におけるHTMLの生成に対してThymeleafのテンプレートエンジンを利用してきた。しかしThymeleafには、Webアプリケーションだけでなく、スタンドアロンのアプリケーションから利用するための仕組みも備えられている。そこで、今度はServletを利用しない、スタンドアロンのJavaプログラムにおいて、XMLコードの生成にThymeleafを利用してみよう。

鍵となるのはTemplateResolverである。Webアプリケーションの場合には、ServletContextTemplateResolverというクラスを利用することで、Servletコンテキスト内でのテンプレート処理を適切に行うことができた。Thymeleafに標準で用意されたTemplateResolverとしては、その他にファイルからテンプレートを読み込むFileTemplateResolver、URLからテンプレートを読み込むUrlTemplateResolver、そしてクラスローダを利用してテンプレートを読み込むClassLoaderTemplateResolverが用意されている。ここでは、もっとも一般的であるFileTemplateResolverを使ってみる。

FileTemplateResolverもServletContextTemplateResolverと同様にTemplateResolverクラスのサブクラスなので、基本的な使い方は変わらない。以下はプレフィックスとして「C:\templates\」フォルダを、サフィックスとして拡張子「.xml」をセットしてFileTemplateResolverオブジェクトを生成した例である。今回はXMLの生成に利用するので、テンプレートモードとしてはTemplateMode.XMLを設定している。

// TemplateResolverを作成
FileTemplateResolver resolver = new FileTemplateResolver();
resolver.setTemplateMode(TemplateMode.XML);  // テンプレートモード
resolver.setPrefix("C:\\templates\\");  // プレフィックス
resolver.setSuffix(".xml");                // サフィックス

テンプレート処理に利用するコンテキストとしてはWebアプリケーションの場合はWebContextクラスを利用したが、スタンドアロンの場合には標準的な実装としてContextクラスが用意されているので、これを利用することにする。以下は、Contextを生成してAccountオブジェクトのリストをセットする例である。これも基本的な手順はWebContextの場合と同様である。

// Contextオブジェクトを作成
Context ctx = new Context();
// オブジェクトをセット
List<Account> accounts = new ArrayList<Account>();
accounts.add(new Account("user1", "hogehoge"));
accounts.add(new Account("user2", "piyopiyo"));
accounts.add(new Account("user3", "hogepiyo"));
ctx.setVariable("accounts", accounts);

TemplateEngineには、上で生成したFileTemplateResolverオブジェクトをセットする。テンプレート処理の実行はこれまでと同様にprocess()メソッドで行えばよい。以下に、テンプレートとして「sample.xml」を、プロパティファイルとして「sample.properties」を用意し、それをもとに「result.xml」を生成するプログラムの例を示す。

package jp.mycom.toolde.Thmeleaf;


import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.thymeleaf.*;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.FileTemplateResolver;


public class ThymeleafSample {
  public static void main(String[] args) {


    // TemplateResolverを作成
    FileTemplateResolver resolver = new FileTemplateResolver();
    resolver.setTemplateMode(TemplateMode.XML);  // テンプレートモード
    resolver.setPrefix("C:\\templates\\");  // プレフィックス
    resolver.setSuffix(".xml");                // サフィックス

    // Contextオブジェクトを作成
    Context ctx = new Context();

    // オブジェクトをセット
    List<Account> accounts = new ArrayList<Account>();
    accounts.add(new Account("user1", "hogehoge"));
    accounts.add(new Account("user2", "piyopiyo"));
    accounts.add(new Account("user3", "hogepiyo"));
    ctx.setVariable("accounts", accounts);

    // TemplateEngineを作成
    TemplateEngine engine = new TemplateEngine();
    engine.setTemplateResolver(resolver);
    // テンプレートの処理を実行
    String result = engine.process("sample", ctx);


    // 結果を出力
    PrintWriter writer = null;
    try {
      writer = new PrintWriter(new FileWriter("result.xml"));
      writer.println(result);
    } catch (IOException ex) {
      ex.printStackTrace();
    } finally {
      if (writer != null) {
        writer.close();
      }
    }
  }
}

sample.xmlの記述は次のようにした。

<?xml version="1.0" encoding="UTF-8"?>


<acountlist xmlns:th="http://www.thymeleaf.org">


  <title th:text="#{title}">タイトル</title>


  <account th:each="account: ${accounts}">
    <id th:text="${account.id}">ユーザID</id>
    <password th:text="${account.password}">パスワード</password>
  </account>


</acountlist>

また、sample.propertiesには次のように記述した。

title=XMLにおけるTymeleafの利用例

ここで使っているのはStandard Dialectsに用意された文法だけなので、テンプレートの内容についてはServletの例とほぼ同様である。このプログラムを実行して生成されたresult.xmlは次のようになった。

このように、Webアプリケーションだけでなく、さまざまな場面でのテキスト処理に活用できるのがThymeleafの強みである。さらにTemplateResolverやDialectsのカスタマイズも可能なため、ニーズに合わせた柔軟な対応が可能である。公式サイトのドキュメントにはDiarectsの拡張方法などもまとめられているので、より深く知りたい方は参照してみるといいだろう。