4標準式の構文
仮想食料品店の開発を少し休憩して、Thymeleaf標準方言の最も重要な部分の1つであるThymeleaf Expression Syntax Standardについて学習します。
この構文で表現される有効な属性値には、メッセージと変数の2種類があります。
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
<p>Today is: <span th:text="${today}">13 february 2011</span></p>
しかし、もっと多くの表現があります。 最初に、標準表現を簡単に見てみましょう。
- 単純な式:
- 変数 :$ {...}
- 選択された変数 :* {...}
- メッセージ :#{...}
- リンクURL :@ {...}
- スニペット :〜{...}
- リテラル:
- テキスト :「1つのテキスト」、「もう1つのテキスト!」、...
- 番号 :0、34、3.0、12.3、...
- ブール値 :true、false
- ヌル :ヌル
- トークン :one、sometext、main、...
- テキスト:
- 行結合 :+
- サブストリング :|名前は$ {name} |
- 算術演算:
- バイナリ :+、-、*、/、%
- マイナス(単項演算子) :-
- ブール値:
- バイナリ :および
- ブール否定(単項演算子) :!、Not
- 比較と平等:
- 比較 :>、<、> =、<=(gt、lt、ge、le)
- 平等 :== ,! =(Eq、ne)
- 条件付き:
- If-then :(if)? (そして)
- If-then-else :(if)? (その後):(その他)
- デフォルト :(値)?:( デフォルト値)
- 特別なトークン:
- 無操作 :_
式は結合およびネストできます 。
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
4.1メッセージ
ご存じのように、メッセージ式#{...}を使用してバインドできます。
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
...と:
home.welcome=¡Bienvenido a nuestra tienda de comestibles!
しかし、まだ考えていない側面が1つあります。メッセージテキストが完全に静的でない場合はどうなりますか? たとえば、アプリケーションがサイトを訪問しているユーザーを認識しており、名前でユーザーに挨拶したい場合はどうなりますか?
<p>¡Bienvenido a nuestra tienda de comestibles, John Apricot!</p>
これは、メッセージにパラメーターを追加する必要があることを意味します。 このように:
home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!
このパラメーターは、標準構文java.text.MessageFormatに関連して定義されます。つまり、数値と日付をフォーマットできます。
ユーザーが呼び出すHTTPセッション属性からパラメーターの値を指定するには、次のように記述します。
<p th:utext="#{home.welcome(${session.user.name})}"> Welcome to our grocery store, Sebastian Pepper! </p>
複数のパラメーターは、コンマで区切って定義できます。 また、メッセージキー自体は変数から取得できます。
<p th:utext="#{${welcomeMsgKey}(${session.user.name})}"> Welcome to our grocery store, Sebastian Pepper! </p>
4.2変数
$ {...}式は、実際にはコンテキストに含まれるマップ変数で実行されるOGNL(オブジェクトグラフナビゲーション言語)式であると既に述べました。
OGNLの構文と機能の詳細については、OGNL言語ガイドをお読みください。
Spring MVC対応アプリケーションでは、OGNLはSpringELに置き換えられますが、その構文はOGNL構文に非常に似ています(実際、ほとんどの一般的なケースでまったく同じです)。
OGNL構文から、次の式がわかっています。
<p>Today is: <span th:text="${today}">13 february 2011</span>.</p>
と同等:
ctx.getVariable("today");
しかし、OGNLでは、次のようなより強力な式を作成できます。
<p th:utext="#{home.welcome(${session.user.name})}"> Welcome to our grocery store, Sebastian Pepper! </p>
...ユーザー名を取得します。
((User) ctx.getVariable("session").get("user")).getName();
しかし、getterはOGNLの機能の1つにすぎません。 もっと見てみましょう:
/* * (.). getter . */ ${person.father.name} /* * ([]) * . */ ${person['father']['name']} /* * map, * get(...). */ ${countriesByCode.ES} ${personsByName['Stephen Zucchini'].age} /* * , * . */ ${personsArray[0].name} /* * . */ ${person.createCompleteName()} ${person.createCompleteNameWithSeparator('-')}
式の基本オブジェクト
コンテキスト変数を使用してOGNL式を実行すると、柔軟性を高めるために一部のオブジェクトが使用可能になります。 これらのオブジェクトは、 #文字で始まる(OGNL標準に従って)参照できます。
#ctx :コンテキスト。
#vars :コンテキスト変数。
#locale :コンテキストロケール。
#request :(Webコンテキストのみ)HttpServletRequestオブジェクト。
#response :(Webコンテキストのみ)HttpServletResponseオブジェクト。
#session :(Webコンテキストのみ)HttpSessionオブジェクト。
#servletContext :(Webコンテキストのみ)ServletContextオブジェクト。
次のこともできます。
<span th:text="${#locale.country}">US</span>
これらのオブジェクトへの完全なリファレンスは、 付録Aで読むことができます。
式ユーティリティ
これらの基本オブジェクトに加えて、Thymeleafは、式で一般的なタスクを実行するのに役立つ一連の便利なオブジェクトを提供します。
#execInfo :現在のテンプレートに関する情報。
#messages :式#{...}を使用して受信するのと同じように、式内でメッセージを受信するためのメソッド。
#uris :URL / URIの一部をエスケープするためのメソッド。
#conversions :変換サービスの設定方法(存在する場合)。
#dates :java.util.Dateオブジェクトのメソッド:フォーマット、コンポーネントの抽出など。
#calendars : #datesに似ていますが、java.util.Calendarオブジェクト用です。
#numbers :数値オブジェクトをフォーマットするためのメソッド。
#strings :Stringオブジェクトのメソッド:contains、startsWith、prepending / appendingなど。
#objects :オブジェクトの一般的なメソッド。
#bools :ブール変換用のメソッド。
#arrays :配列のメソッド。
#lists :Listのメソッド。
#sets :セットのメソッド。
#maps :マップのメソッド。
#aggregates :マスまたはコレクションを集約するためのメソッド。
#ids :(たとえば、反復の結果として)繰り返すことができるID識別子を処理するためのメソッド。
これらの各オブジェクトに提供されている機能は、 付録Bで確認できます。
ホームページの日付の再フォーマット
これで、これらのオブジェクトのユーティリティについて理解し、それらを使用して、ホームページでの日付の表示方法を変更できます。 代わりに、HomeControllerで:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); Calendar cal = Calendar.getInstance(); WebContext ctx = new WebContext(request, servletContext, request.getLocale()); ctx.setVariable("today", dateFormat.format(cal.getTime())); templateEngine.process("home", ctx, response.getWriter());
...次のことができます。
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale()); ctx.setVariable("today", Calendar.getInstance()); templateEngine.process("home", ctx, response.getWriter());
...次に、ビューレイヤー自体で日付をフォーマットします。
<p> Today is: <span th:text="${#calendars.format(today,'dd MMMM yyyy')}">13 May 2011</span> </p>
4.3選択式/選択(アスタリスク構文)
変数を含む式は、 $ {...}だけでなく、 * {...}としても記述できます。
オプションには違いがあります。アスタリスク付きの構文は、コンテキスト全体ではなく、選択したオブジェクトに対して式を変換します。 これは、選択されたオブジェクトがない場合、ドルとアスタリスクが同じことを行うことを意味します。
選択したアイテムとは何ですか? 「 th:object 」属性を使用した式の結果。 プロファイルページ(userprofile.html)で使用します。
<div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
どちらが同等ですか:
<div> <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p> </div>
もちろん、ドルとアスタリスクは混在できます:
<div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
選択したオブジェクトが所定の位置にある場合、選択したオブジェクトは、 #object変数と同じようにドルでアクセスできます。
<div th:object="${session.user}"> <p>Name: <span th:text="${#object.firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
前述のように、選択されたオブジェクトがない場合、ドルとアスタリスクは同等です。
<div> <p>Name: <span th:text="*{session.user.name}">Sebastian</span>.</p> <p>Surname: <span th:text="*{session.user.surname}">Pepper</span>.</p> <p>Nationality: <span th:text="*{session.user.nationality}">Saturn</span>.</p> </div>
4.4リンクURL
その重要性のため、URLはWebアプリケーションテンプレートの第一級市民であり、Thymeleaf Standardの方言には特別な「@」構文があります: @ {...}
さまざまな種類のURLがあります。
- 絶対URL: www.thymeleaf.org
- 相対URL:
- ページ上の相対:user / login.html
- 相対コンテキスト:/ itemdetails?Id = 3(サーバーにコンテキスト名が追加されます)
- 相対サーバー:〜/ billing / processInvoice(同じサーバー上の異なるコンテキスト(=アプリケーション)でURLの呼び出しを許可します。
- 相対プロトコル://code.jquery.com/jquery-2.0.3.min.js
これらの式の実際の処理および表示されるURLへの変換は、使用されるITemplateEngineオブジェクトに登録されているorg.thymeleaf.linkbuilder.ILinkBuilderインターフェースの実装を使用して実行されます。
デフォルトでは、このインターフェースの実装の1つはorg.thymeleaf.linkbuilder.StandardLinkBuilderクラスによって表されます。これは、サーブレットAPIに基づくスタンドアロン(非Webサイト)およびWebベースのスクリプトの両方に十分です。 他のシナリオ(たとえば、非ServletAPI Webフレームワークとの統合)では、リンクビルダーインターフェイスの特定の実装が必要になる場合があります。
新しい構文を使用しましょう。 属性「 th:href 」を満たします:
<!-- 'http://localhost:8080/gtvg/order/details?orderId=3' ( ) --> <a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a> <!-- '/gtvg/order/details?orderId=3' ( ) --> <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a> <!-- '/gtvg/order/3/details' ( ) --> <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
いくつかのメモ:
- 「 th:href 」は変更属性です。実行されると、URLリンクを計算し、<a>タグの「href」属性の値を設定します。
- orderId = $ {o.id}でわかるように、URLパラメーターに式を使用できます。URLパラメーターのエンコードに必要な操作も自動的に実行されます。
- 複数のパラメーターが必要な場合、コンマで区切られます:@ {/ order / process(execId = $ {execId}、execType = 'FAST')}
- URLでも変数テンプレートを使用できます:@ {/ order / {orderId} / details(orderId = $ {orderId})}
- /で始まる相対URL(例:/ order / details)には、アプリケーションコンテキストの名前が自動的に付加されます。
- Cookieが有効になっていないか、まだ知られていない場合は、サフィックス「; jsessionid = ...」を相対URLに追加して、セッションを保存できます。 これはURL書き換えと呼ばれ、Thymeleafでは、各URLのサーブレットAPIからresponse.encodeURL(...)メカニズムを使用して独自の書き換えフィルターを接続できます。
- th:href属性を使用すると、(オプションで)テンプレートに有効なhref静的属性を設定できるため、プロトタイプの目的でテンプレートリンクを直接開いたときにブラウザーへのナビゲーションが維持されます。
- th:href属性を使用すると、(オプションで)テンプレートに有効なhref静的属性を設定できるため、プロトタイプの目的でテンプレートリンクを直接開いたときにブラウザーへのナビゲーションが維持されます。
メッセージ構文(#{...})と同様に、URLは別の式の結果でもあります。
<a th:href="@{${url}(orderId=${o.id})}">view</a> <a th:href="@{'/details/'+${user.login}(orderId=${o.id})}">view</a>
ホームページのメニュー
これでURLの作成方法がわかりました。ホームページに小さなナビゲーションメニューを追加するのはどうでしょうか。
<p>Please select an option</p> <ol> <li><a href="product/list.html" th:href="@{/product/list}">Product List</a></li> <li><a href="order/list.html" th:href="@{/order/list}">Order List</a></li> <li><a href="subscribe.html" th:href="@{/subscribe}">Subscribe to our Newsletter</a></li> <li><a href="userprofile.html" th:href="@{/userprofile}">See User Profile</a></li> </ol>
サーバーのルートディレクトリに関連するURLをリンクします
同じサーバー上の異なるコンテキストを参照するために、追加の構文を使用して、(コンテキスト依存の)ルートディレクトリに基づいてURLを作成することができます。 これらのURLは@ {〜/ path / to / something}としてリストされます
4.5フラグメント
フラグメント式は、マークアップのフラグメントを表現し、パターン間で移動する簡単な方法です。 これにより、コピーしたり、引数として他のテンプレートに渡したりすることができます。
最も一般的な使用方法は、 th:insertまたはth:replaceを使用してフラグメントを挿入することです (これについては次のセクションで詳しく説明します)。
<div th:insert = "〜{commons :: main}"> ...
ただし、他の変数と同様に、どこでも使用できます。
<div th:with="frag=~{footer :: #main/text()}"> <p th:insert="${frag}"> </div>
このチュートリアルの後半では、フラグメントレイアウトの詳細な説明を含むテンプレートレイアウトのセクション全体があります。
4.6リテラル
テキストリテラル
テキストリテラルは、単一引用符で囲まれた文字列です。 任意の文字を含めることができますが、 \ 'を使用してその中に単一引用符を含めないでください。
<p> Now you are looking at a <span th:text="'working web application'">template file</span>. </p>
数値リテラル
数値リテラルは単なる数字です。
<p>The year is <span th:text="2013">1492</span>.</p> <p>In two years, it will be <span th:text="2013 + 2">1494</span>.</p>
ブール/ブールリテラル
ブールリテラルはtrueとfalseです。 例:
<div th:if="${user.isAdmin()} == false"> ...
この例では、括弧の外側に「== false」が書き込まれ、Thymeleafが式を処理します。 括弧内に等式が含まれている場合、OGNL / SpringELエンジンがそれを処理します。
<div th:if="${user.isAdmin() == false}"> ...
リテラルnull
NULLリテラルも使用できます。
<div th:if="${variable.something} == null"> ...
リテラルトークン
数値、ブール、およびNULLリテラルは、リテラルトークンの特殊なケースです。
これらのトークンは、標準式を少し単純化します。 テキストリテラル( '...')と同じように機能しますが、使用できるのは文字(AZおよびaz)、数字(0-9)、角括弧([and])、ピリオド(。)、ハイフン(-)のみですおよびアンダースコア(_)。 スペースやカンマなどは使用できません。
良い部分は? トークンはそれらを囲む引用符を必要としません 。 したがって、次のことができます。
<div th:class="content">...</div>
代わりに:
<div th:class="'content'">...</div>
4.7テキストの追加
テキストは、リテラルであっても、変数やメッセージの処理結果であっても、 +演算子を使用して簡単に追加できます。
<span th:text="'The name of the user is ' + ${user.name}">
4.8置換リテラル
リテラル置換により、「...」+「...」を使用してリテラルを追加する必要なく、変数からの値を含む文字列を簡単にフォーマットできます。
これらの置換は、たとえば次のように垂直バー(|)で囲む必要があります。
<span th:text="|Welcome to our application, ${user.name}!|">
どちらが同等ですか:
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">
リテラル置換は、他のタイプの式と組み合わせることができます。
<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">
内部では、変数/メッセージ式($ {...}、* {...}、#{...})のみが許可されます| ... | リテラル置換。 他のリテラル( '...')、ブール値/数値トークン、条件式などはありません。
4.9算術演算
いくつかの算術演算も使用できます: +、-、*、/、% 。
<div th:with="isEven=(${prodStat.count} % 2 == 0)">
これらの演算子は、OGNL式自体にも直接適用できることに注意してください(この場合、Thymeleaf標準式メカニズムの代わりにOGNLが実行されます)。
<div th:with="isEven=${prodStat.count % 2 == 0}">
これらの演算子には、div(/)、mod(%)のテキストエイリアスが存在することに注意してください。
4.10比較と平等
式の値は、文字>、<、> =および<=、== 、!と比較することができます。 =演算子は、等しい(またはその不在)をチェックするために使用されます。 XMLセットの<and>文字は属性値に使用しないでください。したがって、これらは&lt;に置き換える必要があります。 および&gt;。
<div th:if="${prodStat.count} > 1">
<span th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')">
より簡単な代替方法は、これらの演算子のいくつかに存在するテキストエイリアスを使用することです :gt(>)、lt(<)、ge(> =)、le(<=)、not(!) また、eq(==)、neq / ne(!=)。
4.11条件式
条件式は、条件の評価結果に応じて2つの式のうちの1つのみを実行するように設計されています(それ自体が別の式です)。
フラグメントの例を見てみましょう(別の属性修飾子th:classを紹介します):
<tr th:class="${row.even}? 'even' : 'odd'"> ... </tr>
条件式の3つの部分(condition、then、else)はすべて式です。つまり、変数( $ {...} 、 * {...} )、メッセージ( #{...} )、 URL( @ {...} )またはリテラル( '...' )。
条件式は括弧でネストすることもできます:
<tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'"> ... </tr>
他の式も省略できます。その場合、条件がfalseの場合、null値が返されます。
<tr th:class="${row.even}? 'alt'"> ... </tr>
4.12デフォルト/デフォルト式(Elvisステートメント)
デフォルトの式は、部分のない特別な種類の条件値です。 これは、2つの式を指定できるGroovyなど、一部の言語に存在するElvis演算子と同等です。最初の式がnullでない場合に使用されますが、nullの場合は2番目の式が使用されます。
プロフィールページでどのように機能するかを見てみましょう。
<div th:object="${session.user}"> ... <p>Age: <span th:text="*{age}?: '(no age specified)'">27</span>.</p> </div>
ご覧のとおり、演算子は?:、そして、計算結果* * ageがnullの場合にのみ、ここで名前のデフォルト値(この場合はリテラル値)を指定するために使用します。 したがって、これは次と同等です。
<p>Age: <span th:text="*{age != null}? *{age} : '(no age specified)'">27</span>.</p>
条件値と同様に、括弧の間にネストされた式を含めることができます。
<p> Name: <span th:text="*{firstName}?: (*{admin}? 'Admin' : #{default.username})">Sebastian</span> </p>
4.13無操作トークン
無操作トークンは、記号(_)で表されます。
このトークンの目的は、式の望ましい結果が何もしないことであることを示すことです。処理された属性(たとえば、th:text)が完全に存在しないかのように正確に行います。
他の機能の中でも、これにより開発者はプロトタイプテキストをデフォルト値として使用できます。 たとえば、次の代わりに:
<span th:text="${user.name} ?: 'no user authenticated'">...</span>
...プロトタイピングのテキストとして「ユーザー認証なし」を直接使用できます。これにより、コードはデザインの面でより簡潔で普遍的になります。
<span th:text="${user.name} ?: _">no user authenticated</span>
4.15データ変換/フォーマット
Thymeleafは、変数( $ {...} )および割り当てられた( * {...} )式の二重括弧構文を定義します。これにより、変換サービスの構成を使用してデータ変換を適用できます。
基本的には次のようになります。
<td th:text="${{user.lastAccessDate}}">...</td>
二重括弧に気づきましたか?: $ {{...}} これにより、Thymeleafはuser.lastAccessDate式の結果を変換サービスに渡し、結果を返す前にフォーマット操作(Stringへの変換)を実行するように求められます。
user.lastAccessDateのタイプがjava.util.Calendarであると仮定すると、変換サービス(IStandardConversionServiceの実装)が登録され、Calendar-> Stringの有効な変換が含まれている場合、それが適用されます。
既定では、IStandardConversionService(クラスStandardConversionService)の実装は、オブジェクトに対して.toString()を実行するだけです。 変換サービスのカスタム実装を登録する方法の詳細については、「構成情報の詳細」を参照してください。
公式統合パッケージthymeleaf-spring3およびthymeleaf-spring4は、Thymeleaf変換サービスメカニズムをネイティブの変換サービスSpringインフラストラクチャと透過的に統合します。これにより、Spring構成で宣言された変換サービスおよびフォーマットは$ {{...}}および* {{...}}。
4.14前処理
式を処理するためのこれらすべての関数に加えて、Thymeleafにはプリプロセッサ式関数があります。
前処理は、標準式の実行前に行われる式の実行であり、これにより、最終的に実行される式を変更できます。
前処理された式は通常の式とまったく同じですが、二重アンダースコアで囲まれて表示されます(たとえば、__ $ {expression} __)。
たとえば、言語に固有の静的メソッドを呼び出すOGNL式を含むi18n Messages_fr.propertiesレコードがあるとします。
article.text=@myapp.translator.Translator@translateToFrench({0})
...およびMessages_es.propertiesに相当するもの:
article.text=@myapp.translator.Translator@translateToSpanish({0})
ロケールに応じて、いずれかの式を実行するマークアップフラグメントを作成できます。これを行うには、最初に式を(前処理によって)選択し、次にThymeleafを実行します。
<p th:text="${__#{article.text('textVar')}__}">Some text here...</p>
フランス語の前処理手順により、次の同等物が作成されることに注意してください。
<p th:text="${@myapp.translator.Translator@translateToFrench(textVar)}">Some text here...</p>
__プリプロセッサ文字列は、\ _ \ _を使用して属性でエスケープできます。