[Thymeleaf] 式ユーティリティオブジェクト

## 概要

- 久しぶりにThymeleafを真面目に触ってみたら結構忘れていたので、リハビリも兼ねての備忘
- 特に式ユーティリティは公式ドキュメントをみてもアウトプットのイメージが直感で分からないので、あくまで自分用にメモ

## 検証環境

- SpringBoot + Thymeleaf
 - SpringBoot上でSpringMVCのビューテンプレートエンジンとして動かす
- spring-boot-starter-thymeleaf : 2.2.4.RELEASE
 - thymeleaf-spring5 : 3.0.11.RELEASE
 - thymeleaf-extras-java8time : 3.0.4.RELEASE

## 式ユーティリティオブジェクト

- 式の中で一般的なタスクを実行するのを助けてくれるもの

### 公式

- https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-utility-objects
- https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-b-expression-utility-objects

- [日本語版] https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html

## 検証

### サンプルController

```java:HelloController.java
@Controller
public class HelloController {
    @RequestMapping
    public String exec(Model model) {
        model.addAttribute("string", "Hello");
        model.addAttribute("stringNull", null);
        model.addAttribute("stringArray", new String[]{"Foo", "Bar", "Baz"});
        model.addAttribute("stringList", Arrays.asList("Hoge", "Fuga", "Piyo"));
        model.addAttribute("STRING", "HELLO");
        model.addAttribute("number", 1000);
        return "hello";
    }
}
```

### #strings

- Stringオブジェクトに対するユーティリティメソッド群

|メソッド（書き方）|結果|メモ|
|---|---|---|
|${#strings.isEmpty(string)}|true|<ul><li>文字列が空（またはnull）かどうかをチェックする</li><ul>|
|${#strings.defaultString(stringNull, 'default')}|default|<ul><li>'isEmpty()'を実行する</li><ul><li>false：その文字列を返す</li><li>true：指定したデフォルト文字列を返す</li></ul></ul>|
|${#strings.contains(string, 'el')}|true|<ul><li>文字列にフラグメントが含まれているかどうかをチェックする</li><li>大文字小文字の違いを判別する</li></ul>|
|${#strings.containsIgnoreCase(string, 'EL')}|true|<ul><li>大文字小文字の違いを無視して判定する|
|${#strings.prepend(string, 'prefix:')}|prefix:Hello|<ul><li>先頭に指定した文字列を追加する</li></ul>|
|${#strings.append(string, ':suffix')}|Hello:suffix|<ul><li>末尾に指定した文字列を追加する</li></ul>|
|${#strings.toUpperCase(string)}|HELLO|<ul><li>大文字に変換する</li></ul>|
|${#strings.toLowerCase(string)}|hello|<ul><li>小文字に変換する</li></ul>|
|${#strings.arrayJoin(stringArray, ',')}|Foo,Bar,Baz|<ul><li>文字を連結する</li></ul>|
|${#strings.listJoin(stringList, ',')}|Hoge,Fuga,Piyo|<ul><li>文字を連結する</li></ul>|
|${#strings.length(string)}|5|<ul><li>文字列の長さを計算する</li></ul>|
|${#strings.abbreviate(string, 4)}|H...|<ul><li>与えられたテキストが最大サイズnになるよう省略処理する<br>もしテキストがそれよりも大きい場合は、切り取られて最後に"..."がつく</li><li>最大サイズnは処理後の...を含むため、最小で3</li></ul>|
|${#strings.equals(string, stringNull)}|false|<ul><li>NULLセーフの文字列比較をする</li></ul>|
|${#strings.equalsIgnoreCase(string, STRING)}|true|<ul><li>NULLセーフかつ大文字小文字の違いを無視した文字列比較をする</li></ul>|

### #numbers

- 数値オブジェクトに対するユーティリティメソッド群

|メソッド（書き方）|結果|メモ|
|---|---|---|
|${#numbers.formatInteger(number, 5)}|01000|<ul><li>整数の最小桁数を設定する</li><li>最小桁数に満たない場合は0埋めする</li></ul>|
|${#numbers.formatInteger(number, 3, 'COMMA')}|1,000|<ul><li>整数の最小桁数と千の位の区切り文字を設定する</li><li>'POINT'、'COMMA'、'WHITESPACE'、'NONE'または'DEFAULT'</li></ul>|

### #arrays

- 配列に対するユーティリティメソッド群

|メソッド（書き方）|結果|メモ|
|---|---|---|
|${#arrays.length(stringArray)}|3|<ul><li>配列の長さを計算する</li></ul>|
|${#arrays.isEmpty(stringArray)}|false|<ul><li>配列が空かどうかをチェックする</li></ul>|

### #lists

- リストに対するユーティリティメソッド群

|メソッド（書き方）|結果|メモ|
|---|---|---|
|${#arrays.length(stringList)}|3|<ul><li>配列の長さを計算する</li></ul>|
|${#arrays.isEmpty(stringList)}|false|<ul><li>配列が空かどうかをチェックする</li></ul>|

### #date, #calendars

- java.util.Date と java.util.Calendarオブジェクト用のユーティリティメソッド群
- 今後Java8で（少なくとも私が）実装する際に、DateとCalendarは使わないので省略
 - なんのこっちゃという方は、「[Java8の日時APIはとりあえずこれだけ覚えとけ](https://qiita.com/tag1216/items/91a471b33f383981bfaa)」によくまとめられているので参照ください

### #temporals

- **個人的に今回まとめておきたかったのはこれ**
- LacalDateやLocalDataTimeを扱うことができるユーティリティメソッド群
- `thymeleaf-extras-java8time`に含まれている
 - spring-boot-starter-thymeleaf:2.Xからデフォルト含まれるようになった（1系なら個別で追加すれば利用可能）

|メソッド（書き方）|結果|メモ|
|---|---|---|
|`${#temporals.format(time, 'yyyy/MM/dd HH:mm:ss')}`|2020/02/08 12:34:56|<ul><li>日付をフォーマットする</li><li>LocalDateでも同様</li><li>'yyyy/M/d'にすれば、2020/2/8になる</li><li>'yyyy年MM月dd日 HH時mm分'とかもOK</li></ul>|
|${#temporals.year(date)}|2020|<ul><li>年を取得する</li></ul>|
|${#temporals.month(date)}|2|<ul><li>月を取得する</li></ul>|
|${#temporals.day(date)}|8|<ul><li>日を取得する</li></ul>|
|${#temporals.dayOfWeekName(date)}|土曜日|<ul><li>曜日を取得する</li></ul>|
|${#temporals.hour(time)}|12|<ul><li>時を取得する</li></ul>|
|${#temporals.minute(time)}|34|<ul><li>分を取得する</li></ul>|
|${#temporals.second(time)}|56|<ul><li>秒を取得する</li></ul>|

- 他にも色々あるけど、詳細はjavadocを参照ください  
https://github.com/thymeleaf/thymeleaf-extras-java8time

## まとめ

- この手の処理をサーバサイド(Thymeleaf)で行うかは意見が分かれるとは思いますが、できることを把握する・自分の中の選択肢を増やすことは重要だと考えています
- 今回まとめたものは一部で、他にも便利なユーティリティ群があるので、ぜひ公式ドキュメントやjavadocを参照してみてください
- 気が向いたら記事をアップデートしようと思います