LoginSignup
3
6

More than 5 years have passed since last update.

Thymeleafを拡張する(UtilityObject編)

Posted at

Thymeleafに独自の機能を追加する方法はいくつかありますが、今回はUtilityObjectを追加する方法をまとめます。
以下のドキュメントを参考にしています。
http://www.thymeleaf.org/doc/tutorials/3.0/extendingthymeleaf.html

環境

  • Thymeleaf3.0.8
  • spring 4.3.5

UtilityObjectとは

#datesや#listsみたいなやつです。
http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects

作り方

本体を作成する

実際に処理を行うクラスとメソッドを作成します。ここは特に何も考えずに作成していいです。
今回はJapaneseDateをフォーマットして文字列を返却するメソッドを作成してみます。

public class SampleObject {

    DateTimeFormatter jpFormatter = DateTimeFormatter.ofPattern("Gyy年MM月dd日",
            Locale.JAPAN);

    public String format(JapaneseDate date) {
        if (date == null) {
            return null;
        }

        return jpFormatter.format(date);
    }
}

拡張を管理するクラスを作成する

独自拡張を行うにはそれを管理するDialectクラスを作成する必要があります。
拡張のやり方で実装するクラスが変わりますが、今回はIExpressionObjectDialectを実装したクラスを作成します。
StantdardDialectクラスに倣って、AbstractDialectクラスも継承しておきます。

が、UtilityObjectを拡張する場合はその前に、IExpressionObjectFactoryを実装したFactoryクラスを作成する必要があります。
このFactoryクラスで、本体となるSampleObjectクラスをインスタンス化します。

Factoryクラスを作成する

public class SampleExpressionObjectFactory implements IExpressionObjectFactory {

    private static final String sampleExcepressionObjectName = "sample";

    @Override
    public Set<String> getAllExpressionObjectNames() {
        Set<String> nameSet = new HashSet<>();
        nameSet.add(sampleExcepressionObjectName);
        return nameSet;
    }

    @Override
    public Object buildObject(IExpressionContext context, String expressionObjectName) {
        if (Objects.equals(sampleExcepressionObjectName, expressionObjectName)) {
            return new SampleObject();
        }
        return null;
    }

    @Override
    public boolean isCacheable(String expressionObjectName) {
        return true;
    }
}

getAllExpressionObjectNamesメソッドでは、追加するUtitlityObjectを呼び出すための文字列をSetで返却させます。
今回は、#sampleという形式で処理を呼び出せるようにしようとしています。

buildObjectメソッドで、UtilityObjectを呼び出すための文字列と、実際のUtilityObjectを紐づけます。
sampleという文字列に対しては、SampleObjectインスタンスを返却するようにしています。

isCacheableメソッドはオブジェクトをキャッシュするかどうかを決めます。
今回はとりあえずtrueにしています。
Objectごとに指定することができます。

Dialectクラスを作成する

public class SampleDialect extends AbstractDialect implements IExpressionObjectDialect {

    public SampleDialect() {
        super("sample");
    }

    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() {
        return new SampleExpressionObjectFactory();
    }
}

コンストラクタでこのDialectの名前を決めます。何に利用されているのかはよくわかっていません。。
呼び出し階層を調べてみましたが、printConfigurationというメソッドからしか呼び出されていないので、ログ出力用なのでしょうか。

getExpressionObjectFactoryメソッドで、先ほど作成したFactoryクラスを返却するようにします。

Dialectを登録する

ThymeleafのTemplateEngineに今回作成したDialectクラスを追加します。
今回、Thymeleafの設定はspring-mvc.xmlに定義しているので以下のようにadditionalDialectsに追加します。

<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
  <property name="templateResolver" ref="templateResolver" />
  <property name="additionalDialects">
    <set>
      <bean class="sample.SampleDialect" />
    </set>
  </property>
</bean>

動かしてみる

以下のようなControllerとhtmlを作成して動作を確認しました。

@Controller
public class HelloController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {

        model.addAttribute("date", JapaneseDate.now());

        return "home";
    }

}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home</title>
</head>
<body>
  <h1>Hello world!</h1>
  <p th:text="${#sample.format(date)}">hogehoge</p>
</body>
</html>

Hello Worldの下に「平成yy年MM月dd日」(現在の日付)が表示されていれば完成です。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6