Java のテンプレートエンジン Thymeleaf で Hello world

## 概要
- Java のテンプレートエンジン Thymeleaf で基本的な出力方法を使用する

## 今回の環境
- macOS Mojave
- OpenJDK 11.0.2
- Thymeleaf 3.0.11
- Gradle 5.6.2

## ソースコード

### ソースコード一覧

- build.gradle : Gradle 用のビルド設定ファイル
- MyApp.java : メインとなるクラス
- index.html : テンプレート HTML

```
├── build.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── MyApp.java
        └── resources
            └── templates
                └── index.html
```

### build.gradle

Gradle 用のビルド設定ファイル。
Thymeleaf 3.0.11 を指定。
gradle コマンドでプログラムを実行できる run タスクを使用するため、application プラグインを設定している。

```gradle
plugins {
  id 'java'
  id 'application'
}

group 'com.example'
version '1.0.0'

sourceCompatibility = 11

repositories {
  mavenCentral()
}

dependencies {
  // https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf
  implementation 'org.thymeleaf:thymeleaf:3.0.11.RELEASE'
}

application {
  mainClassName = 'com.example.MyApp'
}
```

### MyApp.java

メインとなるクラス。
Thymeleaf を利用して、オブジェクトの値を HTML テンプレートに埋め込んで出力する。

```java
package com.example;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import java.util.ArrayList;
import java.util.HashMap;

public class MyApp {

  public static void main(String[] args) {

    // ITemplateResolver インターフェースの一実装
    // テンプレートファイルを読み込むためのリゾルバクラス
    ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
    resolver.setPrefix("templates/");
    resolver.setSuffix(".html");
    resolver.setTemplateMode("HTML5");

    // テンプレート処理のメインクラスにリゾルバをセットする
    TemplateEngine engine = new TemplateEngine();
    engine.setTemplateResolver(resolver);

    // IContext インターフェースの一実装
    // ロケールや、テンプレートに埋め込むためのコンテキスト変数を持つ
    Context context = new Context();

    // シンプルなコンテキスト変数をセットする
    context.setVariable("myTitle", "Hello, world.");

    // コンテキスト変数として JavaBean オブジェクトをセットする
    MyData myData = new MyData("Hello, world.");
    context.setVariable("myData", myData);

    // コンテキスト変数として Map オブジェクトをセットする
    HashMap<String, String> myMap = new HashMap<String, String>();
    myMap.put("message", "Hello, world");
    context.setVariable("myMap", myMap);

    // コンテキスト変数として List オブジェクトをセットする
    ArrayList<String> myList = new ArrayList<String>();
    myList.add("Hello, world.");
    context.setVariable("myList", myList);

    // テンプレート処理を実行
    String result = engine.process("index", context);

    System.out.println(result);
  }

  // JavaBean クラス
  public static class MyData {

    private final String msg;

    public MyData(String message) {
      this.msg = message;
    }

    public String getMessage() {
      return msg;
    }
  }
}
```

### index.html

テンプレート HTML ファイル。
基本的なテンプレート機能を記述。

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${myTitle}"></title>
</head>
<body>

<div id="variable">
    <p th:text="${myData.message}"></p>
</div>

<div id="mydata" th:object="${myData}">
    <p th:text="*{message}"></p>
</div>

<div id="mymap" th:object="${myMap}">
    <p th:text="*{message}"></p>
</div>

<div id="mylist" th:each="item : ${myList}">
    <p th:text="*{item}"></p>
</div>

<div id="myif" th:if="${#strings.equals('Hello, world.', myData.message)}">
    'Hello, world' == [[${myData.message}]]
</div>

<div id="myunless" th:unless="${#strings.equals('Goodbye, world.', myData.message)}">
    'Goodbye, world.' != '[[${myData.message}]]'
</div>

<div id="myfalse" th:if="false">
    false
</div>

</body>
</html>
```

## 実行方法

run タスクを実行する。

```
$ gradle run
```

## 実行結果

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello, world.</title>
</head>
<body>

<div id="variable">
    <p>Hello, world.</p>
</div>

<div id="mydata">
    <p>Hello, world.</p>
</div>

<div id="mymap">
    <p>Hello, world</p>
</div>

<div id="mylist">
    <p>Hello, world.</p>
</div>

<div id="myif">
    'Hello, world' == Hello, world.
</div>

<div id="myunless">
    'Goodbye, world.' != 'Hello, world.'
</div>



</body>
</html>
```

## th: 属性の説明

### th:text

- th:text 属性に指定した値は要素の中のテキストを置き換える
- th:text には OGNL (Object-Graph Navigation Language) で値を指定できる

[Tutorial: Using Thymeleaf \(ja\)](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)

> この\${today}式は単純で「todayという名前の変数を取得する」という意味ですが、もっと複雑なこともできます（例えば\${user.name}は「user変数を取得してそのgetName()メソッドを呼び出す」という意味になります）。

### th:object

- th:object 属性にはオブジェクトを指定する
- *{member_name} にてオブジェクトのメンバ変数等を指定する

### th:each

- 配列やリストのループ処理に使用する

[Tutorial: Using Thymeleaf \(ja\)](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)

> Thymeleafの繰り返し処理で使用可能なのはjava.util.Listだけではありません。実際にth:each属性では、ほぼすべてのオブジェクトが繰り返し可能として扱われます：

### th:if と th:unless

- 条件によって表示・非表示をする際に使用する

### 

## 参考資料
- [Tutorial: Using Thymeleaf](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html)
- [Tutorial: Using Thymeleaf \(ja\)](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)
- [Overview \(thymeleaf 3\.0\.11\.RELEASE API\)](https://www.thymeleaf.org/apidocs/thymeleaf/3.0.11.RELEASE/)
- [Thymeleafで遊ぶ \- 気が向いたらなんか書く](http://misty-rc.hatenablog.com/entry/2013/07/12/101912)