Spring Boot + ThymeleafでSpringTemplateEngineをカスタマイズする

## やりたいこと

Thymeleafでリンクを生成する部分を拡張したい。

> ThymeleafでURLを指定するときのこれ

> ```html
> <img th:src="@{/image/hoge.jpg}">
> ```

ホスト名がふくまれてないときに、CDNのホスト名をリンクに追加したい。

> ex) `/image/hoge.jpg` -> `http://cdn.example.com/image/hoge.jpg`みたいにする

***
## 環境

- SpringBoot: 1.4.6.RELEASE
- Thymeleaf: 3.0.2.RELEASE

***
## 実装

`org.thymeleaf.linkbuilder.AbstractLinkBuilder`を拡張したクラスを作成します。

リンクを生成する部分を`buildLink`メソッドに実装します。

CDNのホストを追加する必要がない場合は、デフォルトのURLを利用したいので`StandardLinkBuilder`を利用しています。

`http://example.com/xxx`のように始まるリンクは、CDNのホストを追加しないようにしています。
> `if (UrlUtils.isAbsoluteUrl(link)) { ... }`のところ

```java
@Component
public class CustomLinkBuilder extends AbstractLinkBuilder {
    private static final Logger LOGGER = LoggerFactory.getLogger(CustomLinkBuilder.class);
    private final StandardLinkBuilder standardLinkBuilder = new StandardLinkBuilder();

    private String cdnHost() {
        return "http://localhost:8080";
    }

    private boolean isImageExtention(String path) {
        return StringUtils.endsWith(path, ".jpg")
                || StringUtils.endsWith(path, ".jpeg")
                || StringUtils.endsWith(path, ".png")
                || StringUtils.endsWith(path, ".gif");
    }

    private boolean isImageLink(UriComponents components) {
        final String path = components.getPath();
        return StringUtils.startsWith(path, "/image/") && this.isImageExtention(path);
    }

    @Override
    public String buildLink(final IExpressionContext context, final String base, final Map<String, Object> parameters) {
        String link = this.standardLinkBuilder.buildLink(context, base, parameters);
        LOGGER.debug("build link:{}", link);

        if (UrlUtils.isAbsoluteUrl(link)) {
            return link;
        }

        UriComponents components = UriComponentsBuilder.fromUriString(link).build();

        if (this.isImageLink(components)) {
            return this.cdnHost() + link;
        }

        return link;
    }
}
```
TemplateEngineに、↑のクラスを設定します。

デフォルトの`SpringTemplateEngine`に、`CustomLinkBuilder`を設定したかったので、`@Import(ThymeleafAutoConfiguration.class)`しています。

> `@Import`がないと`SpringTemplateEngine`のBeanが生成されるタイミングより前に、`@Bean SpringTemplateEngine customTemplateEngine() {}`が実行されるため、
> `@Autowired private SpringTemplateEngine templateEngine`がnullになるようです。

```java
@Configuration
@Import(ThymeleafAutoConfiguration.class)
public class WebConfig {
    @Autowired
    private SpringTemplateEngine templateEngine;
    @Autowired
    private CustomLinkBuilder customLinkBuilder;

    @Bean
    public SpringTemplateEngine customTemplateEngine() {
        this.templateEngine.setLinkBuilder(this.customLinkBuilder);
        return this.templateEngine;
    }
}
```

***

これで、`<img th:src="@{/image/hoge/main.jpg}">`のようにtemplateに書くと、
`<img src="http://localhost:8080/image/hoge/main.jpg">`と表示されます。

***

今回のソースはこちらになります。
参考になれば幸いです:sweat_smile:

- https://github.com/yamashiro0110/SpringBoot/blob/master/spring-boot-session-redis/src/main/java/com/example/springbootsessionredis/config/WebConfig.java

- https://github.com/yamashiro0110/SpringBoot/blob/master/spring-boot-session-redis/src/main/java/com/example/springbootsessionredis/view/CustomLinkBuilder.java