Thymeleaf Springのpropertyを利用したUtility Objectを作る

# 前提
- Spring Boot 1.3
	+ Parent POMとしてspring-boot-starter-parentを使用
- Thymeleaf 2.1.4

# やりたいこと

## Thymeleafで何個も似たようなことを書くのを止めたい
`th:text`や`th:href`に記述する内容が↓みたいに長くなってきた&大量に似たような記述をしなくちゃいけなくなってきたので、何とかしたい。

```html:problem.html
<link rel="stylesheet" type="text/css" th:href="@{${@environment.getProperty('testapp.static-file.path')}/css/style.css?ver=${@environment.getProperty('testapp.version')}}"/>
<link rel="stylesheet" type="text/css" th:href="@{${@environment.getProperty('testapp.static-file.path')}/css/layout.css?ver=${@environment.getProperty('testapp.version')}}"/>
<link rel="stylesheet" type="text/css" th:href="@{${@environment.getProperty('testapp.static-file.path')}/css/debug.css?ver=${@environment.getProperty('testapp.version')}}"/>
```

具体的には、「propertyから値を読み込んで、それをもとにURLを生成処理を行うfunction」を作って、記述をスッキリさせたい。

# アプローチ
## Utility Objectを作る
[カスタム Utility Object を追加する ー Thymeleaf ｜ Developers.IO](http://dev.classmethod.jp/client-side/thymeleaf/custome-utility-objects/)を読みながら自分なりにやってみる。

### カスタム Utility Objectの実装と登録

まずは、実際にURL生成を行うためのクラス(`PathBuilder`)を実装。

```java:PathBuilder.java
@Component public class PathBuilder {

    @Value("${testapp.static-file.path}")
    private String staticFilePath;

    @Value("${testapp.version}")
    private String projectVersion;

    public String build(String path) {
        return staticFilePath + path + "?ver=" + projectVersion;
    }
}
```

次に、Dialectクラス(`TestAppDialect`)を作って、`PathBuilder`を登録
(ここでは、PathBuilderを格納したMapを使って初期化するようにした)

```java:TestAppDialect.java
@Component
public class TestAppDialect extends AbstractDialect implements IExpressionEnhancingDialect {

    private Map<String, Object> expressionObjects;

    public TestAppDialect(Map<String, Object> expressionObjects) {
        super();
        this.expressionObjects = expressionObjects;
    }

    @Override
    public Map<String, Object> getAdditionalExpressionObjects(
        IProcessingContext iProcessingContext) {
        return expressionObjects;
    }

    @Override
    public String getPrefix() {
        return null;
    }
}
```

つづけて、`TestAppDialect`をBeanとして登録

```java:WebMvcConfig.java
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
  //...

    @Bean
    TestAppDialect testAppDialect() {
        return new TestAppDialect(ImmutableMap.of("pathBuilder", pathBuilder()));
    }

    @Bean
    PathBuilder pathBuilder() {
        return new PathBuilder();
    }

  //...
}

```

## html上でUtility Objectを使用する
カスタムUtility Objectは、`${#object.method}`という形式でcallできる。
ということで、問題だった箇所を↓のように書き換える。

```html:solved.html
<link rel="stylesheet" type="text/css" th:href="@{${#pathBuilder.build('/css/style.css')}}"/>
<link rel="stylesheet" type="text/css" th:href="@{${#pathBuilder.build('/css/layout.css')}}"/>
<link rel="stylesheet" type="text/css" th:href="@{${#pathBuilder.build('/css/debug.css')}}"/>
```

### おまけ: pomに記述したversion情報をpropertyとして使う
`testapp.version`
には、pom.xmlに記載されているアプリケーションのバージョンを入れたかったので、
↓のように記述。

```properties:application.properties
testapp.version=@pom.version@
```

`spring-boot-starter-parent`を使う場合、
maven-resources-pluginの設定は自動でなされるんだけど、
delimiterが`${..}`じゃなくて`@..@`になってるのでそこだけ注意。
c.f [Spring Boot Reference Guilde - 45.7.1 Automatically expand info properties at build time](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-application-info-automatic-expansion)