Thymeleaf 3.0を試す その3 ユーティリティを作る

Thymeleaf 3.0を試す
Thymeleaf 3.0を試す その2 エスケープの有無

の続き。

今までパラメータとして文字列しか渡していませんでしたが、もちろん数値も扱えます。

〜
        String template = "[[${a}]] + [[${b}]] = [[${a+b}]]";

〜

        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);
〜


計算もView側でできるのがわかりますね。
実行結果

1000 + 20000 = 21000

3桁区切り

3ケタごとに区切り文字を入れたいというのはよくあることです。もちろんそれも標準で用意はされてはいます。一応。

〜
        String template = "[[${#numbers.formatInteger(a+b, 1, 'DEFAULT')}]]";
〜


実行結果

21,000

一応と書いたのは、見てわかる通りあほみたいに長いのが原因です。
実行しないとこのミスはわからないしこんなのいちいち書いてられないと思います。書いていたらおかしいと思わないといけませんよね。

オレオレutil

というわけで作ります。まずシンプルに何も考えず現在できる仕組みの中で考えてみましょう。

        //----------------------------------------------------------------------
        //追加したいユーティリティ
        //----------------------------------------------------------------------
        class OreOreUtil {
            public String num(int num){
                NumberFormat nf = NumberFormat.getInstance();
                return nf.format(num);
            }
        }
〜
        String template = "[[${oreore.num(a+b)}]]";
〜
        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);
        params.put("oreore", new OreOreUtil());
〜


実行結果

21,000

まずはこれで十分だと思います。しいて言えばユーティリティなのかパラメータなのかどうかがわかりにくいです。パラメータとして渡していますので。「#」は予約されていてパラメータの名前として使えないのでこうなります。

が、命名規則でどうにでもなるとは思いますので気になる人だけ次に進むとよいでしょう。

複雑化させる仕組みは必須ではないと思います。

まじめに実装する

dialectという拡張する仕組みがどうやらあるぽいです。全ソースコードを載せます。

import java.text.NumberFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.context.IContext;
import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.dialect.IExpressionObjectDialect;
import org.thymeleaf.expression.IExpressionObjectFactory;

public class Thymeleaf3 {

    public static void main(String[] args) {

        //----------------------------------------------------------------------
        //追加したいユーティリティ
        //----------------------------------------------------------------------
        class OreOreUtil {
            public String num(int param){
                NumberFormat nf = NumberFormat.getInstance();
                return nf.format(param);
            }
        }
        
        //----------------------------------------------------------------------
        //「#oreore」という名前でOreOreUtilにアクセスさせるためのしくみ
        //----------------------------------------------------------------------
        class OreOreDialect implements IExpressionObjectDialect{
            
            final static String KEY = "oreore";
            
            final Set<String> names = new HashSet<String>(){
                {add(KEY);}
            };
            
            @Override
            public IExpressionObjectFactory getExpressionObjectFactory() {
                return new IExpressionObjectFactory() {
                    
                    @Override
                    public Set<String> getAllExpressionObjectNames() {
                        return names;
                    }

                    @Override
                    public Object buildObject(IExpressionContext context, String expressionObjectName) {
                        if(KEY.equals(expressionObjectName)){//名前が一致したなら
                            return new OreOreUtil();
                        }
                        return null;
                    }

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

            @Override
            public String getName() {
                return "OreOreUtilDialect";
            }
        }
        
        //----------------------------------------------------------------------
        //ここから下が実行
        //----------------------------------------------------------------------
        
        
        //準備
        TemplateEngine engine = new TemplateEngine();
        //オレオレ設定追加
        engine.addDialect(new OreOreDialect());


        String template = "[[${#oreore.num(a+b)}]]";


        Map<String, Object> params = new HashMap<>();
        params.put("a", 1000);
        params.put("b", 20000);

        IContext context = new Context(Locale.getDefault(), params);

        //生成
        String result = engine.process(template, context);

        //出力
        System.out.println(result);
    }
}

実行結果は同じです。

21,000

#oreore.num()でアクセスできているのがわかりますね。