1. 序章

Thymeleaf は、Springと直接連携できるJavaテンプレートエンジンです。 ThymeleafとSpringの紹介については、この記事をご覧ください。

これらの基本的な機能に加えて、Thymeleafは、アプリケーションで一般的なタスクを実行するのに役立つ一連のユーティリティオブジェクトを提供します。

このチュートリアルでは、Thymeleaf3.0のいくつかの機能を備えた新旧のJavaDateクラスの処理とフォーマットについて説明します。

2. Mavenの依存関係

まず、ThymeleafとSpringをpom.xmlに統合するための構成を作成しましょう。

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>

thymeleafおよびthymeleaf-spring5の最新バージョンは、MavenCentralにあります。 Spring 4プロジェクトの場合、thymeleaf-spring5の代わりにthymeleaf-spring4ライブラリを使用する必要があることに注意してください。

さらに、新しいJava 8 Date クラスを使用するには、pom.xmlに別の依存関係を追加する必要があります。

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>

thymeleaf extras は、Java 8 Time APIとの互換性のために作成された、公式のThymeleafチームによって完全にサポートされているオプションのモジュールです。 式の評価中に、ユーティリティオブジェクトプロセッサとして#temporalsオブジェクトをContextに追加します。 これは、Object-Graph Navigation Language(OGNL)およびSpring Expression Language(SpringEL)で式を評価するために使用できることを意味します。

3. 新旧: java.utilおよびjava.time

Time パッケージは、Java SEプラットフォーム用の新しい日付、時刻、およびカレンダーAPIです。 この新しいAPIと古いレガシーDate APIの主な違いは、新しいAPIがタイムラインのマシンビューと人間ビューを区別することです。 マシンビューはエポックに関連する一連の整数値を表示しますが、人間ビューは一連のフィールド(たとえば、年、月、日)を表示します。

新しいTimeパッケージを使用するには、新しいJava8TimeDialectを使用するようにテンプレートエンジンを構成する必要があります。

private ISpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
    SpringTemplateEngine engine = new SpringTemplateEngine();
    engine.addDialect(new Java8TimeDialect());
    engine.setTemplateResolver(templateResolver);
    return engine;
}

これにより、標準方言のオブジェクトと同様の# Temporals オブジェクトが追加され、ThymeleafテンプレートからTemporalオブジェクトをフォーマットおよび作成できるようになります。

新しいクラスと古いクラスの処理をテストするために、次の変数を作成し、それらをモデルオブジェクトとしてコントローラークラスに追加します。

model.addAttribute("standardDate", new Date());
model.addAttribute("localDateTime", LocalDateTime.now());
model.addAttribute("localDate", LocalDate.now());
model.addAttribute("timestamp", Instant.now());

これで、ThymeleafのExpressionおよびTemporalsユーティリティオブジェクトを使用する準備が整いました。

3.1. フォーマット日付

最初に取り上げる関数は、 Date オブジェクト(Springモデルのパラメーターに追加される)のフォーマットです。 ISO8601形式を使用します。

<h1>Format ISO</h1>
<p th:text="${#dates.formatISO(standardDate)}"></p>
<p th:text="${#temporals.formatISO(localDateTime)}"></p>
<p th:text="${#temporals.formatISO(localDate)}"></p>
<p th:text="${#temporals.formatISO(timestamp)}"></p>

Date がバックエンド側でどのように設定されていても、選択した標準に従ってThymeleafに表示されます。 standardDate は、#datesユーティリティによって処理されます。 新しいLocalDateTime LocalDate 、および Instant クラスは、#temporalsユーティリティによって処理されます。

さらに、フォーマットを手動で設定する場合は、次を使用して設定できます。

<h1>Format manually</h1>
<p th:text="${#dates.format(standardDate, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDateTime, 'dd-MM-yyyy HH:mm')}"></p>
<p th:text="${#temporals.format(localDate, 'MM-yyyy')}"></p>

ご覧のとおり、 Instant クラスを#temporals.format(…)で処理することはできません。その結果、UnsupportedTemporalTypeExceptionが発生します。 さらに、 LocalDate のフォーマットは、時間フィールドをスキップして特定の日付フィールドのみを指定した場合にのみ可能です。

最終結果を見てみましょう:

3.2. 特定の日付フィールドを取得する

java.util.Date クラスの特定のフィールドを取得するには、次のユーティリティオブジェクトを使用する必要があります。

${#dates.day(date)}
${#dates.month(date)}
${#dates.monthName(date)}
${#dates.monthNameShort(date)}
${#dates.year(date)}
${#dates.dayOfWeek(date)}
${#dates.dayOfWeekName(date)}
${#dates.dayOfWeekNameShort(date)}
${#dates.hour(date)}
${#dates.minute(date)}
${#dates.second(date)}
${#dates.millisecond(date)}

新しいjava.timeパッケージの場合、#temporalsユーティリティを使用する必要があります。

${#temporals.day(date)}
${#temporals.month(date)}
${#temporals.monthName(date)}
${#temporals.monthNameShort(date)}
${#temporals.year(date)}
${#temporals.dayOfWeek(date)}
${#temporals.dayOfWeekName(date)}
${#temporals.dayOfWeekNameShort(date)}
${#temporals.hour(date)}
${#temporals.minute(date)}
${#temporals.second(date)}
${#temporals.millisecond(date)}

いくつかの例を見てみましょう。 まず、今日の曜日を表示しましょう。

<h1>Show only which day of a week</h1>
<p th:text="${#dates.day(standardDate)}"></p>
<p th:text="${#temporals.day(localDateTime)}"></p>
<p th:text="${#temporals.day(localDate)}"></p>

次に、平日の名前を表示しましょう。

<h1>Show the name of the week day</h1>
<p th:text="${#dates.dayOfWeekName(standardDate)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDateTime)}"></p>
<p th:text="${#temporals.dayOfWeekName(localDate)}"></p>

最後に、その日の現在の秒を表示しましょう。

<h1>Show the second of the day</h1>
<p th:text="${#dates.second(standardDate)}"></p>
<p th:text="${#temporals.second(localDateTime)}"></p>

LocalDate はエラーをスローするため、時間部分を処理するには、LocalDateTimeを使用する必要があることに注意してください。

4. フォームで日付ピッカーを使用する方法

日付ピッカーを使用して、Thymeleafフォームから日付値を送信する方法を見てみましょう。

まず、Date属性を持つStudentクラスを作成しましょう。

public class Student implements Serializable {
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthDate;
}

@DateTimeFormat アノテーションは、birthDateフィールドをaDateとしてフォーマットする必要があることを宣言します。

次に、Date入力を送信するためのThymeleafフォームを作成します。

<form th:action="@{/saveStudent}" method="post" th:object="${student}">
    <div>
        <label for="student-birth-date">Date of birth:</label>
        <input type="date" th:field="${student.birthDate}" id="student-birth-date"/>
    </div>
    <div>
        <button type="submit" class="button">Submit</button>
    </div>
</form>

フォームを送信すると、コントローラーは、 th:object属性を持つフォームにマップされたStudentオブジェクトをインターセプトします。 また、 th:field 属性は、入力値をbirthDateフィールドにバインドします。

それでは、POSTリクエストをインターセプトするコントローラーを作成しましょう。

@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(Model model, @ModelAttribute("student") Student student) {
    model.addAttribute("student", student);
    return "datePicker/displayDate.html";
}

フォームを送信した後、birthDateの値をdd/ MM /yyyyのパターンで別のページに表示します。

<h1>Student birth date</h1>
<p th:text="${#dates.format(student.birthDate, 'dd/MM/yyyy')}"></p>

結果は、日付ピッカー付きのフォームを示しています。

フォームを送信すると、選択した日付が表示されます。

5. 結論

このクイックチュートリアルでは、Thymeleafフレームワークバージョン3.0に実装されているJava Date処理機能について説明しました。

テスト方法は?最初にブラウザーでコードを試してから、既存のJUnitテストも確認することをお勧めします。

私たちの例は、Thymeleafで利用可能なすべてのオプションを網羅しているわけではないことに注意してください。 すべてのタイプのユーティリティについて知りたい場合は、SpringおよびThymeleaf式に関する記事をご覧ください。

このチュートリアルの完全な実装は、GitHubにあります。