Apache-tapestry-components

提供:Dev Guides
移動先:案内検索

Apacheタペストリー-コンポーネント

前述のように、コンポーネントとページは同じです。ただし、ページはルートコンポーネントであり、1つ以上の子コンポーネントが含まれます。 コンポーネントは常にページ内に常駐し、ページのほぼすべての動的機能を実行します。

Tapestryコンポーネントは、*インタラクティブAJAX *を使用して、複雑なグリッド機能への単純なHTMLリンクをレンダリングします。 コンポーネントには別のコンポーネントも含めることができます。 タペストリーのコンポーネントは、次の項目で構成されています-

  • Component Class -コンポーネントのメインJavaクラス。
  • * XMLテンプレート*-XMLテンプレートはページテンプレートに似ています。 コンポーネントクラスは、テンプレートを最終出力としてレンダリングします。 一部のコンポーネントにはテンプレートがありません。 この場合、出力は MarkupWriter クラスを使用してコンポーネントクラス自体によって生成されます。
  • Body -ページテンプレート内で指定されたコンポーネントにはカスタムマークアップが含まれている場合があり、「コンポーネントボディ」と呼ばれます。 コンポーネントテンプレートに <body/> 要素がある場合、<body/>要素はコンポーネントの本文に置き換えられます。 これは、前述のXMLテンプレートセクションで説明したレイアウトに似ています。
  • レンダリング-レンダリングは、XMLテンプレートとコンポーネントの本体をコンポーネントの実際の出力に変換するプロセスです。
  • パラメータ-コンポーネントとページ間の通信を作成し、それらの間でデータを渡すために使用されます。
  • イベント-コンポーネントからコンテナ/親(ページまたは別のコンポーネント)に機能を委任します。 ページナビゲーションの目的で広く使用されています。

レンダリング

コンポーネントのレンダリングは、一連の事前定義されたフェーズで行われます。 コンポーネントシステムの各フェーズには、コンポーネントクラスの規則または注釈によって定義された対応するメソッドが必要です。

//Using annotaion
@SetupRender
void initializeValues() {
  //initialize values
}

//using convention
boolean afterRender() {
  //do logic
   return true;
}

フェーズ、そのメソッド名、および注釈を以下にリストします。

Annotation Default Method Names
@SetupRender setupRender()
@BeginRender beginRender()
@BeforeRenderTemplate beforeRenderTemplate()
@BeforeRenderBody beforeRenderBody()
@AfterRenderBody afterRenderBody()
@AfterRenderTemplate afterRenderTemplate()
@AfterRender afterRender()
@CleanupRender cleanupRender()

各フェーズには特定の目的があり、次のとおりです-

SetupRender

SetupRenderは、レンダリングプロセスをキックスタートします。 通常、コンポーネントのパラメーターを設定します。

BeginRender

BeginRenderは、コンポーネントのレンダリングを開始します。 通常、コンポーネントの開始/開始タグをレンダリングします。

BeforeRenderTemplate

BeforeRenderTemplateは、XMLテンプレートを装飾するために使用され、テンプレートの周りに特別なマークアップを追加します。 また、テンプレートのレンダリングをスキップするオプションも提供します。

BeforeRenderBody

BeforeRenderTemplateには、コンポーネントのbody要素のレンダリングをスキップするオプションがあります。

AfterRenderBody

AfterRenderBodyは、コンポーネントのボディがレンダリングされた後に呼び出されます。

AfterRenderTemplate

AfterRenderTemplateは、コンポーネントのテンプレートがレンダリングされた後に呼び出されます。

AfterRender

AfterRenderはBeginRenderの対応物であり、通常は終了タグをレンダリングします。

CleanupRender

CleanupRenderは、SetupRenderに対応しています。 レンダリングプロセス中に作成されたすべてのオブジェクトを解放/破棄します。

レンダリングフェーズのフローは順方向だけではありません。 フェーズの戻り値に応じて、フェーズ間を行き来します。

たとえば、SetupRenderメソッドがfalseを返す場合、レンダリングはCleanupRenderフェーズにジャンプし、その逆も同様です。 異なるフェーズ間のフローを明確に理解するには、下の図のフローを確認してください。

注釈リスト

単純なコンポーネント

「Hello、Tapestry」という出力メッセージを持つ単純なコンポーネントHelloを作成しましょう。 Helloコンポーネントとそのテンプレートのコードは次のとおりです。

package com.example.MyFirstApplication.components;
public class Hello {
}
<html
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">

   <div>
      <p>Hello, Tapestry (from component).</p>
   </div>

</html>

Helloコンポーネントは、ページテンプレートで次のように呼び出すことができます-

<html title = "Hello component test page"
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">
<t:hello/>
</html>

同様に、コンポーネントは、次に示すように、テンプレートの代わりにMarkupWriterを使用して同じ出力をレンダリングする場合があります。

package com.example.MyFirstApplication.components;

import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.annotations.BeginRender;

public class Hello {
   @BeginRender
   void renderMessage(MarkupWriter writer) {
      writer.write("<p>Hello, Tapestry (from component)</p>");
   }
}

コンポーネントテンプレートを変更し、次のコードブロックに示すように<body/>要素を含めます。

<html>
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">

   <div>
      <t:body/>
   </div>
</html>

これで、以下に示すように、ページテンプレートのコンポーネントマークアップに本文が含まれることがあります。

<html title = "Hello component test page"
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">

   <t:hello>
      <p>Hello, Tapestry (from page).</p>
   </t:hello>
</html>

出力は次のようになります-

<html>
   <div>
      <p>Hello, Tapestry (from page).</p>
   </div>
</html>

パラメーター

これらのパラメーターの主な目的は、コンポーネントのフィールドとページのプロパティ/リソース間の接続を作成することです。 パラメータを使用して、コンポーネントとその対応するページが相互に通信し、データを転送します。 これは Two Way Data Binding と呼ばれます。

たとえば、ユーザー管理ページで年齢を表すために使用されるテキストボックスコンポーネントは、パラメーターを通じてその初期値(データベースで利用可能)を取得します。 繰り返しますが、ユーザーの年齢が更新されて送信された後、コンポーネントは同じパラメーターを使用して更新された年齢を送り返します。

コンポーネントクラスで新しいパラメーターを作成するには、フィールドを宣言し、 @ Parameter アノテーションを指定します。 この@Parameterには2つのオプションの引数があります。

  • 必須-パラメータを必須として設定します。 タペストリーが提供されない場合、例外が発生します。
  • -パラメータのデフォルト値を指定します。

パラメータは、ページテンプレートでコンポーネントタグの属性として指定する必要があります。 属性の値は、前の章で説明したバインディング式/拡張を使用して指定する必要があります。 以前に学んだ拡張の一部は次のとおりです-

  • プロパティ展開(prop:«val»)-ページクラスのプロパティからデータを取得します。
  • メッセージ展開(message:«val»)-index.propertiesファイルで定義されたキーからデータを取得します。
  • コンテキスト展開(context:«val»)-Webコンテキストフォルダ/src/main/webappからデータを取得します。
  • アセットの展開(asset:«val»)-jarファイル/META-INF/assetsに埋め込まれたリソースからデータを取得します。
  • シンボル展開(シンボル:«val»)-AppModule.javafileで定義されているシンボルからデータを取得します。

タペストリーには、より多くの便利な拡張機能があり、その一部を以下に示します-

  • リテラル展開(literal:«val»)-リテラル文字列。
  • 変数展開(var:«val»)-コンポーネントのレンダー変数の読み取りまたは更新を許可します。
  • * Validate expansion(validate:«val»)*-オブジェクトの検証ルールを指定するために使用される特殊な文字列。 たとえば、validate:required、minLength = 5。
  • * Translate(translate:«val»)*-入力検証でTranslatorクラス(クライアント側からサーバー側への変換)を指定するために使用されます。
  • * Block(block:«val»)*-テンプレート内のブロック要素のID。
  • * Component(component:«val»)*-テンプレート内の別のコンポーネントのID。

プロパティの展開とVarの展開を除き、上記の展開はすべて読み取り専用です。 それらは、ページとデータを交換するためにコンポーネントによって使用されます。 属性値として展開を使用する場合、 $ \ {…​} は使用しないでください。 代わりに、ドル記号とブレース記号なしの展開を使用します。

パラメータを使用するコンポーネント

コンポーネントクラスに name パラメータを追加し、それに応じてコンポーネントテンプレートとページテンプレートを変更することにより、メッセージを動的にレンダリングするようにHelloコンポーネントを変更して、新しいコンポーネントHelloWithParameterを作成しましょう。

  • 新しいコンポーネントクラス HelloWithParameter.java を作成します。
  • プライベートフィールドを追加し、 @ Parameter アノテーションを付けて名前を付けます。 必須の引数を使用して必須にします。
@Parameter(required = true)
private String name;
  • @ Propery アノテーションを使用して、プライベートフィールドを追加します。 結果のプロパティは、コンポーネントテンプレートで使用されます。 コンポーネントテンプレートは、 @ Parameter アノテーションが付けられたフィールドにはアクセスできず、 @ Property アノテーションが付けられたフィールドにのみアクセスできます。 コンポーネントテンプレートで使用できる変数は、レンダリング変数と呼ばれます。
@Property
 private String result;
  • RenderBodyメソッドを追加し、nameパラメーターの値をresultプロパティにコピーします。
@BeginRender
void initializeValues() {
   result = name;
}
  • 新しいコンポーネントテンプレート HelloWithParamter.tml を追加し、resultプロパティを使用してメッセージをレンダリングします。
<div> Hello, ${result} </div>
  • テストページ(testhello.java)に新しいプロパティUsernameを追加します。
public String getUsername() {
   return "User1";
}
  • ページテンプレートで新しく作成されたコンポーネントを使用し、 HelloWithParameter コンポーネントのnameパラメーターでUsernameプロパティを設定します。
<t:helloWithParameter name = "username"/>

完全なリストは次のとおりです-

package com.example.MyFirstApplication.components;

import org.apache.tapestry5.annotations.*;
public class HelloWithParameter {
   @Parameter(required = true)
   private String name;

   @Property
   private String result;

   @BeginRender
   void initializeValues() {
      result = name;
   }
}
<html
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">

   <div> Hello, ${result} </div>

</html>
package com.example.MyFirstApplication.pages;

import org.apache.tapestry5.annotations.*;
public class TestHello {
   public String getUsername() {
      return "User1";
   }
}
<html title = "Hello component test page"
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">
   <t:helloWithParameter name = "username"/>

</html>

結果は次のようになります-

<div> Hello, User1 </div>

拡張パラメーター

前の章では、カスタムコンポーネントで単純なパラメーターを作成して使用する方法を分析しました。 拡張パラメータには、完全なマークアップも含まれる場合があります。 この場合、ページテンプレートのサブセクションなどのコンポーネントタグ内でマークアップを指定する必要があります。 組み込みのifコンポーネントには、成功条件と失敗条件の両方のマークアップがあります。 成功のマークアップはコンポーネントタグの本体として指定され、失敗のマークアップは elseparameter を使用して指定されます。

*if* コンポーネントの使用方法を見てみましょう。 ifコンポーネントには2つのパラメータがあります-
  • test -単純なプロパティベースのパラメーター。
  • Else -条件が失敗した場合に代替マークアップを指定するために使用される高度なパラメーター

Tapestryは、次のロジックを使用してテストプロパティの値をチェックし、trueまたはfalseを返します。 これは Type Coercion と呼ばれ、あるタイプのオブジェクトを同じコンテンツを持つ別のタイプに変換する方法です。

  • データ型が String の場合、リテラル文字列「False」ではなく、空白でない場合は「True」(大文字と小文字は区別されません)。
  • データ型が Number の場合、ゼロ以外の場合はTrue。
  • データ型が Collection の場合、空でない場合はTrue。
  • データ型が Object の場合、True(nullでない場合)。

条件が満たされると、コンポーネントはその本体をレンダリングします。それ以外の場合は、elseパラメーターの本体をレンダリングします。

完全なリストは次のとおりです-

package com.example.MyFirstApplication.pages;
public class TestIf {
   public String getUser() {
      return "User1";
   }
}
<html title = "If Test Page"
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"
   xmlns:p = "tapestry:parameter">

   <body>
      <h1>Welcome!</h1>
      <t:if test = "user">
         Welcome back, ${user}
         <p:else>
            Please <t:pagelink page = "login">Login</t:pagelink>
         </p:else>
      </t:if>
   </body>

</html>

コンポーネントイベント/ページナビゲーション

タペストリーアプリケーションは、相互作用する*ページのコレクション*です。 これまで、個々のページ間で通信を行わずにページを作成する方法を学びました。 コンポーネントイベントの主な目的は、サーバー側イベントを使用してページ間(ページ内でも)の対話を提供することです。 コンポーネントイベントのほとんどは、クライアント側のイベントから発生します。

たとえば、ユーザーがページ内のリンクをクリックすると、Tapestryはターゲットページを呼び出すのではなく、ターゲット情報を使用して同じページ自体を呼び出し、サーバー側イベントを発生させます。 タペストリーページはイベントをキャプチャし、ターゲット情報を処理し、ターゲットページへのサーバー側のリダイレクトを行います。

タペストリーは、ページナビゲーションの* Post/Redirect/Get(RPG)デザインパターン*に従います。 RPGでは、ユーザーがフォームを送信して投稿要求を行うと、サーバーは投稿されたデータを処理しますが、応答を直接返しません。 代わりに、別のページへのクライアント側のリダイレクトを行い、結果を出力します。 RPGパターンは、ブラウザーの戻るボタン、ブラウザーの更新ボタンなどによるフォームの重複送信を防ぐために使用されます。Tapestryは、次の2種類のリクエストを提供することでRPGパターンを提供します。

  • コンポーネントイベントリクエスト-このタイプのリクエストは、ページ内の特定のコンポーネントを対象とし、コンポーネント内でイベントを発生させます。 このリクエストはリダイレクトのみを行い、レスポンスは出力しません。
  • リクエストのレンダリング-これらのタイプのリクエストはページを対象とし、クライアントにレスポンスをストリーミングします。

コンポーネントイベントとページナビゲーションを理解するには、タペストリーリクエストのURLパターンを知る必要があります。 両方のタイプのリクエストのURLパターンは次のとおりです-

  • コンポーネントイベントリクエスト-
/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
  • リクエストのレンダリング-
/<<page_name_with_path>>/<<context_information>>

URLパターンの例のいくつかは次のとおりです-

  • インデックスページは、 [[1]] でリクエストできます。
  • インデックスページがサブフォルダ管理者の下で利用できる場合、 [[2]] によってリクエストできます。
  • ユーザーがインデックスページで id test の* ActionLinkコンポーネントをクリックすると、URLは* [[3]]

イベント

デフォルトでは、Tapestryはすべてのリクエストに対して OnPassivate および OnActivate イベントを発生させます。 コンポーネントイベントリクエストタイプの場合、tapestryはコンポーネントに応じて追加の1つ以上のイベントを発生させます。 ActionLinkコンポーネントはActionイベントを発生させ、Formコンポーネントは Validate、Success などの複数のイベントを発生させます。

イベントは、対応するメソッドハンドラーを使用してページクラスで処理できます。 メソッドハンドラーは、メソッドの命名規則または @ OnEvent アノテーションを使用して作成されます。 メソッドの命名規則の形式は、* On«EventName»From«ComponentId»*です。

  • idテスト*を持つActionLinkコンポーネントのアクションイベントは、次のいずれかの方法で処理することができます-
void OnActionFromTest() {
}
@OnEvent(component = "test", name = "action")
void CustomFunctionName() {
}

メソッド名に特定のコンポーネントがない場合、一致するイベントを持つすべてのコンポーネントに対してメソッドが呼び出されます。

void OnAction() {
}

OnPassivateおよびOnActivateイベント

OnPassivateは、OnActivateイベントハンドラーのコンテキスト情報を提供するために使用されます。 一般に、Tapestryはコンテキスト情報を提供し、OnActivateeventハンドラーの引数として使用できます。

たとえば、コンテキスト情報がint型の3である場合、OnActivateイベントは次のように呼び出すことができます-

void OnActivate(int id) {
}

シナリオによっては、コンテキスト情報が利用できない場合があります。 この状況では、OnPassivateイベントハンドラーを使用して、コンテキスト情報をOnActivateイベントハンドラーに提供できます。 OnPassivateイベントハンドラの戻り値の型は、OnActivateイベントハンドラの引数として使用する必要があります。

int OnPassivate() {
   int id = 3;
   return id;
}
void OnActivate(int id) {
}

イベントハンドラーの戻り値

Tapestryは、イベントハンドラーの戻り値に基づいてページリダイレクトを発行します。 イベントハンドラは、次の値のいずれかを返す必要があります。

  • ヌル応答-ヌル値を返します。 Tapestryは現在のページURLを作成し、リダイレクトとしてクライアントに送信します。
public Object onAction() {
   return null;
}
  • 文字列応答-文字列値を返します。 Tapestryは、値に一致するページのURLを構築し、リダイレクトとしてクライアントに送信します。
public String onAction() {
   return "Index";
}
  • クラス応答-ページクラスを返します。 Tapestryは、返されたページクラスのURLを構築し、リダイレクトとしてクライアントに送信します。
public Object onAction() {
   return Index.class
}
  • ページ応答-@InjectPageで注釈されたフィールドを返します。 Tapestryは、挿入されたページのURLを作成し、リダイレクトとしてクライアントに送信します。
@InjectPage
private Index index;

public Object onAction(){
   return index;
}
  • HttpError -HTTPErrorオブジェクトを返します。 Tapestryはクライアント側のHTTPエラーを発行します。
public Object onAction(){
   return new HttpError(302, "The Error message);
}
  • リンク応答-リンクインスタンスを直接返します。 Tapestryは、LinkオブジェクトからURLを構築し、リダイレクトとしてクライアントに送信します。
  • Stream Response - StreamResponse オブジェクトを返します。 Tapestryは、クライアントブラウザーに直接応答としてストリームを送信します。 レポートと画像を直接生成し、クライアントに送信するために使用されます。
  • Url Response - java.net.URL オブジェクトを返します。 Tapestryは、オブジェクトから対応するURLを取得し、リダイレクトとしてクライアントに送信します。
  • オブジェクト応答-上記の指定値以外の値を返します。 タペストリーはエラーを発生させます。

イベントコンテキスト

一般に、イベントハンドラーは引数を使用してコンテキスト情報を取得できます。 たとえば、コンテキスト情報がタイプintの3である場合、イベントハンドラは次のようになります-

Object onActionFromTest(int id) {
}

Tapestryはコンテキスト情報を適切に処理し、引数を介してメソッドに提供します。 場合によっては、プログラミングの複雑さのためにTapestryが適切に処理できないことがあります。 その時点で、完全なコンテキスト情報を取得し、自分で処理する場合があります。

Object onActionFromEdit(EventContext context) {
   if (context.getCount() > 0) {
      this.selectedId = context.get(0);
   } else {
      alertManager.warn("Please select a document.");
      return null;
   }
}