Webページにデータを表示する必要がある場合は、ADFデータ・バインディングを使用すると、ADF Facesコンポーネントを使用してデータにバインドする表の宣言的な作成が容易になります。 デフォルトでは、ユーザーは行セットをスクロールして行を選択できるようになります。 また、開発者は、選択された行の詳細を表示する新規ページを作成し、2つのページ間のナビゲーションを追加できます。 ADFデータ・バインディングによって、選択した行の詳細が自動的に表示されるため、追加コードは必要ありません。
たとえば、図9-9に、SOADEMO-CLIENTアプリケーションのBrowseItems
ページを示します。 ユーザーは製品を選択してから、「View Details」ボタンをクリックしてSelectItem
ページに移動します。このページで、選択した品目の詳細を表示できます。
図9-10に、選択した製品に対するSelectItem
ページを示します。
データのコレクションを表示するページを作成し、選択した品目の詳細を表示するページにリンクする手順は、次のとおりです。
2つのページに対するナビゲーション・ダイアグラムを作成します。
品目のコレクションを表示するページ(参照ページ)に、コレクションを表示するためのADF Faces表を作成し、詳細ページに移動するためのボタンを追加します。
詳細ページに、詳細を表示するフォームを作成します。
ナビゲーション・ダイアグラムを作成すると、ページおよびページ間ナビゲーションの両方を作成できます。
ナビゲーション・ダイアグラムを作成する手順は、次のとおりです。
第9.3.1項「JSF Webページの作成方法」で説明したWebページの作成手順に従って、参照ページと詳細ページの両方を作成します。
たとえば、SOADEMO-CLIENTアプリケーションでは、図9-11に示すように、BrowseItems
ページとSelectItem
ページに対するJSPを作成します。
コンポーネント・パレットから「JSF Navigation Case」コンポーネント(図9-12を参照)をクリックし、「browseItems.jsp」アイコン、「selectItem.jsp」アイコンの順にクリックして、2つのページ間に新規のナビゲーション・ケースを作成します。
デフォルトでは、図9-13に示すように、結果値は「success」に設定されます。
success
結果テキストをダブルクリックし、details
などのわかりやすいテキストに変更します。
selectItem
ページからbrowseItems
ページに戻る別のナビゲーション・ケースを作成します。 この結果値も、back
などのわかりやすい名前に変更します。
ヒント: 「JSF Navigation Case」行をドラッグして矢印線を作成すると、読みやすいダイアグラムを簡単に作成できます。 |
これで、ナビゲーション・ケースが作成されました。最初のページにコマンド・コンポーネントを配置し、action属性を結果の値に設定すると、ユーザーは2番目のページに移動します。 たとえば、browseItems
ページにコマンド・ボタンを配置し、そのaction属性をdetails
に設定すると、ユーザーはselectItem
ページに移動します。
JSFナビゲーション・モデラーまたはJSF構成エディタを使用してナビゲーション・ルールを作成すると、JDeveloperでは、ナビゲーション・ルール要素がfaces-config.xml
ファイルに自動的に追加されます。
例9-4に、faces-config.xml
ファイルに定義された2つのナビゲーション・ルールを示します。 最初のルールでは、アクティブ化したナビゲーション・コンポーネントのaction
属性で指定した結果がdetails
のときに、browseItems
ページからselectItem
ページに移動します。 2番目のルールでは、アクティブ化したナビゲーション・コンポーネントのaction
属性がreturn
のときに、selectItem
ページからbrowseItems
ページに戻ります。
例9-4 faces-config.xmlファイル内のナビゲーション・ルール
<navigation-rule> <from-view-id>/retailclient/browseItems.jsp</from-view-id> <navigation-case> <from-outcome>details</from-outcome> <to-view-id>/retailclient/selectItem.jsp</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/retailclient/selectItem.jsp</from-view-id> <navigation-case> <from-outcome>return</from-outcome> <to-view-id>/retailclient/browseItems.jsp</to-view-id> </navigation-case> </navigation-rule>
Sun社のJSFリファレンス実装では、faces-config.xml
ファイルのナビゲーション・ルールを読み込み、ナビゲーション・ルールを評価して表示するページを決定するNavigationHandler
クラスをコールします。 このハンドラは、最初に、ナビゲーションが開始されたページについて、すべてのルールを検出します。 次に、アクション・メソッドで戻される結果、またはコンポーネントのactionプロパティの結果文字列として設定されている結果を確認し、使用する正しいルールを決定します。
ナビゲーション・モデラーを使用してナビゲーションを作成および維持する場合は、次の機能に注意してください。
XMLエディタを使用してfaces-config.xml
ファイル内のナビゲーション・ルールを直接変更した場合、または構成エディタでナビゲーション・ルールを変更した場合は、通常、ナビゲーション・モデラーがリフレッシュされます。 各JSF構成ファイルには、独自のナビゲーション・モデラー・ダイアグラムがあります。 ナビゲーション・ダイアグラム内の情報が、そのダイアグラムのfaces-config.xml
ファイルの情報と一致しない場合は、ダイアグラム内を右クリックし、「ダイアグラム」→「faces-configからダイアグラムをリフレッシュ」の順に選択して、ダイアグラムを手動でリフレッシュできます。
ダイアグラムでナビゲーション・ケースを削除すると、関連するnavigation-case
要素がfaces-config.xml
ファイルから削除されます。 ルール内のすべてのケースを削除した場合、navigation-rule
要素はfaces-config.xml
ファイルに残ります。 faces-config.xml
ファイル内のルールは直接削除できます。
ダイアグラムでナビゲーション・ケースのラベルを編集すると、faces-config.xml
ファイル内の関連するnavigation-case
要素が更新されます。 ナビゲーション・ケースの宛先はダイアグラムで変更できません。 ただし、ナビゲーション・ケースの宛先は、JSF構成エディタを使用するか、faces-config.xml
ファイル自体を直接変更することによって変更できます。
ページ・アイコンをナビゲーション・ダイアグラムから削除した場合、関連するページ・ファイルは、アプリケーション・ナビゲータのViewController
プロジェクトの「Webコンテンツ」フォルダから削除されません。
ページを手動で編集した場合、JDeveloperでは、ナビゲーション・ダイアグラムまたは関連するfaces-config.xml
ファイルが自動的に更新されません。 さらに、既存のページの動作に影響を与える変更をページ・フローに加えた場合、JDeveloperでは、ページ内のコードが自動的に更新されません。 ナビゲーション・ダイアグラムとWebページの変更を一致させるには、ナビゲーション・ダイアグラムでページ内を右クリックし、「ダイアグラム」→「すべてのページからダイアグラムをリフレッシュ」の順に選択します。
ナビゲーション・モデラー・ダイアグラムは、faces-config.xml
ファイルに対するデフォルトのエディタです。 アプリケーションが大規模または複雑な場合は、ファイルが大きいためにダイアグラムのロード速度が遅くなる場合があります。 JSF構成ファイルに対してJSFダイアグラム・ファイルを作成しない場合は、「ツール」→「設定」→「ファイル・タイプ」→「デフォルトのエディタ」→「JSF構成ファイル」オプションの順に選択して、デフォルトのエディタを変更します。 faces-config.xml
ファイルを初めて開く前にデフォルトのエディタを変更すると、特に要求しないかぎり、ダイアグラム・ファイルは作成されません。
データのコレクション全体を表示するには、メソッドから戻されてデータ・コントロールに表示されているコレクションをJSFページに表としてドラッグします。
コレクション・データをページに追加する手順は、次のとおりです。
ビジュアル・エディタでJSFページを開きます。
データ・コントロール・パレットから、コレクションを戻すメソッドの戻りを選択します。
たとえば、すべての製品を表示する表を作成するには、findAllProduct
メソッドから戻されたProduct
コレクションをドラッグします。 図9-14に、データ・コントロール・パレット内のProduct
コレクションを示します。
メソッドの戻りをJSFページまでドラッグし、ポップアップ・メニューから適切な表を選択します。
コレクションをドラッグするときは、次のタイプの表から選択できます。
ADF表: 編集可能な表列に表示する特定の属性、およびデータの表示に使用するUIコンポーネントを選択できます。 デフォルトでは、コレクション・オブジェクトの各属性はinputText
コンポーネントに表示されるため、表が編集可能になります。
ADF読取り専用表: 「ADF表」と同じですが、各属性はoutputText
コンポーネントに表示されます。
ADF読取り専用動的表: 戻されて表示される属性は動的に決まります。 このコンポーネントは、対応するオブジェクトの属性が実行時まで不明な場合、またはJSFページの列名をハードコードしない場合に便利です。 たとえば、多相コレクションを戻すメソッドの場合、(つまり、getAnimals()
は哺乳動物または鳥類のコレクションを戻す可能性がある)、動的表には、戻り値に応じて異なる属性を表示できます。
後続の「表の列の編集」ダイアログでは、次の操作を実行できます。
列の表示ラベルを変更できます。 デフォルトでは、ラベルは表バインディングのlabel
プロパティにバインドされます。 このプロパティへのバインディングによって、ラベル・テキストの値を1回変更でき、このラベルを表示するすべてのページに同じラベルを表示できます。 このダイアログでは、テキストまたはEL式を入力するかわりに、ラベル値をリソース・ファイル内のキーなどにバインドできます。
たとえば、browseItems
ページの表にあるdescription列のヘッダーは、対応する属性バインディングのlabelプロパティにバインドされます。
#{bindings.findAllProduct1.labels.description}
列の属性バインディングを変更できます。
たとえば、description列をlistPrice
属性にバインドするように変更できます。 次の点に注意してください。
バインディングを変更すると、列のラベルも変更されます。
現在、他の列にバインドされている属性へのバインディングを変更すると、UIコンポーネントは、その属性に現在バインドされている列で使用するコンポーネントとは異なるコンポーネントに変更されます。
単に列を並べ替える場合は、順序ボタンを使用してください。 詳細は、4番目のブレットを参照してください。
属性の表示に使用するUIコンポーネントを変更できます。 UIコンポーネントはinputText
またはoutputText
のいずれかで、コレクションをページにドロップしたときに選択した表に基づいて設定されます。 このコンポーネントは、ドロップダウン・メニューを使用して他のコンポーネントに変更できます。 コマンド・リンクやボタンなどの別のコンポーネントを使用する場合は、このダイアログを使用してoutputText
コンポーネントを選択し、構造ウィンドウで、このコンポーネントに別のUIコンポーネント(例: コマンド・リンク)を親として追加する必要があります。
順序ボタンを使用して、列の順序を変更できます。
「新規」ボタンを使用して、列を追加できます。 この操作によって、ダイアログの下部に新規の列が追加され、デフォルトで、コレクション内で次の順序にある属性の値が移入されます。 この値は編集する必要があります。 選択できるのは、表がバインドされているオブジェクトに関連した属性のみです。
「削除」ボタンを使用して、列を削除できます。 この操作によって、表から列が削除されます。
「選択を有効にする」を選択して、tableSelectOne
コンポーネントを表のselection
ファセットに追加できます。 表で選択した行の詳細を表示するページに移動するには、このオプションを選択する必要があります。
「ソートの有効化」を選択して、すべての列をソートできます。
詳細ページに移動するコマンド・ボタンを追加するには、図9-15に示すように、構造ウィンドウでtableSelectOne
コンポーネントのcommandButton
を選択します。
注意: このコンポーネントが表示されるのは、前の手順で表を作成したときに「選択を有効にする」オプションを選択した場合のみです。 |
プロパティ・インスペクタで、Action
属性のドロップダウン・メニューを使用して、前の一連の手順でナビゲーション・ダイアグラムに作成した結果を選択します。 たとえば、2つのページ間にdetails
という結果を作成した場合は、detailsを選択します。 図9-16に、Action属性に対してこの結果を選択したプロパティ・インスペクタを示します。
これで、ユーザーがこのボタンをクリックすると、ナビゲーション・ケースで定義したページ(ここではselectItem
ページ)に移動します。
データ・コントロール・パレットからアイテムをドラッグ・アンド・ドロップしてADF Webアプリケーションを作成すると、JDeveloperでは、そのアプリケーションの実行に必要なすべてのファイルが作成および登録されます。 具体的には、JDeveloperで次の処理が実行されます。
「アプリケーション・ソース」ディレクトリのビュー・パッケージにDataBindings.cpx
ファイルが作成され(まだ存在しない場合)、ページのエントリが追加されます。
このDataBindings.cpx
ファイルは、アプリケーションのバインディング・コンテキストを定義します。 このファイルは、各ページを対応するページ定義ファイルにマップし、これらのページで使用するデータ・コントロールを登録します。 このデータ・コントロールは、DataControls.dcx
ファイルに定義されます。
ADFバインディング・フィルタがweb.xml
ファイルに登録されます。
このADFバインディング・フィルタによって、バインディング・コンテキストへのアクセスに必要なHTTPリクエストが事前処理されます。
ADFフェーズ・リスナーがfaces-config.xml
ファイルに登録されます。
次のADFランタイム・ライブラリがビュー・プロジェクトのプロジェクト・プロパティに追加されます。
ADF Model Runtime(adfm.jar
)
ADF Controller(adf-controller.jar
)
ページ定義ファイル(ページに対して存在しない場合)がページ定義サブパッケージに追加され、その名前がプロジェクト・プロパティのADF設定に定義されます。 デフォルトのサブパッケージは、「アプリケーション・ソース」ディレクトリのview.pageDefs
です。
ページ定義ファイル(<
pageName
>
PageDef.xml
)によって、アプリケーションのビュー・レイヤーにある各ページに対してADFバインディング・コンテナが定義されます。 このバインディング・コンテナによって、すべてのADFバインディング・オブジェクトへのランタイム・アクセスが可能になります。
ページで参照されるバインディング・オブジェクトの定義の追加も含めて、ページ定義ファイルが構成されます。
例9-5に、Product
コレクションをドロップした場合に作成されるページ定義ファイルを示します。 メソッド・イテレータは、findAllProduct
メソッドの戻りを参照します。 これによって、戻されたすべてのインスタンスのデータにページからアクセスできます。 メソッド・アクション・バインディングは、実際にメソッドを起動するバインディングです。 表バインディングはイテレータ内の結果を参照し、各属性のデータが表示可能になります。
例9-5 ページ定義コード
<executables> <methodIterator id="findAllProductIter" Binds="findAllProduct.result" DataControl="ProductsFacadeLocal" RangeSize="10" BeanClass="oracle.soademo.clientmodel.Product"/> </executables> <bindings> <methodAction id="findAllProduct" InstanceName="ProductsFacadeLocal.dataProvider" DataControl="ProductsFacadeLocal" MethodName="findAllProduct" RequiresUpdateModel="true" Action="999" ReturnName="ProductsFacadeLocal.methodResults.ProductsFacadeLocal_ dataProvider_findAllProduct_result"/> <table id="findAllProduct1" IterBinding="findAllProductIter"> <AttrNames> <Item Value="category"/> <Item Value="description"/> <Item Value="id"/> <Item Value="listPrice"/> <Item Value="name"/> <Item Value="prodid"/> <Item Value="producer"/> </AttrNames> </table> </bindings>
ビルトインのコンポーネントがJSFページに追加されます。
表をJSFページにドロップすると、JDeveloperでは、バインド先となるオブジェクトの各属性の列を格納する表が作成されます。 これを行うために、JDeveloperではADF Faces table
コンポーネントが挿入されます。 このコンポーネントには、表バインディングで名前を指定した各属性のADF Faces column
コンポーネントが格納されます。 さらに、各列には、属性の値にバインドされるinput
またはoutputText
コンポーネントが格納されます。 各列のヘッダー属性は、表バインディングの各属性のlabel
プロパティにバインドされます。 例9-6に、Product
の戻りを表としてドロップした場合に生成されるコードの一部を示します。
例9-6 JSFページ・コード
<af:table value="#{bindings.findAllProduct1.collectionModel}" var="row"
rows="#{bindings.findAllProduct1.rangeSize}"
first="#{bindings.findAllProduct1.rangeStart}"
emptyText="#{bindings.findAllProduct1.viewable ? \
'No rows yet.\' : \'Access Denied.\'}">
<af:column headerText="#{bindings.findAllProduct1.labels.category}"
sortProperty="category" sortable="false">
<af:outputText value="#{row.category}"/>
</af:column>
<af:column headerText="#{bindings.findAllProduct1.labels.description}"
sortProperty="description" sortable="false">
<af:outputText value="#{row.description}"/>
</af:column>
...
</af:table>
ADF Faces表自体では、イテレータ・バインディングでアクセスしたデータが繰り返されます。 これを行うために、この表では、イテレータ・バインディングからの結果セットがoracle.adf.view.faces.model.CollectionModel
オブジェクトにラップされます。 表が繰り返されると、コレクション内の各項目が、var
属性を使用してtable
コンポーネント内で使用可能になります。
例9-6では、findAllProduct1
表バインディングからのコレクションに対して表が繰り返され、findAllProductIter
イテレータ・バインディングが参照されます。 イテレータ・バインディングは、現行データ・オブジェクトを決定します。 表のvar
属性をrow
に設定すると、次のoutputText
タグの値に示すように、各列は、このrow
変数を使用して、表タグに記述された現行の行に対する現行のデータ・オブジェクトにアクセスします。
<af:outputText value="#{row.category}"/>
ADF Facesコンポーネントが使用されている場合は、そのADF Facesコンポーネントに必要なすべてのライブラリ、ファイルおよび構成要素が追加されます。
ページにADFバインディングがある場合、クライアントまたはコントローラから起動したビジネス・サービスとの実行時の相互作用は、Oracle ADFバインディング・コンテキストと呼ばれる単一オブジェクトを介してアプリケーションで管理されます。 このADFバインディング・コンテキストは、Oracle ADF Modelレイヤーから導出されたデータ・コントロールおよびデータ・バインディング・オブジェクトのリストが格納されているコンテナ・オブジェクトです。
図9-17に示すように、ADFのライフサイクルを通じて、Oracle ADFバインディング・コンテキストは、DataControls.dcx
、DataBindings.cpx
およびページ定義ファイルから作成されます。 DataControls.dcx
ファイルは、アプリケーションで使用可能なすべてのデータ・コントロールを定義します。 DataBindings.cpx
ファイルは、アプリケーションのページで現在使用されているデータ・コントロールを参照し、ページ定義ファイルに定義したバインディング・オブジェクトが格納されているバインディング・コンテナをWebページのURLにマップします。 ページ定義ファイルは、アプリケーション・ページで使用するバインディング・オブジェクトを定義します。 ページごとに1つのページ定義があります。
たとえば、Product
の戻りから作成された表を使用すると、バインディング・コンテナはfindAllProductIter
メソッド・イテレータを起動し、そのメソッド・イテレータはProduct
コレクションを戻すfindAllProduct
メソッドを起動します。 イテレータではデータが繰り返され、最初に検出したレコードのデータをバインディング・コンテナに配置することによって、そのデータがUIコンポーネントで使用可能になります。 イテレータからの値にアクセスできるページ定義にはfindAllProduct1
表のバインディングがあり(例9-5を参照)、UIコンポーネントがEL式(#{bindings.findAllProduct1.collectionModel}
)を使用してfindAllProduct1
バインディングにバインドされているため、データはこのコンポーネントによって表示されます。
実行時のADF表の具体的な処理内容については、『Oracle Application Development Framework開発者ガイド』を参照してください。
戻されたコレクションをフォームとしてドラッグすると、戻された項目の詳細データを表示できます。 読取り専用フォームを使用した場合、表示されるのは現在選択されているデータのみです。
フォームを追加して品目の詳細を表示する手順は、次のとおりです。
ビジュアル・エディタでJSFページを開きます。
データ・コントロール・パレットから、コレクションを戻すメソッドの戻りを選択します。
たとえば、製品に関する情報を表示するフォームを作成するには、図9-18に示すように、製品の戻りのフォームであるfindAllProduct
メソッドをドラッグします。 このメソッドによって、データがすでにテキスト・フィールドに移入されたフォームが作成されます。
コレクションをページまでドラッグし、ポップアップ・メニューから、オブジェクトのデータを表示するフォームのタイプを選択します。 選択できるフォームのタイプは次のとおりです。
ADFフォーム: 「フォーム・フィールドの編集」ダイアログが起動します。このダイアログでは、デフォルトで属性のフィールドを作成するかわりに、属性を個別に選択できます。 また、各属性で使用するラベルおよびUIコンポーネントも選択できます。 デフォルトでは、ADF inputText
コンポーネントが使用されます。ただし、日付については、selectInputDate
コンポーネントが使用されます。 各inputText
コンポーネントには、属性に対して検証を設定できるvalidatorタグがあります。
ユーザーがコレクション内のすべてのデータ・オブジェクトに移動できるように、ナビゲーション・コントロールを含めることもできます。 このダイアログの使用方法については、「ヘルプ」をクリックしてください。 panelForm
コンポーネント内には、すべてのUIコンポーネントが配置されています。
ADF読取り専用フォーム: 「ADFフォーム」と同じですが、デフォルトでoutputText
コンポーネントが使用されます。 このフォームはデータの表示が目的であるため、validator
タグは追加されていません。 コンポーネントごとにlabel
属性が移入されます。 Date
型の属性でもoutputText
コンポーネントが使用されます。 すべてのコンポーネントはpanelLabelAndMessage
コンポーネント内に配置され、さらに、これらのコンポーネントはpanelForm
コンポーネント内に配置されます。
これで、表で選択した品目のデータがフォームに表示されます。
データ・コントロール・パレットからフォームをドロップすることは、表をドロップすることと同じ結果になります。 詳細は、第9.5.6項「ページへのコレクション追加時の処理内容」を参照してください。 次に、JDeveloperで実行される処理を簡単に説明します。
フォームに対してバインディングが作成され、ページ定義ファイルに追加されます。 例9-7に、Product
の戻りをフォームとしてドロップした場合に作成されるページ定義コードを示します。
例9-7 フォームに対するページ定義コード
<executables> <methodIterator id="findAllProductIter" Binds="findAllProduct.result" DataControl="ProductsFacadeLocal" RangeSize="10" BeanClass="oracle.soademo.clientmodel.Product"/> </executables> <bindings> <methodAction id="findAllProduct" InstanceName="ProductsFacadeLocal.dataProvider" DataControl="ProductsFacadeLocal" MethodName="findAllProduct" RequiresUpdateModel="true" Action="999" IsViewObjectMethod="false" ReturnName="ProductsFacadeLocal.methodResults.ProductsFacadeLocal_ dataProvider_findAllProduct_result"/> <attributeValues id="category" IterBinding="findAllProductIter"> <AttrNames> <Item Value="category"/> </AttrNames> </attributeValues> <attributeValues id="description" IterBinding="findAllProductIter"> <AttrNames> <Item Value="description"/> </AttrNames> </attributeValues> ... </bindings>
メソッド・イテレータとメソッド・バインディングは、表の場合もフォームの場合も同じです。 ただし、表バインディングは使用せず、各属性で独自のバインディングが使用されます。
UIコンポーネントに必要なコードがJSFページに追加されます。
UIコンポーネントの属性(例: value
)は、その属性のバインディング・オブジェクトのプロパティ(例: inputValue
)にバインドされます。 例9-8に、findAllProduct
メソッドのProduct
コレクションをデフォルトのADFフォームとしてドロップした場合に、JSFページに生成されるコードを示します。
例9-8 ADFフォームに対するJSFコード
<af:panelForm> <af:panelLabelAndMessage label="#{bindings.category.label}"> f:outputText value="#{bindings.category.inputValue}"/> </af:panelLabelAndMessage> <af:panelLabelAndMessage label="#{bindings.description.label}"> <af:outputText value="#{bindings.description.inputValue}"/> </af:panelLabelAndMessage> <af:panelLabelAndMessage label="#{bindings.id.label}"> <af:outputText value="#{bindings.id.inputValue}"> <f:convertNumber groupingUsed="false" pattern="#{bindings.id.format}"/> </af:outputText> </af:panelLabelAndMessage> ... </af:panelForm>