>> Visual Web Pack のほかのドキュメント
データベースデータからのツリーの構築
執筆: Chris Kutler、Gail Chappell、James Branam
| 2007 年 5 月 [Revision number: V5.5.1-1] |
|
|
このチュートリアルでは、データベース内のデータからツリー構造を動的に構築する方法について説明します。 NetBeans Visual Web Pack 5.5 を使用して、2 ページ構成のアプリケーションを構築し、最初のページにツリーコンポーネントを配置します。 ツリーの第 1 レベルノードにはデータベースから取得した旅行者の名前を表示し、第 2 レベルノードにはその旅行者の旅行情報を表示します。 旅行情報のノードは、旅行の詳細を示す 2 ページ目にリンクします。
|
|
目次
|
|
 |
このチュートリアルでは、次のテクノロジとリソースを使用します。
JavaServer Faces コンポーネント / Java EE プラットフォーム |
Java EE 5* の場合、1.2 J2EE 1.4 の場合、1.1
|
| Travel データベース |
必須 |
| BluePrints AJAX コンポーネントライブラリ |
任意 |
* このチュートリアルの公開時点で Java EE 5 をサポートしていたのは Sun Java System Application Server だけです。
このチュートリアルは、Sun Java System Application Server PE 9.0 Update Release 1 と Tomcat 5.5.17 を使用することを想定しています。 別のサーバーを使用している場合は、「リリースノート」と「FAQ」(または「日本語 FAQ」) で既知の問題やその回避策を確認してください。 サポートされているサーバーと Java EE プラットフォームについては、「リリースノート」を参照してください。
ホームページのデザイン
最初に、ツリーコンポーネントと TRIP データベース表を含むホームページを作成します。 作成するページは次の図のようになります。
 図 1: ページのデザイン |
-
新しい Visual Web アプリケーションプロジェクトを「
DatabaseTree」という名前で作成します。
-
「パレット」の「基本」セクションからページに「ツリー」コンポーネントをドラッグし、「旅行情報」と入力して、Enter キーを押します。 「プロパティー」ウィンドウで、「id」プロパティーを「displayTree」に、「clientSide」プロパティーを「True」に設定します。
clientSide を True に設定すると、すべての子ノードが、展開しているかどうかにかかわらずクライアントに送信されます。ただし、親ノードを展開しないかぎり子ノードは表示されません。 clientSide を False に設定すると、展開している親ノードの子ノードだけが送信されます。
-
「ツリーノード 1」を選択して右クリックし、ポップアップメニューから「削除」を選択します。
このアプリケーションでは、プログラムでツリーに値を表示するので、IDE によって作成される初期のツリーノードは必要ありません。 ノードを削除しないと、JSP タグの属性に設定された値が実行時の設定に優先して、ページにノードが表示されます。
-
「パレット」から「メッセージグループ」コンポーネントをページ上の右上隅にドラッグします。
データベースへの接続
ここでは、Travel データソースのデータベース表にページを接続します。 次に、旅行者の名前がアルファベット順に表示され、旅行の出発日が日付順に表示されるように、クエリーエディタを使用して、データを取得する SQL クエリーを編集します。
-
「実行時」ウィンドウを開き、「データベース」ノードを展開して、Travel データベースが接続されていることを確認します。
Travel データベースのバッジの jdbc ノードが壊れていてノードを展開できない場合、IDE は、このデータベースに接続されていません。 Travel データベースに接続するには、Travel の jdbc ノードを右クリックし、ポップアップメニューから「接続」を選択します。 「接続」ダイアログが表示された場合は、「パスワード」に「travel」と入力し、「セッション中はパスワードを保存」を選択して、「了解」をクリックします。 Travel データベースの jdbc ノードが表示されない場合は、IDE でデータベースを使用できるようにする方法について、「NetBeans Visual Web Pack 5.5 インストール」を参照してください。
注: Apache Tomcat を使用している場合は、データベースに接続する前に、derbyClient.jar ファイルを <Tomcat のインストールディレクトリ>/common/lib ディレクトリにコピーします。
-
次の図に示すように、TRAVEL データベースの jdbc ノードを展開し、「表」ノードを展開します。
 図 2: Travel データベース |
「TRIP」ノードをビジュアルデザイナー上にドラッグします。
「アウトライン」ウィンドウの「Page1」セクションに「tripDataProvider」ノードが表示され、「SessionBean1」セクションに「tripRowSet」ノードが表示されます。
「アウトライン」ウィンドウで、「tripRowSet」ノードを右クリックし、「SQL 文を編集」を選択します。
編集領域にクエリーエディタが表示され、TRIP 表の図が表示されます。
-
「実行時」ウィンドウから「Travel」>「表」>「PERSON」ノードをドラッグし、図 3 に示すように、クエリーエディタの TRIP 表の図の横にドロップします。
別の表の図が表示されます。2 つの表の図がリンク (結合) された状態になっています。
- PERSON 表内の PERSONID のチェックボックスの選択を解除します。
-
クエリーエディタのデザイングリッドで、TRAVEL.PERSON 表の NAME 行を探します。 「ソート方法」セルをクリックし、ドロップダウンリストから「昇順」を選択します。
この操作により、データベース表内の名前が姓のアルファベット順でソートされます。
-
TRAVEL.TRIP 表の DEPDATE 行を探します。 「ソート方法」セルをクリックし、ドロップダウンリストから「昇順」を選択します。
この操作により、旅行の出発日が古い日付から新しい日付の順でソートされます。 クエリーエディタは次の図のようになります。
 図 3: クエリーエディタ |
データベース表からのツリーの構築
ここでは、アプリケーションの両方のページで使用する情報を格納する要求 Bean プロパティーを追加します。 次に、TRIP と PERSON の各データベース表からツリーコンポーネントを動的に構築するコードを prerender() メソッドに追加します。
-
Page1 を開いて「アウトライン」ウィンドウを表示します。 「アウトライン」ウィンドウで、「RequestBean1」ノードを右クリックし、「追加」>「プロパティー」を選択します。 プロパティーの名前に「personId」、型に「Integer」と入力して、「了解」をクリックします。
次の図に示すように、このプロパティーには旅行者の ID を格納します。 あとで、このプロパティーを使用して現在の旅行者の ID を Page1 に渡す旅行の詳細ページを作成します。 このプロパティーが設定されると、Page1 でその旅行者のノードが展開されます。
図 4: 新しいプロパティーの追加 |
注: この製品バージョンのバグにより、「追加」サブメニューをアクティブにするには、ポップアップメニューを閉じ、RequestBean ノードをもう一度右クリックする必要がある場合があります。
-
Java エディタで Page1 を開き、prerender メソッドまでスクロールします。 prerender メソッドの本体を次のコード (太字部分) に置き換えます。
| コード例 1: Page1 の prerender メソッド |
public void prerender() {
// 要求 Bean の personId が設定されている場合は、
// Trip ページから戻ったところであり、
// 選択された旅行は表示済み。
// あとで personId を使用して、旅行者のノード
// を展開するかどうかを判断
Integer expandedPersonId = getRequestBean1().getPersonId();
try {
// 必要な変数を設定
Integer currentPersonId = new Integer(-1);
// nbrChildren が 0 以外の場合、これは
// ポストバックであり、ツリーは完成済み
int nbrChildren = displayTree.getChildCount();
if (nbrChildren == 0) {
// 外側 (旅行者) のノードの一覧
List outerChildren = displayTree.getChildren();
// 前の内容を消去
outerChildren.clear();
// 内側 (旅行) のノードの一覧
List innerChildren = null;
// SQL クエリーを実行
tripDataProvider.refresh();
// 結果セットの各行に対して繰り返す。
// 新しい旅行者が見つかるたびに、第 1 レベルのノードを追加。
// 第 2 レベルの旅行ノードを旅行者の親ノードに追加。
boolean hasNext = tripDataProvider.cursorFirst();
while (hasNext) {
Integer newPersonId =
(Integer) tripDataProvider.getValue(
"TRIP.PERSONID");
if (!newPersonId.equals(currentPersonId)) {
currentPersonId = newPersonId;
TreeNode personNode = new TreeNode();
personNode.setId("person" + newPersonId.toString());
personNode.setText(
(String)tripDataProvider.getValue(
"PERSON.NAME"));
// 要求 Bean から旅行者の ID が渡されたら、
// その旅行者のノードを展開
personNode.setExpanded(newPersonId.equals
(expandedPersonId));
outerChildren.add(personNode);
innerChildren = personNode.getChildren();
}
// 新しい旅行ノードを作成
TreeNode tripNode = new TreeNode();
tripNode.setId("trip" +
tripDataProvider.getValue("TRIP.TRIPID").toString());
tripNode.setText(
tripDataProvider.getValue("TRIP.DEPDATE").toString());
tripNode.setUrl("/faces/Trip.jsp?tripId=" +
tripDataProvider.getValue("TRIP.TRIPID").toString());
innerChildren.add(tripNode);
hasNext = tripDataProvider.cursorNext();
}
}
} catch (Exception ex) {
log("Exception gathering tree data", ex);
error("Exception gathering tree data: " + ex);
}
}
|
このコードにより、personId 順に並べられている旅行レコードが読み取られます。 personId ごとに新しい第 1 レベルのノードがツリー内に作成されます。 次に、その personId に関連付けられている旅行ごとに、第 2 レベルのノード (下位ノード) が作成されます。 最後に、第 2 レベルの旅行ノードが、あとで作成する tripNode_action メソッドにバインドされます。
- Alt-Shift-F キーを押して、クラスが見つからないというエラーを修正します。 「インポートを修正」ダイアログで、「完全修飾名」フィールドに java.util.List が表示されていることを確認し、「了解」をクリックします。
プロジェクトを実行します。
Web ブラウザが開き、次の図に示すように、それぞれ旅行者の名前を示す第 1 レベルのノードごとのツリーコンポーネントが表示されます。 ノードを展開すると、その旅行者の旅行の出発日が表示されます。 図に示すように、旅行者の名前は姓のアルファベット順、旅行の出発日は日付順に表示されます。 次の節では、ユーザーが旅行ノードをクリックしたときに 2 ページ目に移動するためのコードを追加します。 2 ページ目には、ユーザーが選択した旅行の詳細が表示されます。
図 5: 動的なツリーノード |
詳細ページの追加
ここでは、次の図に示すように、アプリケーションに 2 ページ目を追加します。 このページでは、プロパティーシートコンポーネントを使用して、最初のページでユーザーが選択した旅行の詳細を動的に表示します。
図 6: 詳細ページ |
-
「プロジェクト」ウィンドウを開き、「Web ページ」ノードを右クリックして、ポップアップメニューから「新規」>「ページ」を選択します。 新しいページに「
Trip」という名前を付けます。
-
「実行時」ウィンドウを開き、「表」>「TRIP」ノードを、「Trip」ページのビジュアルデザイナー上にドラッグします。 次の図に示すように、ダイアログで、「作成 SessionBean1 tripRowSet1」の横にあるラジオボタンを選択します。 「了解」をクリックします。
図 7: 行セットを使用した新規データプロバイダの追加 |
「アウトライン」ウィンドウの「Trip」セクションに「tripDataProvider1」ノードが表示され、「SessionBean1」セクションに「tripRowSet1」ノードが表示されます。
- 「アウトライン」ウィンドウで、「tripRowSet1」ノードを右クリックし、「SQL 文を編集」を選択します。
クエリーエディタのデザイングリッドで、TRIPID 行の任意のセルを右クリックし、「クエリー条件を追加」を選択します。 ダイアログで、「比較」ドロップダウンリストを「=等しい」に設定し、「パラメータ」ラジオボタンを選択します。 「了解」をクリックします。
TRIPID の「条件」列に「=?」と表示され、SQL クエリーに次の WHERE 句が追加されます。 WHERE TRAVEL.TRIP.TRIPID = ?
- ビジュアルデザイナーで「Trip」ページを開きます。 「パレット」の「基本」セクションからページに「ハイパーリンク」コンポーネントをドラッグし、「ホーム
」と入力して、Enter キーを押します。
ハイパーリンクコンポーネントの「プロパティー」ウィンドウで、「action」プロパティーの省略符号ボタン (...) をクリックし、ドロップダウンリストから「hyperlink1_action」を選択して、「了解」をクリックします。
IDE によって Java ソースに hyperlink1_action イベントハンドラが追加されます。
- 「パレット」からページに「メッセージグループ」コンポーネントをドラッグし、ハイパーリンクコンポーネントの右側に配置します。
-
「パレット」の「レイアウト」セクションからページに「プロパティーシート」コンポーネントをドラッグし、 ハイパーリンクコンポーネントの下に配置します。
プロパティーシートコンポーネントは、旅行情報を配置するためのコンテナです。 プロパティーシートコンポーネントにはプロパティーシートセクションが含まれ、その中にさらにプロパティーコンポーネントが含まれます。
「プロパティーシートセクション 1」を選択します。 「プロパティー」ウィンドウで、「label」プロパティーを「旅行の詳細」に設定します。
注: プロジェクトのソースレベルが 1.4 に設定されている場合は、「プロパティー」ウィンドウでプロパティーシートのラベルを変更してもラベルは更新されません。
-
「アウトライン」ウィンドウで、「propertySheet1」>「section1」を展開し、「property1」ノードを選択します。 「プロパティー」ウィンドウで、「
label」プロパティーを「出発日:」に設定し、Enter キーを押します。
-
「アウトライン」ウィンドウで、「section1」を選択して右クリックして、ポップアップメニューから「追加 プロパティー」を選択します。 追加されたプロパティーの「プロパティー」ウィンドウで、「
label」プロパティーを「出発地:」に設定し、Enter キーを押します。
「パレット」から「静的テキスト」コンポーネントをドラッグし、「アウトライン」ウィンドウの「property1」ノードの上にドロップします。
静的テキストが「property1」のサブノードになります。 この静的テキストはビジュアルデザイナーにも表示されます。
静的テキストコンポーネントを右クリックし、ポップアップメニューから「データにバインド」を選択します。 必要に応じて、「データプロバイダにバインド」タブをクリックして、このタブを前面に表示します。 次の図に示すように、ダイアログの「データフィールド」で「TRIP.DEPDATE」を選択し、「了解」をクリックします。
ビジュアルデザイナー内で静的テキストコンポーネントに現在の日付が表示されます。
図 8: 「データにバインド」ダイアログ |
- property2 に静的テキストコンポーネントを追加します。 静的テキストを TRIP.DEPCITY にバインドします。
コードの追加
ここでは、Page1 で格納された tripId を Trip ページで取得し、Trip ページで格納された personId を Page1 で取得できるようにするコードを追加します。
-
Java エディタで「Trip」ページを開き、prerender メソッドまでスクロールします。 Page1 で格納された tripId をこのメソッドで取得できるように、次のコード (太字部分) を追加します。
| コード例 2: Trip ページの prerender メソッド |
public void prerender() {
// 要求パラメータから旅行者の ID を取得
String parmTripId = (String)
getExternalContext().getRequestParameterMap().get("tripId");
if (parmTripId != null) {
Integer tripId = new Integer(parmTripId);
try {
getSessionBean1().getTripRowSet1().setObject(1, tripId);
tripDataProvider1.refresh();
} catch (Exception e) {
error("Cannot display trip " + tripId);
log("Cannot display trip " + tripId, e);
}
} else {
error("No trip id specified.");
}
}
|
setObject メソッドは、旅行のクエリーの最初の引数を tripId に設定します。 つまり、クエリー内の「?」を tripId に置き換えます。 このクエリーには引数が 1 つしかないので、setObject を一度だけ呼び出します。 tripDataProvider1.refresh() は、CachedRowSet.release() を呼び出して、CachedRowSetDataProvider のカーソルをリセットします。 この時点では CachesRowSet を実行しません。
hyperlink1_action メソッドまでスクロールします。 personId を Page1 に渡す次のコード (太字部分) を追加します。
| コード例 3: Trip ページの hyperlink1_action メソッド |
public String hyperlink1_action() {
getRequestBean1().setPersonId(
(Integer)tripDataProvider1.getValue("trip.personid"));
return null;
}
|
ページナビゲーションの定義
最後に、Page1 のツリーノードから Trip ページへのナビゲーションを指定します。
-
「プロジェクト」ウィンドウを開き、「ページナビゲーション」ノードをダブルクリックします。
-
Page1.jsp アイコンの横にあるコネクタポートをクリックし、Trip.jsp アイコンまでコネクタをドラッグします。
Trip.jsp アイコンをクリックして拡大し、ハイパーリンクコンポーネントから Page1.jsp アイコンまでコネクタをドラッグします。 ページナビゲーションの設定は次の図のようになります。
図 9: ページナビゲーション |
アプリケーションを実行します。 ホームページで、旅行者の名前を展開し、旅行の出発日をクリックします。
次の図に示すように、旅行の詳細を示す Trip ページが表示されます。
図 10: 実行時の詳細ページ |
- Trip ページで「ホーム」リンクをクリックします。 ホームページでは、最後に選択した旅行の第 1 レベルノードが展開されたままです。
- ツリーのほかの第 1 レベルノードを展開または縮小したり、旅行の出発日をクリックしたりして、アプリケーションの動作を確認します。
その他の可能な操作: ツリーノードへのアクションメソッドのバインド
JavaServer Faces 1.2 のツリーコンポーネントを使用している場合は (プロジェクトのJava EE バージョンの設定が「Java EE 5」プラットフォームになっている場合)、ツリーノードにアクションメソッドをバインドできます。アクションメソッドでは、ツリーコンポーネントの getSelected() メソッドを呼び出して、クリックされたノードを判別できます。次に、その手順を示します。
- 要求 Bean に Integer 型の「tripId」プロパティーを追加します。
Page1 の Java ソースに次のメソッドを追加します。
| コード例 4: Page1 の tripNode_action メソッド |
public String tripNode_action() {
// 現在選択されているツリーノードの ID を取得
String nodeId = displayTree.getSelected();
// 指定された ID を持つツリーノードコンポーネントを検索
TreeNode selectedNode =
(TreeNode) this.getForm1().findComponentById(nodeId);
try {
// ノードの id プロパティーは「trip」と tripId で構成される
// tripId を抽出し、次のページ用に保存
Integer tripId = Integer.valueOf(selectedNode.getId().substring(4));
getRequestBean1().setTripId(tripId);
} catch (Exception e) {
error("Can't convert node id to Integer: " +
selectedNode.getId().substring(4));
return null;
}
return "case1";
}
|
- Page1 の
prerender メソッドで、次のコードをコード例 5 のコードに置き換えます。 tripNode.setUrl("/faces/Trip.jsp?tripId=" +
tripDataProvider.getValue("TRIP.TRIPID").toString());
| コード例 5: prerender メソッドの調整 |
ExpressionFactory exFactory =
getApplication().getExpressionFactory();
ELContext elContext =
getFacesContext().getELContext();
tripNode.setActionExpression(
exFactory.createMethodExpression(
elContext, "#{Page1.tripNode_action}",
String.class, new Class<?>[0])); |
- Alt-Shift-F キーを押して、インポートを修正します。
-
Trip ページの prerender() メソッドの本体を次のコードに置き換えます。
| コード例 6: Trip ページの prerender メソッド |
public void prerender() {
Integer tripId = getRequestBean1().getTripId();
try {
getSessionBean1().getTripRowSet1().setObject(1, tripId);
tripDataProvider1.refresh();
} catch (Exception e) {
error("Cannot display trip " + tripId);
log("Cannot display trip " + tripId, e);
}
}
|
- アプリケーションを実行します。
ツリーノードの選択に関する注意事項
プロジェクトが J2EE 1.4 の場合は、ツリーノードの選択について次の点に注意してください。
- JavaServer Faces 1.1 のツリーコンポーネントでは、選択されたノードを判別するために
getSelected メソッドまたは getCookieSelectedTreeNode メソッドを使用できません。 ユーザーがブラウザの Cookie を無効にしている場合、これらのメソッドから正しい値が返されません。 また、Cookie を有効にしている場合でも、ユーザーがはじめてページにアクセスし、ノードをクリックしたときに、Cookie から間違った値が返される可能性があります。 以前にアクセスしたときの Cookie が残っている場合は、以前に選択された値が返される可能性があります。 JavaServer Faces 1.2 バージョンのツリーコンポーネントでは、選択された値が Cookie に保存されないので、この問題は発生しません。
- ツリーノードの強調表示はセッションが変わっても解除されません。 このチュートリアルのプログラムを複数回実行すると、最後のセッションで選択したノードが、新しいセッションではじめてページを開いたときにも強調表示されます。 この問題は、選択されたノード ID を渡すのに Cookie を使用していることが原因で起こります。
まとめ
このチュートリアルでは、データベース内のデータからツリー構造を構築しました。 2 ページ構成のアプリケーションを作成し、最初のページにツリーコンポーネントを配置しました。 ツリーの第 1 レベルノードにはデータベースから取得した旅行者の名前を表示し、第 2 レベルノードにはその旅行者の旅行情報を表示しました。 最初のページに表示される各旅行を、旅行の詳細を示す 2 ページ目にリンクしました。
関連項目:
更新日: 2007 年 5 月 24 日