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日」(現在の日付)が表示されていれば完成です。