テンプレートエンジン(Thymeleaf) ================================================================================ .. only:: html .. contents:: 目次 :depth: 3 :local: Overview -------------------------------------------------------------------------------- Thymeleafとは ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ \ `Thymeleaf `_\ は、Javaで実装されたテンプレートエンジンである。 Thymeleafは、その特性により主にHTML生成用のテンプレートエンジンに分類される。 Spring MVCでViewに採用可能なテンプレートエンジンには、他にもApache Velocity、Apache FreeMarker等が存在する。 また以前から利用されている類似の技術としては、Java EE標準で規定されているJSPがある。 本節では、これらの既存のテンプレートエンジンと異なるThymeleafの特性を説明し、ThymeleafをSpring MVCと連携してWebアプリケーションのView(画面)に適用する方法について説明する。 Thymeleafの特性 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 1. Thymeleafのテンプレートは、ブラウザでの静的描画が可能 既存のテンプレートエンジンと比較してThymeleafの特筆すべき点は、HTMLの文法に則ってテンプレートを書ける仕様となっている事である。 この仕様によりThymeleafではテンプレートをHTMLファイルとして作成する事が可能であり、テンプレート自体をWebブラウザで描画する事ができる。(以降、テンプレートファイルをブラウザで直接開く事を静的表示と呼ぶ。) ここで単純なテンプレートファイルをブラウザで静的表示した場合の例を示す。 * **Thymeleaf以外** のテンプレートファイル(JSP、 Apache FreeMarker等) .. code-block:: HTML

Chapter ${number}

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - |

要素にnumber変数を埋め込み、"Chapter "と連結した文字列をHTMLに出力する。実装は要素のコンテンツ部分に記述している。 テンプレートファイルをブラウザで開いた場合には、テンプレートファイルのロジックが表示されてしまう。 .. figure:: ./images/thymeleaf-other-template.png :alt: thymeleaf other template :width: 50% * **Thymeleaf** のテンプレートファイル .. code-block:: HTML

Chapter 1

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - |

要素にnumber変数を埋め込み"Chapter "と連結した文字列をHTMLに出力する。実装は属性値に記述している。 | また要素のコンテンツ部分には、固定文字列"Chapter 1"を記述している。 テンプレートファイルをブラウザで開いた場合にもテンプレートファイルのロジックは表示されず、

要素に記述したコンテンツが表示される。 .. figure:: ./images/thymeleaf-template.png :alt: thymeleaf template :width: 50% Thymeleafのテンプレートファイルを確認すると分かるが、Thymeleafでは出力内容を変更するために固有の属性を用いている。 これはブラウザで表示する際に、ブラウザが解釈出来ない属性が無視される事を前提としている。 この仕様により、静的表示の際にThymeleafのテンプレートファイルの実装をブラウザに無視させる事が出来、Thymeleafで動的に変更しないデザインの確認が可能となる。 この特性を活かして、Thymeleafを採用した開発では設計工程で作成したHTMLに対してブラウザでデザインの確認をしつつ、動的表示の為のロジックを実装していく事ができる。(以降、画面設計時に作成するHTMLをThymeleafでの呼称に合わせてプロトタイプと呼び、HTML形式のThymeleafテンプレートファイルをテンプレートHTMLと呼ぶこととする。) 2. Thymeleafの実行環境 Thymeleafでは、JSPのようにサーブレットコンテナで提供されるテンプレートエンジンを利用して動作するのではなく、アプリケーションに含まれるThymeleafのテンプレートエンジンがテンプレートHTMLの解釈を行う。 このため、アプリケーションサーバごとにテンプレートの解釈が異なり、動作しなくなるといった問題が発生しにくい。 ただし、HttpServletRequestなどのサーブレットAPIを利用しているため、アプリケーションサーバごとの挙動の違いを完全に排除することはできない点に注意されたい。 3. Thymeleafテンプレート Thymeleafでは、HTML形式でテンプレートファイルを作成できる。 ThymeleafのテンプレートHTMLに記述できるHTMLの書式は、HTML5に対応しておりHTML5より追加された属性の解釈が可能である。 また、Thymeleafの固有属性をHTML5のカスタムデータ属性として記述する事も可能である。 なお、Thymeleafが提供するテンプレートモードを変える事でJAVASCRIPTやCSS用のテンプレートも作成する事が可能である。 .. note:: **Thymeleafで選択可能なテンプレートモード** 本ガイドラインでは、ThymeleafでHTMLを生成する為のテンプレートモードである"HTML"モードについて記述するが、他にも出力するテンプレートに応じたモードが定義されている。 Thymeleafのテンプレートとして選択可能なテンプレートモードについては、 `公式リファレンス `_ を参照されたい。 Thymeleafが提供する基本的な機能 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Thymeleafのテンプレートファイルを記述する為の基本機能である、Thymeleafスタンダードダイアレクトについて説明する。 Thymeleafスタンダードダイアレクト """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Thymeleafは、テンプレートファイルを記述する為に `スタンダードダイアレクト `_ を提供している。 スタンダードダイアレクトとは、テンプレートファイルに記述して動的に出力を生成する為の各種プロセッサや、式、式オブジェクトを包含した機能群である。 スタンダードダイアレクトは複数の要素により構成されているため、構成要素とその概要について下表に示す。 なお、各要素の機能詳細についてはThymeleaf公式リファレンスを参照されたい。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.60\linewidth}|p{0.30\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 60 30 * - 構成要素 - 説明 - 例 * - | 属性プロセッサ - | Thymeleafテンプレート中の要素(タグ)に *属性* として記述するプロセッサ。 | Thymeleafテンプレートを記述する為の基本的な文法であり、開発者は属性プロセッサを介してHTML出力処理を実装する。 - | \ ``th:text``\ 、 \ ``th:if``\ 等 * - | 要素プロセッサ - | Thymeleafテンプレートに *要素(タグ)* として記述するプロセッサ。 | 汎用要素である\ ````\ のみが提供されている。\ ````\ は、属性プロセッサを記述する為のHTML文法上の土台として用意されている。\ ````\は、Webブラウザで不明なタグとして扱われる為、HTMLの文法に則った属性プロセッサの使用だけでは実現できない場合に限定的に使用されるべきである - | \ ````\ * - | `式(エクスプレッション) `_ - | 属性プロセッサの値に記述する事で、固有の処理を提供する式。 | Thymeleafが独自に解釈するトークン及び演算子も提供している。 - | 変数式 \ ``${}``\ 、 メッセージ式 \ ``#{}``\ 、 リンクURL式 \ ``@{}``\ 等 | テキストリテラル、数値リテラル、算術演算子、条件式等 * - | 式オブジェクト - | * `基本オブジェクト `_ | 1. Web コンテキスト ネームスペース : Webオブジェクトにアクセスする為の別名 | 2. Web コンテキスト ネームスペース : Webオブジェクトにアクセスする為の別名 | 3. Web オブジェクト : HttpServletRequest、 HttpSession等のServlet API | * `ユーティリティオブジェクト `_ | 4. Thymeleafが提供するユーティリティ機能群 - | | 1. \ ``#ctx``\ , \ ``#local``\ | 2. \ ``param``\ , \ ``session``\ , \ ``application``\ | 3. \ ``#request``\ , \ ``#session``\ , \ ``#servletContext``\ | | 4. \ ``#arrays``\ , \ ``#strings``\ 等 .. note:: インライン処理について テンプレートHTMLでは、多くの場合属性プロセッサに式を記述してHTML生成処理を実装する。 その一方で、 `インライン処理機能 `_ が用意されており、 属性プロセッサを介さずに要素内のコンテンツを動的に変更する事が可能である。 ただし、静的表示した場合にインライン処理の記述がブラウザに表示される為、ブラウザで静的表示が可能であるThymeleafの利点を損なう事となる。 その為、本ガイドラインでは利用を推奨しない。 .. note:: th:remove属性について テンプレートHTMLでは、多くの場合属性プロセッサに式を記述してHTML生成処理を実装する。 その為、属性プロセッサを記述する目的だけのためにデザイン上不要なHTML要素が必要となるケースがある。 またプロトタイプにおいてダミーデータを表示する為の記述についても、Thymeleafによるテンプレート解釈時に削除したいケースがある。 これらのような場合に\ ``th:remove``\属性を用いて、不要なHTML要素やコンテンツを削除する事ができる。 \ ``th:remove``\属性は、属性値に削除する範囲を設定でき動的処理時に柔軟に削除範囲を決める事が可能である。 \ ``th:remove``\属性の詳細については、 `Thymeleaf公式リファレンス `_ を参照されたい。 Thymeleaf + Spring ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Thymeleaf + Spring `_ は、Thymeleafチームが提供するSpring MVCとの連携機能である。 ブランクプロジェクトを利用した場合、Thymeleaf + Springを適用した状態で開発を進める事が出来るようになっている。 設定の詳細は :ref:`configuration-of-blank-project-label` を参照されたい。 ここでは、Thymeleaf + Springを適用した場合の処理フローやThymeleaf + Springが提供する機能について説明する。 Thymeleaf + Springを適用した処理フロー """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Thymeleaf + Springを利用し、ThymeleafとSpring MVCを連携させた場合のリクエストを受けてからレスポンスを返すまでの処理フローを以下の図に示す。 なお、 :doc:`../../Overview/SpringMVCOverview` にて解説済みのController周りの処理については省略する。 .. figure:: ./images/thymeleaf-spring.png :alt: spring thymeleaf :width: 80% .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | \ ``DispatcherServlet``\が、リクエストを受け取る。 * - | (2) - | \ ``DispatcherServlet``\は、ビュー名に対応する\ ``View``\の解決を\ ``ViewResolver``\に委譲する。 * - | (3) - | \ ``DispatcherServlet``\は、返却された\ ``View``\にレンダリング処理を委譲する。 * - | (4) - | \ ``View``\は、\ ``TemplateEngine``\にレンダリング処理を委譲する。 * - | (5) - | \ ``TemplateEngine``\は、\ ``TemplateManager``\にレンダリング処理を委譲し、処理結果のレスポンスをコミットする。 * - | (6) - | \ ``TemplateManager``\は、テンプレートがキャッシュされていない場合は\ ``TemplateResolver``\にテンプレートファイルのロード処理を委譲する。 * - | (7) - | \ ``TemplateManager``\は、パース済みのテンプレートをキャッシュする。 * - | (8) - | \ ``TemplateManager``\は、\ ``TemplateHandler``\にレンダリング処理を委譲する。 * - | (9) - | \ ``View``\は、Thymeleafのレンダリング処理結果を返却する。 Thymeleaf + Springの機能 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 1. Springスタンダードダイアレクト Thymeleaf + Springを利用する場合、`Springスタンダードダイアレクト `_ を用いてテンプレートを記述できる。 Springスタンダードダイアレクトは、Thymeleafスタンダードダイアレクトを拡張した機能群であり、 Spring MVCと連携する為の属性プロセッサの拡張と新規追加、及び新たな式オブジェクトを提供している。 追加された機能はHTMLモードに特化しており、Spring MVCのタグライブラリで実現する機能やEL関数を補完する機能を提供している。 追加された属性プロセッサの内、最も特徴的なのは\ ``th:field``\属性でinput要素のtype属性値毎に出力結果を変える。 これにより、Spring Framework JSP Form Tag Libraryが提供する\ ````\や\ ````\、 \ ````\等の機能をカバーしている。 また\ ````\の代替機能を実現する\ ``th:errors``\属性、 \ ``th:errorClass``\属性も提供されており、Spring MVCの利点を享受できるように設計されている。 機能の詳細については、`Creating a Form `_ 及び `Validation and Error Messages `_ を参照されたい。 2. その他機能 Thymeleaf + Springを適用する場合、Thymeleaf単体で利用する場合とは以下の点で異なる。 * 式言語として、OGNL(Object Graph Navigation Language)の代わりにSpEL(`Spring Expression Language `_)を利用する。 * メッセージリソースとして、SpringのMessageSourceを利用する。 * Thymeleafが提供するフォーマット機能の代わりに、SpringのConversionサービスを利用する。 `The Conversion Service `_ を参照されたい。 Thymeleafテンプレートの実装 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ テンプレートHTMLの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" これよりThymeleafのテンプレートHTMLの実装例を説明する。 ここでは、設計時に画面のデザインが決定している前提とし、作成済みのHTMLファイルにThymeleaf及びThymeleaf + Springのスタンダードダイアレクトを適用してテンプレートHTMLを作成する。 単純な検索画面と検索結果画面を例とする。以下が対象の画面である。(なお、以下の画面は作成後のテンプレートHTMLを静的表示したものである。) .. figure:: ./images/thymeleaf-screen-transition.png :alt: thymeleaf screen transition :width: 70% * 検索画面 HTML .. code-block:: HTML Search Screen

Search Screen

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | テキスト入力要素を1つ保持する、単純な
要素のみを定義している。 | action属性には、検索結果画面のHTMLファイルへの静的リンクを記述している。 テンプレートHTML .. code-block:: HTML Search Screen

Search Screen

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | xmlns宣言を追加し、プロセッサに付与する名前空間("th")を定義する。 | この定義は無くても構わないが、定義が無い場合Eclipse等のIDEによるHTML構文バリデーションで警告される為、記述する事を推奨する。 * - | (2) - | 要素に\ ``th:href``\属性を追加する。 | \ ``th:href``\属性のようにHTMLの属性に"th:"を付加した属性プロセッサは、テンプレートの解釈時に対象のHTML属性値を上書きする。 | \ ``th:href``\属性値には、リンクURL式\ ``@{}``\を用いている。リンクURL式は、指定されたパスにWebアプリケーションのコンテキストパスを付加した値を生成する。 * - | (3) - |
要素に\ ``th:action``\属性を追加する。 | \ ``th:action``\属性値には、リンクURL式\ ``@{}``\を用いている。 * - | (4) - | 要素に\ ``th:object``\属性を追加し、要素内からアクセスするプロパティを格納したオブジェクトを指定する。 | \ ``th:object``\属性値には、変数式\ ``${}``\を用いThymeleafのコンテキストに格納したオブジェクトを参照する。 | 変数式中の記述は、SpELによって処理される。 * - | (5) - | 要素に\ ``th:field``\属性を追加し、サーバサイドで保持されているデータが有る場合に出力する。 | \ ``th:field``\属性値を要素に適用すると、id属性、name属性、value属性が付加される。 | \ ``th:field``\属性値には選択変数式\ ``*{}``\を用い、\ ``th:object``\属性で指定したオブジェクトのプロパティを参照している。 | これは変数式を利用し、\ ``${searchForm.fruitsName}``\と実装した場合と同様の結果を得る。 | 選択変数式中の記述も変数式と同様にSpELによって処理される。 * 検索結果画面 HTML .. code-block:: HTML Search Result Screen

Search Result

name price
Apple 300
Apple Juice 100
Apple Pie 500
Back .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | name、 priceヘッダを持ったn行×2列のテーブルを定義する。ここでは3行分のデータを記述している。 * - | (2) - | 要素のhref属性には、検索画面のHTMLファイルへの静的リンクを記述している。 テンプレートHTML .. code-block:: HTML Search Result Screen

Search Result

name price
Apple 300
Apple Juice 100
Apple Pie 500
Back .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | xmlns宣言を追加し、プロセッサに付与する名前空間("th")を定義する。 * - | (2) - | 要素に\ ``th:href``\属性を追加する。 | \ ``th:href``\属性値には、リンクURL式\ ``@{}``\を用いている。 * - | (3) - | 要素に\ ``th:each``\属性を追加し、テーブルの要素及び配下の子要素を繰り返し出力している。 | \ ``th:each``\属性では、変数式を用い\ ``items``\リストを参照し、リスト内のオブジェクトを\ ``item``\変数に格納している。 * - | (4) - | \ ``th:text``\属性値には変数式を用い、\ ``th:each``\属性で定義した\ ``item``\変数の\ ``name``\フィールド、\ ``price``\フィールドを参照している。 | \ ``th:text``\属性は、記述した要素のコンテンツを属性値で上書きする。 * - | (5) - | Thymeleafのパーサーレベルコメントブロックを用いて、静的表示の為に記述したテーブル内の要素をThymeleafによるテンプレート解釈時に削除するようにしている。 | コメントブロックについては、後述する :ref:`comment-blocks` の「2. Thymeleafパーサーレベルコメントブロック」を参照されたい。 * - | (6) - | 要素に\ ``th:href``\属性を追加する。 | \ ``th:href``\属性値には、リンクURL式\ ``@{}``\を用いている。 .. note:: テンプレートHTMLの実装において静的表示を意識すべきかについて Thymeleafの最も大きな特徴であり魅力であるのが、テンプレートファイルが静的表示可能な事である。 この特徴は、設計時に作成したプロトタイプを元にブラウザでデザインを確認しつつ、サーバ上で動的にHTMLを生成する機能を組み込む事を可能とする。 新規に画面テンプレートを作成する際にサーバ側のプログラムを実装する必要なくデザインが確認できるのは、他のテンプレートエンジンには無い優れた点である。 また、開発途中にデザインの変更が生じた場合もHTMLテンプレートを修正すれば良いため、他テンプレートエンジンでの開発のようなプロトタイプとテンプレートの二重管理が不要となる。 一方で、当機能の副作用についても考慮しておく必要がある。 新規開発時のUI開発の効率化や管理対象資材の削減による利点は先に述べたとおりで否定のしようがないが、エンタープライズ系のシステムでは5~10年(或いはそれ以上)システムを運用する事は当然であり、 その間に機能追加による改修を複数回行う。 このようなシステムに対して、静的表示可能なテンプレートを採用した場合に考慮すべき点を挙げる。 1. ソースコードの可読性 静的表示が可能なテンプレートHTMLには、商用環境におけるHTML生成後には読み込まれないCSSや遷移する事のない画面へのリンク、削除される要素等の無駄なコンテンツが含まれる。 画面の複雑度が低い場合は気にならないが、複雑度が高くなるほど静的表示用の記述も増える為、テンプレート中に本質的には不要な実装が増えていく。 また静的表示用の記述と動的に解釈させる記述に明確な境界が無い為、実装を読み解かない限りは、いずれの為の記述なのかは判断出来ない。 これらの要因により、静的表示用の実装が無い場合と比較してソースコードの可読性が下がり、メンテナンスコストが高くなる恐れが有る。 2. メンテナンスに伴うデグレードのリスク 静的表示用の記述の修正によりテンプレートにバグを埋め込む可能性があり、逆にテンプレートの修正により静的表示を損なう可能性もあり、 両者の品質を確保し続けるには高いスキルと冗長なコストが必要とされる。 また、エンタープライズ向けのシステムでは一度リリースしたソースコードを修正するハードルが高く、 静的表示のみの修正のために十分なテストを行ないリリースするコストを避ける為、テンプレートHTMLとプロトタイプの二重管理が発生する危険性も否定できない。 これらの品質・コスト面でのリスクを許容してプロトタイプをメンテナンスし続けるかどうかは、慎重に判断する必要がある。 テンプレートファイルに静的表示用の実装を含める事については、ソースコードの可読性を損ない技術的な負債を作らないか、 プロジェクトで採用する開発プロセスと合致するか、どのように品質を保持していくのか等を勘案のうえ決定するべきである。 また、静的表示可能なテンプレートを採用する場合においては、後述する :ref:`comment-blocks` の機能を用い静的表示部と動的にHTMLを生成させるための処理を可能な限り分ける検討をすること。 .. todo:: Thymeleafには、`Decoupled Template Logic `_ という機能が存在する。 Decoupled Template Logicを適用すると、プロトタイプと動的処理を別ファイルに実装できる為、デザインとテンプレートエンジンによる処理を分離可能である。 当機能については、ガイドラインの次版以降で紹介する予定である。 .. _comment-blocks: コメント文 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Thymeleafのテンプレートでは、プロトタイプとの両立をサポートするため3種類のコメント文が記述可能である。 ここでは、各々のコメント文の特性及び利用場面を紹介する。 1. HTMLコメント 通常のHTMLコメント文は、Thymeleafで特別な処理をされず、そのまま生成したHTMLに出力される。 その為、利用者に見られても問題が無い内容以外をHTMLコメントで記述するべきではない。 * 記述例 .. code-block:: HTML .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 通常のHTMLコメント文は、生成したHTMLに出力される。 * 出力例 .. code-block:: HTML 2. Thymeleafパーサーレベルコメントブロック Thymeleafパーサーレベルコメントブロックは、Thymeleafでの処理時に削除され生成したHTMLには出力されない。 これは、コメントブロック自体もコメントブロックで囲ったコンテンツに対しても同様である。 その為、静的表示用のみに使用する。 * 記述例 .. code-block:: HTML Apple 300 Banana 300 Strawberry 300 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | Thymeleafパーサーレベルコメントブロックは、Thymeleafでの処理時に削除され生成したHTMLには出力されない。 | 本例の場合は、コメントブロックで囲われたテーブルの2~3行目は、静的表示時のみ有効でThymeleafが生成したHTMLからは削除されている。 | また\ ````\も同様に削除される。 * 出力例 .. code-block:: HTML Grape 300 Grape Juice 100 Grape Soda 100 3. Thymeleafプロトタイプのみのコメントブロック Thymeleafプロトタイプのみのコメントブロックは、コメントブロック内部の記述がThymeleafで処理される。 一方で静的表示する場合には、HTMLコメントと判断される為ブラウザには表示されない。 静的表示した場合に解釈不可能な\ ````\タグを用いた場合や、\ ``th:if``\属性を用いた分岐制御の為だけに、デザイン上不要なタグを使用する場合に有用なコメントブロックである。 * 記述例 .. code-block:: HTML Apple 300 10 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | プロトタイプのみのコメントブロックを使用して\ ````\を用いた繰り返し処理を静的表示の際には、描画されないようにしている。 | Thymeleafによる処理時には、コメントブロックが削除され\ ````\に記述した\ ``th:each``\属性が処理される。 * 出力例 .. code-block:: HTML Orange 300 5 Orange Juice 100 15 Orange Sherbet 200 20 How to use -------------------------------------------------------------------------------- アプリケーションの設定 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 本節では、ThymeleafをSpring MVCと連携して使用する為の設定の説明をする。 .. _configuration-of-blank-project-label: ブランクプロジェクトの設定 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Thymeleafを利用する為の初期設定をブランクプロジェクトで提供している。 ここでは、Spring MVCと組み合わせてThymeleafを使用する為のブランクプロジェクトの設定の説明をする。 Thymeleafに係るブランクプロジェクトの設定は、以下の4点である。 1. Thymeleaf及び推奨ライブラリの依存関係の設定 2. ThymeleafをSpring MVCのViewとして用いる為のBean定義 3. テンプレートHTMLのレイアウト化 (テンプレートHTMLのレイアウト機能については、\ :doc:`./TemplateLayout`\ を参照されたい。) 4. エラー画面のテンプレートHTMLをThymeleafで処理する為の設定及びControllerの実装 | テンプレートHTMLに直接遷移した場合、Thymeleafによるテンプレートの解釈がされない。 | その為、ブランクプロジェクトではエラー画面遷移用パスを定義し、専用のControllerで受け付けるようにしている。 * pom.xmlの定義 * プロジェクトのルートのpom.xml .. code-block:: xml org.thymeleaf thymeleaf ${thymeleaf.version} org.thymeleaf thymeleaf-spring4 ${thymeleaf.version} org.thymeleaf.extras thymeleaf-extras-springsecurity4 ${thymeleaf-extras-springsecurity4.version} 3.0.9.RELEASE 3.0.2.RELEASE .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | thymeleafのdependencyを定義する。 * - | (2) - | thymeleaf-spring4のdependencyを定義する。 * - | (3) - | thymeleaf-extras-springsecurity4のdependencyを定義する。 * - | (4) - | Thymeleaf及び推奨するライブラリのバージョンを定義する。 | 本ガイドラインで採用するThymeleafのバージョンは、採用するSpring IO platform(Brussels-SR5)で管理されているバージョンと異なる為、明示的に上書き指定している。 .. note:: Thymeleaf 3.xを採用する理由 Spring IO platform(Brussels-SR5)で管理されているThymeleafのバージョンは、2.1.4.RELEASLEであるが、本ガイドラインは、3.0.9.RELEALSEを前提に記述している。 敢えてSpring IO platformと異なるバージョンを採用する理由は、Thymeleaf 2.xから3.xへのバージョンアップの際に大幅に性能向上が図られたためである。 3.xへのバージョンアップ情報の詳細については、`Thymeleaf 3.0 announcement and more info `_ を参照されたい。 * [artifactID]-webプロジェクトのpom.xml .. code-block:: xml org.thymeleaf thymeleaf org.thymeleaf thymeleaf-spring4 org.thymeleaf.extras thymeleaf-extras-springsecurity4 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | thymeleafのdependencyを追加することで、Thymeleafが利用可能となる。 * - | (2) - | thymeleaf-spring4のdependencyを追加することで、Spring MVCとの連携機能が有効になる。 * - | (3) - | thymeleaf-extras-springsecurity4のdependencyを追加することで、Spring Securityとの連携機能が有効になる。 * spring-mvc.xmlの定義 .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | \ ``ThymeleafViewResolver``\をBean定義する。 | Spring MVCのViewにThymeleafを採用する場合には、\ ``ThymeleafViewResolver``\を用いる。 | \ ````\内に記述し、\ ``BeanNameViewResolver``\の次に処理をする設定としている。 * - | (2) - | レスポンスのエンコーディングを設定する。UTF-8を設定している。 * - | (3) - | \ ``forcedContentType``\プロパティに\ ``true``\を指定し、レスポンスのContent-Typeヘッダを明示的に設定するようにしている。 | \ ``contentType``\プロパティに\ ``text/html;charset=UTF-8``\を指定している。 * - | (4) - | \ ``SpringResourceTemplateResolver``\をBean定義する。 | \ ``SpringResourceTemplateResolver``\は、SpringのResourceLoader経由で、Thymeleafのテンプレートファイルを検出する。 * - | (5) - | Thymeleafテンプレートが格納されているベースディレクトリ(ファイルパスのプレフィックス)を指定する。 * - | (6) - | Thymeleafテンプレートの拡張子(ファイルパスのサフィックス)を設定する。HTMLファイルをテンプレートとする為、\ ``.html``\を設定している。 * - | (7) - | 解釈するテンプレートモードを設定する。デフォルト値は"HTML"モードであるが、明示的に設定している。 * - | (8) - | テンプレートファイルのエンコーディングを設定する。\ ``UTF-8``\を設定している * - | (9) - | \ ``SpringTemplateEngine``\をBean定義する。 | \ ``SpringTemplateEngine``\により、Thymeleaf + Springが提供する各種機能を利用可能となる。 * - | (10) - | SpEL(Spring Expression Language)のコンパイル実施可否を設定する。 | SpELのコンパイルを実施する事で性能向上が見込める為、\ ``true``\を設定している。 * - | (11) - | \ ``additionalDialects``\に、\ ``SpringSecurityDialect``\を定義することで、テンプレートHTML内で、Spring Securityの認証・認可制御が可能となる。 .. note:: レスポンスのContent-Typeの解決方法について \ ``ThymeleafViewResolver``\のデフォルトの動作では、リクエストのAcceptヘッダの値やURLを元にレスポンスのContent-Typeヘッダの値を決めている。 例えば、URLの末尾に\ ``.json``\のような拡張子を指定したリクエストの場合、レスポンスのContent-Typeに\ ``application/json``\が設定される。 レスポンスでHTMLのみを返却する場合は、Content-Typeが自動判定されることで思わぬ不具合が生じる可能性がある。 本ガイドラインでは、Thymeleafを介した場合のレスポンスがHTMLのみである想定の為、ブランクプロジェクトにてContent-Typeを"text/html;charset=UTF-8"に明示的に指定している。 Content-Typeの指定は、\ ``ThymeleafViewResolver``\のBean定義で\ ``forcedContentType``\プロパティをtrueとし、\ ``contentType``\プロパティに任意のContent-Typeを設定する事で可能である。 * spring-security.xmlの定義 .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | spring-security.xmlの\ ``AccessDeniedHandler``\の\ ``errorPage``\のパスを指定する。 | エラー画面をThymeleafに処理させるため、直接HTMLファイルのパスを指定せず、後述するエラー画面に遷移させるためのControllerでハンドリングされるようにしている。 * web.xmlの定義 .. code-block:: xml 500 /common/error/systemError 404 /common/error/resourceNotFoundError java.lang.Exception /WEB-INF/views/common/error/unhandledSystemError.html .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | 遷移するパスを指定する。エラー画面をThymeleafに処理させるため、直接HTMLファイルのパスを指定せず、後述するエラー画面に遷移させるためのControllerでハンドリングされるようにしている。 * - | (2) - | unhandledSystemError.htmlは、Thymeleafのテンプレートではない為、直接HTMLファイルのパスを指定している。 * エラーページ遷移用Controllerクラス .. code-block:: java @Controller @RequestMapping("common/error") // (1) public class CommonErrorController { @RequestMapping("accessDeniedError") // (1) public String accessDeniedError() { return "common/error/accessDeniedError"; // (2) } @RequestMapping("businessError") public String businessError() { return "common/error/businessError"; } @RequestMapping("dataAccessError") public String dataAccessError() { return "common/error/dataAccessError"; } @RequestMapping("/invalidCsrfTokenError") public String invalidCsrfTokenError() { return "common/error/invalidCsrfTokenError"; } // omitted } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | クラスレベルの\ ``@RequestMapping``\アノテーションにエラー画面の共通パスを指定し、メソッドレベルの\ ``@RequestMapping``\アノテーションに各種例外に応じたエラー画面遷移用パスを指定する。 * - | (2) - | ハンドラメソッドからは、Thymeleafのテンプレートを指定する文字列を返却する。 Viewの実装 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ThymeleafのテンプレートHTMLの実装については、\ :doc:`../../ImplementationAtEachLayer/ApplicationLayer`\ の\ :ref:`view`\を参照されたい。 How to extend -------------------------------------------------------------------------------- カスタムダイアレクトの追加 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Thymeleafでは開発者がカスタムダイアレクトを追加することで、独自に開発したタグや属性、式オブジェクトを使用することができる。 カスタムダイアレクトを追加するにはProcessorやExpressionObjectとDialectを実装する必要がある。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - - 説明 * - | Processor - | テンプレート内のイベントに対して実行する処理を定義するオブジェクト。 | タグを定義する要素プロセッサとタグの属性を定義する属性プロセッサなどの種類がある。 * - | ExpressionObject - | テンプレート内の式から呼び出されるオブジェクト。 | テンプレート内で用いるためのメソッドなどを定義する。特に制約がなく、POJOで定義できる。 * - | Dialect - | ProcessorやExpressionObjectをまとめたライブラリ。 | テンプレートエンジンにDialectを登録することで、ProcessorやExpressionObjectで定義された文法をテンプレート内で用いることができるようになる。 Processorの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Processorはテンプレート内のイベントに対して実行する処理を定義するオブジェクトである。 Processorを実装するためには、Thymeleafから提供されているインタフェースを実装すればよい。 Thymeleafから提供されている代表的なProcessorのインタフェースを以下に示す。 .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 :class: longtable * - processor - 説明 * - | \ ``org.thymeleaf.processor.element.IElementTagProcessor``\ - | 開始タグに対して実行される処理を定義するためのインタフェース。対象のタグの内容は参照可能だが、直接変更することはできない。structureHandlerを介してのみ対象のタグの属性やボディを変更することができる。 | 通常は、\ ``IElementTagProcessor``\ を直接実装するのではなく、\ ``org.thymeleaf.processor.AbstractAttributeTagProcessor``\ などの\ ``IElementTagProcessor``\ を実装した抽象クラスを継承する。 * - | \ ``org.thymeleaf.processor.element.IElementModelProcessor``\ - | 開始タグから閉じタグまでの要素全体に対して実行される処理を定義するためのインタフェース。対象の要素全体をモデルとして処理するため、任意の要素を参照、直接変更することができる。また、閉じタグの後など、任意の箇所に要素を追加することもできる。 | 通常は、\ ``IElementModelProcessor``\ を直接実装するのではなく、\ ``org.thymeleaf.processor.AbstractAttributeModelProcessor``\ などの\ ``IElementModelProcessor``\ を実装した抽象クラスを継承する。 .. note:: 上記のインタフェース以外にもイベントごとに対応するインタフェースが提供されている。詳しくは\ `Tutorial: Extending Thymeleaf(Processors) `_\ を参照されたい。 Processorでの処理に用いる代表的なインタフェースを以下に示す。 .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 :class: longtable * - インタフェース - 説明 * - | \ ``org.thymeleaf.model.IModel``\ - | HTMLタグなどを抽象化したインタフェース。開始タグ、ボディ、終了タグなどのHTMLを構成する要素をリストのように保持する。 * - | \ ``org.thymeleaf.model.IModelFactory``\ - | \ ``IModel``\ の生成や組み立てをするインタフェース。 * - | \ ``org.thymeleaf.context.ITemplateContext``\ - | コンテキストの情報を保持するインタフェース。\ ``IModelFactory``\ などを取得することができる。 * - | \ ``org.thymeleaf.model.IProcessableElementTag``\ - | 属性を適用したタグ自体の情報を保持するインタフェース。タグの名前や付与された属性を取得することができる。 * - | \ ``org.thymeleaf.processor.element.IElementTagStructureHandler``\ - | 属性を適用したタグや、そのボディ部を編集するためのインタフェース。 ラベル、入力フィールド、エラーメッセージをまとめて出力する独自属性の実装例を以下に示す。 .. note:: 独自タグと独自属性どちらでも同じ機能を実装できる場合があるが、独自属性での実装を推奨する。 理由は、静的表示する際、独自タグは\ ````\ と同様に解釈不能となってしまうが、独自属性はその属性のみが無視され、正しく表示できるためである。 **テンプレート記述例** .. code-block:: html
**独自属性の処理結果** .. code-block:: html
.. note:: 上記の処理結果は実装する独自属性のみをテンプレートエンジンで評価した結果である。 実際に出力されるHTMLは\ ``th:field``\ 属性などもテンプレートエンジンで評価した形となるため上記の処理結果とは異なる。 実際のHTML出力については :ref:`custom_dialect_how_to_use` を参照されたい。 **実装例** .. code-block:: java // (1) public class FormInputAttributeTagProcessor extends AbstractAttributeTagProcessor { public FormInputAttributeTagProcessor(final String dialectPrefix) { super(TemplateMode.HTML, // (2) dialectPrefix, // (3) null, false, // (4) "form-input", true, // (5) 1000, // (6) true // (7) ); } @Override protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue, //(8) IElementTagStructureHandler structureHandler) { // (9) String classValue = tag.getAttributeValue("class"); // (10) if (StringUtils.isEmpty(classValue)) { structureHandler.setAttribute("class", "form-input"); } else { structureHandler.setAttribute("class", classValue + " form-input"); } // (11) IModelFactory modelFactory = context.getModelFactory(); IModel model = modelFactory.createModel(); // (12) model.add(modelFactory.createOpenElementTag("label", "for", "userName")); model.add(modelFactory.createText(createLabel(attributeValue))); model.add(modelFactory.createCloseElementTag("label")); model.add(modelFactory.createStandaloneElementTag("input", "th:field", attributeValue)); model.add(modelFactory.createOpenElementTag("span", "th:errors", attributeValue)); model.add(modelFactory.createCloseElementTag("span")); // (13) structureHandler.setBody(model, true); } private String createLabel(String attributeValue){ // omitted } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | \ ``AbstractAttributeTagProcessor``\(\ ``IElementTagProcessor``\ を実装した抽象クラス)を継承する。 * - | (2) - | HTMLテンプレートに適用する場合は、\ ``TemplateMode.HTML``\ を指定する。 * - | (3) - | 属性の名前に適用するプレフィックスを指定する。通常は、Dialectから引数で受け取った値を指定する。 * - | (4) - | 独自タグを作成する場合、タグ名を設定する。この例では独自属性を作成するので\ ``null``\ を設定している。booleanはタグ名にプレフィックスを適用するかを指定する。 * - | (5) - | 独自属性を作成する場合、属性名を設定する。booleanは属性名にプレフィックスを適用するかを指定する。 * - | (6) - | Dialect内におけるProcessorの優先順位を指定する。値が低いほど優先度が高くなる。 * - | (7) - | Processor適用後に適用対象の属性の記述を削除するか指定する。基本的に適用対象の属性は出力するHTMLには不要となるので\ ``true``\ を指定する。 * - | (8) - | 適用対象の属性が持つ値が渡される。渡される値は式の処理をしていない状態で、上記のテンプレート記述例の場合は\ ``*{userName}``\ が渡される。 * - | (9) - | 適用対象の属性を持つタグから\ ``class``\ 属性の値を取得する。\ ``class``\ 属性が存在しない場合は\ ``null``\ になる。 * - | (10) - | 適用対象の属性を持つタグの\ ``class``\ 属性の値に\ ``form-input``\ を追加する。 * - | (11) - | \ ``IModelFactory``\ を取得し、\ ``IModel``\ を生成する。 * - | (12) - | \ ``IModel``\ にラベル、入力フィールド、エラーメッセージを出力させるための要素を追加する。 * - | (13) - | 渡した\ ``IModel``\適用対象の属性を持つタグのボディを置き換える。booleanは置き換えたボディをテンプレートエンジンで再評価するかを指定する。 | 上記の例では\ ``th:field``\ 属性と\ ``th:errors``\ 属性を再評価する必要があるため\ ``true``\ を指定している。 .. note:: \ ``AbstractAttributeTagProcessor``\を継承した抽象クラスがいくつか提供されており、より簡単にProcessorを実装することができる場合がある。詳しくは\ `AbstractAttributeTagProcessor `_\ を参照されたい。 ExpressionObjectの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ExpressionObjectはテンプレート内の式から呼び出すメソッドなどを定義するオブジェクトである。 ExpressionObjectはインタフェース等を実装する必要がなく、POJOで定義できる。 日付(\ ``java.util.Date``\ )をyyyy/MM/dd形式でフォーマットして出力するメソッドを持つ式オブジェクトの実装例を以下に示す。 .. note:: 日付を引数で渡した形式でフォーマットして出力する機能はthymeleafから提供されている。 **実装例** .. code-block:: java // (1) public class CustomDateFormat { // (2) public String formatYYYYMMDD(Date date) { DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); return dateFormat.format(date); } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | POJOとして作成する。 * - | (2) - | 引数に指定された日付をyyyy/MM/dd形式でフォーマットした文字列を返す。 Dialectの実装 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ProcessorやExpressionObjectで実装した処理をテンプレートに適用するためにはDialectを実装してテンプレートエンジンに追加する必要がある。 Dialectを実装するためにThymeleafから提供されている代表的なインタフェースを以下に示す。 .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 :class: longtable * - インタフェース名 - 説明 * - | \ ``org.thymeleaf.dialect.IProcessorDialect``\ - | Processorを登録するDialectを実装するためのインタフェース | 通常は、\ ``IProcessorDialect``\ を直接実装するのではなく、\ ``IProcessorDialect``\ を実装した抽象クラス\ ``org.thymeleaf.dialect.AbstractProcessorDialect``\ を継承する。 * - | \ ``org.thymeleaf.dialect.IExpressionObjectDialect``\ - | ExpressionObjectを登録するDialectを実装するためのインタフェース .. note:: 上記のインタフェース以外にも登録内容ごとに対応するインタフェースが提供されている。詳しくは\ `Tutorial: Extending Thymeleaf(Dialects) `_\ を参照されたい。 ProcessorとExpressionObjectを登録するDialectの実装例を以下に示す。 **実装例(Processorの登録)** .. code-block:: java // (1) public class InputFormDialect extends AbstractProcessorDialect { // (2) public InputFormDialect() { super("Input Form Dialect", "input", 1000); } @Override public Set getProcessors(String dialectPrefix) { final Set processors = new HashSet(); // (3) processors.add(new FormInputAttributeTagProcessor(dialectPrefix)); // (4) processors.add( new StandardXmlNsTagProcessor(TemplateMode.HTML, dialectPrefix)); return processors; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | Processorを登録する場合は、\ ``AbstractProcessorDialect``\ (\ ``IProcessorDialect``\ を実装した抽象クラス)を継承する。 * - | (2) - | 引数はDialect名、登録するProcessorのプレフィックス、Dialectの優先順位である。 | Processorの適用順序はDialectの優先順位、Processorの優先順位の順番で比較して決められる。 * - | (3) - | 実装したProcessorを登録する。 * - | (4) - | HTMLの最初につける\ ``xmlns:th="http://www.thymeleaf.org"``\ のようなネームスペース表記を削除するために\ ``org.thymeleaf.standard.processor.StandardXmlNsTagProcessor``\ を登録する。 **実装例(ExpressionObjectの登録)** .. code-block:: java // (1) public class CustomFormatDialect implements IExpressionObjectDialect { private Set names = new HashSet() { { add("customdateformat"); } }; @Override public IExpressionObjectFactory getExpressionObjectFactory() { return new IExpressionObjectFactory() { // (2) @Override public Set getAllExpressionObjectNames() { return names; } // (3) @Override public Object buildObject(IExpressionContext context, String expressionObjectName) { if ("customdateformat".equals(expressionObjectName)) { return new CustomDateFormat(); } return null; } // (4) @Override public boolean isCacheable(String expressionObjectName) { return true; } }; } @Override public String getName() { return "Date Format(yyyy/MM/dd) Dialect"; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | ExpressionObjectを登録する場合は、\ ``IExpressionObjectDialect``\を実装する。 * - | (2) - | ExpressionObjectの名前を登録する。 * - | (3) - | 実装したExpressionObjectを登録する。引数の\ ``expressionObjectName``\に入る値が(2)で登録した名前に存在する場合、このメソッドが呼ばれる。 * - | (4) - | ExpressionObjectをキャッシュするか指定する。ExpressionObjectが状態によって異なる値を返す場合は\ ``false``\ 、状態にかかわらず返す値が一定である場合は\ ``true``\ を指定する。 .. note:: 上記の例ではProcessorとExpressionObjectを別のDialectで登録する例を示しているが、意味的にまとめられる機能であれば一つのDialectで登録することも可能である。 .. _custom_dialect_how_to_use: カスタムダイアレクトの使用方法 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 作成したカスタムダイアレクトを使用するために必要なアプリケーション設定と出力画面の実装を以下に示す。 **spring-mvc.xml** .. code-block:: xml .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | テンプレートエンジンに作成したカスタムダイアレクトを\ ``java.util.Set``\ で追加する。 **view.html** .. code-block:: html
yyyy/MM/dd .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | 作成したDialectの名前空間を定義する。 * - | (2) - | 作成した\ ``input:form-input``\ 属性を指定する。 * - | (3) - | 作成した式オブジェクト\ ``customdateformat``\ を呼び出す。 **出力結果** .. code-block:: html
2017/10/30 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 :class: longtable * - 項番 - 説明 * - | (1) - | 見やすくするために改行とインデントを入れてあるが、実際には開始タグから閉じタグまで1行で出力される。 Appendix -------------------------------------------------------------------------------- テンプレートキャッシュの適用 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ テンプレートキャッシュの機能および設定方法について説明する。 テンプレートキャッシュ機能の説明 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" テンプレートキャッシュとは、パースしたテンプレート(HTML)をキャッシュする機能である。 テンプレートが呼び出される度にパースを行わないため、処理時間を削減することができる。 Controllerから渡されたView名をキーとしてキャッシュの判定が行われる。キャッシュにヒットした場合は、キャッシュからパースされたテンプレートが読み込まれる。 キャッシュにヒットしない場合は、テンプレートをパースしてキャッシュに追加する。 .. note:: \ ``org.thymeleaf.spring4.view.ThymeleafViewResolver``\にはViewオブジェクトをキャッシュする機能が備わっているが、本機能と直接関係はないので、ここでの説明は省略する。 アプリケーションの設定 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" キャッシュの有効化、対象および期間の設定は、\ ``org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver``\で実施する。 主要な設定項目の一覧を以下に示す。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.30\linewidth}|p{0.40\linewidth}|p{0.20\linewidth}| .. list-table:: :widths: 10 30 40 20 :header-rows: 1 :class: longtable * - 項番 - 設定項目 - 内容 - デフォルト値 * - | (1) - | \ ``cacheable``\ - | 全テンプレートに対するキャッシュの有効化を\ ``true``\か\ ``false``\で指定する。 - | \ ``true``\ * - | (2) - | \ ``cacheTTLMs``\ - | キャッシュの生存時間をミリ秒単位で指定する。 - | \ ``null``\ (時間経過でのキャッシュ削除を行わない) * - | (3) - | \ ``cacheablePatterns``\ - | キャッシュ対象のテンプレートをView名で指定する。\ ``cacheable``\に\ ``false``\を指定した場合に用いる。"\ ``*``\"などのワイルドカードを使用することができる。 - | - * - | (4) - | \ ``nonCacheablePatterns``\ - | キャッシュ対象から除外するテンプレートをView名で指定する。\ ``cacheable``\に\ ``true``\を指定した場合に用いる。"\ ``*``\"などのワイルドカードを使用することができる。 - | - .. note:: 頻繁にアクセスするテンプレートをキャッシュ対象とし、アクセス頻度が低いテンプレートはキャッシュ対象から除外することで、メモリ負荷を抑えて効率的にキャッシュ機能を働かせることを推奨する。 以下に特定のテンプレートのみキャッシュ対象から除外する場合の設定例を示す。 - spring-mvc.xml .. code-block:: xml welcome/home sample/* さらにキャッシュサイズ等の詳細な設定については、\ ``org.thymeleaf.cache.StandardCacheManager``\で実施する。 主要な設定項目の一覧を以下に示す。 .. tabularcolumns:: |p{0.10\linewidth}|p{0.30\linewidth}|p{0.40\linewidth}|p{0.20\linewidth}| .. list-table:: :widths: 10 30 40 20 :header-rows: 1 :class: longtable * - 項番 - 設定項目 - 内容 - デフォルト値 * - | (1) - | \ ``templateCacheInitialSize``\ - | キャッシュの初期サイズをテンプレート数単位で指定する。 - | \ ``20``\ * - | (2) - | \ ``templateCacheMaxSize``\ - | キャッシュの最大サイズをテンプレート数単位で指定する。\ ``-1``\を指定した場合は制限なしになる。"\ ``0``\"を指定した場合はキャッシュが無効になる。 - | \ ``200``\ * - | (3) - | \ ``templateCacheLoggerName``\ - | ログを出力するロガー名を指定する。 - | \ ``org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE``\ * - | (4) - | \ ``templateCacheName``\ - | ログに出力するキャッシュ名を指定する。 - | \ ``TEMPLATE_CACHE``\ 以下にキャッシュの初期サイズ、最大サイズをデフォルト値から変更する場合の設定例を示す。 - spring-mvc.xml .. code-block:: xml \ ``StandardCacheManager``\を利用する場合、キャッシュの初期サイズに指定した値を初期容量としてキャッシュの初期化が行われる。 キャッシュされたテンプレート数がキャッシュ容量の9割を超えるごとにキャッシュ容量が自動で段階的に拡張されるため、一時的に性能が劣化する場合がある。 そのため、全テンプレートに満遍なくアクセスがあるような場合、全テンプレートをキャッシュできる十分なサイズになるように初期サイズを指定することを推奨する。 また、少数のテンプレートのみにアクセスが集中するような場合には、アクセス集中が考えられるテンプレート数の初期サイズを指定することを推奨する。 どちらの場合においても\ ``SpringResourceTemplateResolver``\で生存時間を適切に指定することで、レスポンス性能の向上を期待できる。 キャッシュの最大サイズについても、テンプレート数単位で指定するため、1テンプレートの容量が大きいアプリではメモリ負荷が大きくなる場合がある。 テンプレートキャッシュに割り当てることができるメモリ容量に応じて、適切な値で指定する必要がある。 .. note:: キャッシュされたテンプレート数がキャッシュの最大サイズを超過する場合は、キャッシュ上でテンプレートの入れ替えが行われる。 \ `15.1 Template Resolver `_\ には、 「キャッシュの生存時間を指定しない場合にはLRU(Least Recently Used)方式でのみキャッシュの削除が行われる」と記述されているが、実際にはFIFO(First-In First-Out)方式で実装されている。 .. note:: **ログを出力する** Thymeleafの\ ``StandardCacheManager``\はデフォルトで\ ``org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE``\というロガー名でトレースログを出力する。 このトレースログには、テンプレートがキャッシュに追加、および削除されたこと、また一定時間ごとにキャッシュのヒット回数やヒット率などをまとめたキャッシュレポートが出力される。 キャッシュサイズの計算などに参考にされたい。 以下にログの出力例を示す。 - キャッシュに追加される場合 .. code-block:: text date:2017-10-30 11:07:11 thread:http-nio-8080-exec-2 X-Track:f5e0a41eecf844259d94d7dcd9f292f5 level:TRACE logger:o.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE message:[THYMELEAF][CACHE_INITIALIZE] Initializing cache TEMPLATE_CACHE. Max size: 200. Soft references are used. date:2017-10-30 11:07:11 thread:http-nio-8080-exec-2 X-Track:f5e0a41eecf844259d94d7dcd9f292f5 level:TRACE logger:o.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE message:[THYMELEAF][http-nio-8080-exec-2][TEMPLATE_CACHE][CACHE_MISS] Cache miss in cache "TEMPLATE_CACHE" for key "welcome/home". date:2017-10-30 11:07:12 thread:http-nio-8080-exec-2 X-Track:f5e0a41eecf844259d94d7dcd9f292f5 level:TRACE logger:o.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE message:[THYMELEAF][http-nio-8080-exec-2][TEMPLATE_CACHE][CACHE_ADD][1] Adding cache entry in cache "TEMPLATE_CACHE" for key "welcome/home". - キャッシュにヒットした場合 .. code-block:: text date:2017-10-30 11:07:15 thread:http-nio-8080-exec-5 X-Track:aa6b912177ed483e87270f38d479b9a9 level:TRACE logger:o.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE message:[THYMELEAF][http-nio-8080-exec-5][TEMPLATE_CACHE][CACHE_HIT] Cache hit in cache "TEMPLATE_CACHE" for key "welcome/home". - キャッシュレポート .. code-block:: text date:2017-10-30 11:13:15 thread:http-nio-8080-exec-3 X-Track:7377e5e09aff4d35ab391efe6f6b9958 level:TRACE logger:o.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE message:[THYMELEAF][*][*][*][CACHE_REPORT] 4 elements | 4 puts | 21 gets | 13 hits | 8 misses | 0.62 hit ratio | 0.38 miss ratio - [TEMPLATE_CACHE] logback.xmlで以下のように設定することで、トレースログを出力することができる。 \ ``org.thymeleaf.TemplateEngine.cache``\以下のロガーを出力するように設定することで、\ ``org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE``\などのトレースログも出力することができる。 詳細については、「:doc:`../GeneralFuncDetail/Logging`」を参照されたい。 - logback.xml .. code-block:: xml