Thymeleafで独自UtilityObjectを作る

# 概要
Thymeleaf側で金額の数値(int)にカンマを入れたい。(例：1000→1,000)
もちろんThymeleafのデフォルトのUtilityメソッド`#numbers.formatInteger`で可能なので適用箇所が少なければ下記で十分だと思う。

```
${price < 1000 ? price : #numbers.formatInteger(price, 3, 'COMMA')}
```
ただ、適用箇所が多いとコピペするにしても各所でいちいち三項演算子を書きたくない。そこで金額専用の独自Utilityメソッドを作って下記のように書けば上記の三項演算子を書いたように出力したい。

```
${#customInt.price(price)}
```

ちなみに`price < 1000`をしないと、100未満の場合050みたいに0埋めされてしまう。なので条件式は`price < 100`でも良いと思う。

# 環境
- Java 1.8
- SpringBoot 2.2.1.RELEASE
- Thymeleaf 3.0.11.RELEASE

# サンプル

Thymeleafで金額にカンマを入れる独自Utilityメソッドのサンプル。

## UtilityObject(ExpressionObject)を作る

まずテンプレートで呼び出すメソッドを定義したUtilityObjectを作成する。

```java
package com.tamorieeeen.sample.thymeleaf;

/**
 *
 * @author tamorieeeen
 *
 */
public class CustomInt {

    public String price(int price) {

        return String.format("%,d", price);
    }
}
```

## Dialectを作る

次にDialectを作成する。

```java
package com.tamorieeeen.sample.thymeleaf;

import java.util.HashSet;
import java.util.Set;

import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.dialect.IExpressionObjectDialect;
import org.thymeleaf.expression.IExpressionObjectFactory;

/**
 *
 * @author tamorieeeen
 *
 */
public class CustomDialect implements IExpressionObjectDialect {

    private static final String EXPRESSION_NAME = "customInt";

    private static final Set<String> ALL_EXPRESSION_SET = new HashSet<String>() {
        {
            add(EXPRESSION_NAME);
        }
    };

    @Override
    public String getName() {

        return "CustomDialect";
    }

    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() {
        return new IExpressionObjectFactory() {

            @Override
            public boolean isCacheable(String expressionObjectName) {

                return false;
            }

            @Override
            public Set<String> getAllExpressionObjectNames() {

                return ALL_EXPRESSION_SET;
            }

            @Override
            public Object buildObject(IExpressionContext context, String expressionObjectName) {

                switch (expressionObjectName) {
                    case EXPRESSION_NAME:
                        return new CustomInt();
                    default:
                        return null;
                }
            }
        };
    }
}
```

## DialectをBeanに登録する

最後にConfigurationクラスを作成してDialectをBean定義する。

```java
package com.tamorieeeen.sample.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.tamorieeeen.sample.thymeleaf.CustomDialect;

/**
 *
 * @author tamorieeeen
 *
 */
@Configuration
public class ThymeleafConfig {

    @Bean
    public CustomDialect customDialect() {

        return new CustomDialect();
    }
}
```

## Thymeleaf側で使う

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="common :: meta_header('金額サンプル',~{::link},~{::script},~{::meta})">
</head>
<body>
    <h1>tamorieeeen</h3>
    <h2>金額サンプル</h3>
    <div>
        <p>[[${#customInt.price(price)}]]円</p>
    </div>
</body>
```
※Controllerは省略


# 参考
[Thymeleaf3で独自のDialectを作る](https://qiita.com/yoshikawaa/items/aba090f291f69185e6a5)
[Spring BootでThymeleafのDialectを追加する方法](https://qiita.com/suke_masa/items/e84a5b4e540fbb5dd475)
[Tutorial: Using Thymeleaf (ja)](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)