FeaturesPluginsDocs & SupportCommunityPartners

>> Visual Web Pack のほかのドキュメント

データベースデータからのツリーの構築

2007 年 5 月 [Revision number: V5.5.1-1]    

このチュートリアルでは、データベース内のデータからツリー構造を動的に構築する方法について説明します。 NetBeans Visual Web Pack 5.5 を使用して、2 ページ構成のアプリケーションを構築し、最初のページにツリーコンポーネントを配置します。 ツリーの第 1 レベルノードにはデータベースから取得した旅行者の名前を表示し、第 2 レベルノードにはその旅行者の旅行情報を表示します。 旅行情報のノードは、旅行の詳細を示す 2 ページ目にリンクします。

目次

ホームページのデザイン
データベースへの接続
データベース表からのツリーの構築
詳細ページの追加
コードの追加
ページナビゲーションの定義
その他の可能な操作: ツリーノードへのアクションメソッドのバインド
ツリーノードの選択に関する注意事項
  このページの情報は NetBeans 5.5 および 5.5.1 の Visual Web Pack が対象です。

このチュートリアルでは、次のテクノロジとリソースを使用します。

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: ページのデザイン
図 1: ページのデザイン
  1. 新しい Visual Web アプリケーションプロジェクトを「DatabaseTree」という名前で作成します。
  2. 「パレット」の「基本」セクションからページに「ツリー」コンポーネントをドラッグし、「旅行情報」と入力して、Enter キーを押します。 「プロパティー」ウィンドウで、「id」プロパティーを「displayTree」に、「clientSide」プロパティーを「True」に設定します。

    clientSideTrue に設定すると、すべての子ノードが、展開しているかどうかにかかわらずクライアントに送信されます。ただし、親ノードを展開しないかぎり子ノードは表示されません。 clientSideFalse に設定すると、展開している親ノードの子ノードだけが送信されます。
  3. 「ツリーノード 1」を選択して右クリックし、ポップアップメニューから「削除」を選択します。

    このアプリケーションでは、プログラムでツリーに値を表示するので、IDE によって作成される初期のツリーノードは必要ありません。 ノードを削除しないと、JSP タグの属性に設定された値が実行時の設定に優先して、ページにノードが表示されます。
  4. 「パレット」から「メッセージグループ」コンポーネントをページ上の右上隅にドラッグします。

データベースへの接続

ここでは、Travel データソースのデータベース表にページを接続します。 次に、旅行者の名前がアルファベット順に表示され、旅行の出発日が日付順に表示されるように、クエリーエディタを使用して、データを取得する SQL クエリーを編集します。
  1. 「実行時」ウィンドウを開き、「データベース」ノードを展開して、Travel データベースが接続されていることを確認します。

    Travel データベースのバッジの jdbc ノードが壊れていてノードを展開できない場合、IDE は、このデータベースに接続されていません。 Travel データベースに接続するには、Travel の jdbc ノードを右クリックし、ポップアップメニューから「接続」を選択します。 「接続」ダイアログが表示された場合は、「パスワード」に「travel」と入力し、「セッション中はパスワードを保存」を選択して、「了解」をクリックします。 Travel データベースの jdbc ノードが表示されない場合は、IDE でデータベースを使用できるようにする方法について、「NetBeans Visual Web Pack 5.5 インストール」を参照してください。

    注: Apache Tomcat を使用している場合は、データベースに接続する前に、derbyClient.jar ファイルを <Tomcat のインストールディレクトリ>/common/lib ディレクトリにコピーします。
  2. 次の図に示すように、TRAVEL データベースの jdbc ノードを展開し、「表」ノードを展開します。

    図 2: Travel データベース
    図 2: Travel データベース
  3. 「TRIP」ノードをビジュアルデザイナー上にドラッグします。

    「アウトライン」ウィンドウの「Page1」セクションに「tripDataProvider」ノードが表示され、「SessionBean1」セクションに「tripRowSet」ノードが表示されます。
  4. 「アウトライン」ウィンドウで、「tripRowSet」ノードを右クリックし、「SQL 文を編集」を選択します。

    編集領域にクエリーエディタが表示され、TRIP 表の図が表示されます。
  5. 「実行時」ウィンドウから「Travel」>「表」>「PERSON」ノードをドラッグし、図 3 に示すように、クエリーエディタの TRIP 表の図の横にドロップします。

    別の表の図が表示されます。2 つの表の図がリンク (結合) された状態になっています。
  6. PERSON 表内の PERSONID のチェックボックスの選択を解除します。
  7. クエリーエディタのデザイングリッドで、TRAVEL.PERSON 表の NAME 行を探します。 「ソート方法」セルをクリックし、ドロップダウンリストから「昇順」を選択します。

    この操作により、データベース表内の名前が姓のアルファベット順でソートされます。
  8. TRAVEL.TRIP 表の DEPDATE 行を探します。 「ソート方法」セルをクリックし、ドロップダウンリストから「昇順」を選択します。

    この操作により、旅行の出発日が古い日付から新しい日付の順でソートされます。 クエリーエディタは次の図のようになります。

    図 3: クエリーエディタ
    図 3: クエリーエディタ

データベース表からのツリーの構築

ここでは、アプリケーションの両方のページで使用する情報を格納する要求 Bean プロパティーを追加します。 次に、TRIP と PERSON の各データベース表からツリーコンポーネントを動的に構築するコードを prerender() メソッドに追加します。
  1. Page1 を開いて「アウトライン」ウィンドウを表示します。 「アウトライン」ウィンドウで、「RequestBean1」ノードを右クリックし、「追加」>「プロパティー」を選択します。 プロパティーの名前に「personId」、型に「Integer」と入力して、「了解」をクリックします。

    次の図に示すように、このプロパティーには旅行者の ID を格納します。 あとで、このプロパティーを使用して現在の旅行者の ID を Page1 に渡す旅行の詳細ページを作成します。 このプロパティーが設定されると、Page1 でその旅行者のノードが展開されます。

    図 4: 新しいプロパティーの追加
    図 4: 新しいプロパティーの追加

    注: この製品バージョンのバグにより、「追加」サブメニューをアクティブにするには、ポップアップメニューを閉じ、RequestBean ノードをもう一度右クリックする必要がある場合があります。
  2. 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 メソッドにバインドされます。
  3. Alt-Shift-F キーを押して、クラスが見つからないというエラーを修正します。 「インポートを修正」ダイアログで、「完全修飾名」フィールドに java.util.List が表示されていることを確認し、「了解」をクリックします。
  4. プロジェクトを実行します。

    Web ブラウザが開き、次の図に示すように、それぞれ旅行者の名前を示す第 1 レベルのノードごとのツリーコンポーネントが表示されます。 ノードを展開すると、その旅行者の旅行の出発日が表示されます。 図に示すように、旅行者の名前は姓のアルファベット順、旅行の出発日は日付順に表示されます。 次の節では、ユーザーが旅行ノードをクリックしたときに 2 ページ目に移動するためのコードを追加します。 2 ページ目には、ユーザーが選択した旅行の詳細が表示されます。

    図 5: 動的なツリーノード
    図 5: 動的なツリーノード

詳細ページの追加

ここでは、次の図に示すように、アプリケーションに 2 ページ目を追加します。 このページでは、プロパティーシートコンポーネントを使用して、最初のページでユーザーが選択した旅行の詳細を動的に表示します。

図 6: 詳細ページ
図 6: 詳細ページ
  1. 「プロジェクト」ウィンドウを開き、「Web ページ」ノードを右クリックして、ポップアップメニューから「新規」>「ページ」を選択します。 新しいページに「Trip」という名前を付けます。
  2. 「実行時」ウィンドウを開き、「表」>「TRIP」ノードを、「Trip」ページのビジュアルデザイナー上にドラッグします。 次の図に示すように、ダイアログで、「作成 SessionBean1 tripRowSet1」の横にあるラジオボタンを選択します。 「了解」をクリックします。

    図 7: 行セットを使用した新規データプロバイダの追加
    図 7: 行セットを使用した新規データプロバイダの追加

    「アウトライン」ウィンドウの「Trip」セクションに「tripDataProvider1」ノードが表示され、「SessionBean1」セクションに「tripRowSet1」ノードが表示されます。
  3. 「アウトライン」ウィンドウで、「tripRowSet1」ノードを右クリックし、「SQL 文を編集」を選択します。
  4. クエリーエディタのデザイングリッドで、TRIPID 行の任意のセルを右クリックし、「クエリー条件を追加」を選択します。 ダイアログで、「比較」ドロップダウンリストを「=等しい」に設定し、「パラメータ」ラジオボタンを選択します。 「了解」をクリックします。

    TRIPID の「条件」列に「=?」と表示され、SQL クエリーに次の WHERE 句が追加されます。
    WHERE TRAVEL.TRIP.TRIPID = ? 
  5. ビジュアルデザイナーで「Trip」ページを開きます。 「パレット」の「基本」セクションからページに「ハイパーリンク」コンポーネントをドラッグし、「ホーム」と入力して、Enter キーを押します。
  6. ハイパーリンクコンポーネントの「プロパティー」ウィンドウで、「action」プロパティーの省略符号ボタン (...) をクリックし、ドロップダウンリストから「hyperlink1_action」を選択して、「了解」をクリックします。

    IDE によって Java ソースに hyperlink1_action イベントハンドラが追加されます。
  7. 「パレット」からページに「メッセージグループ」コンポーネントをドラッグし、ハイパーリンクコンポーネントの右側に配置します。
  8. 「パレット」の「レイアウト」セクションからページに「プロパティーシート」コンポーネントをドラッグし、 ハイパーリンクコンポーネントの下に配置します。

    プロパティーシートコンポーネントは、旅行情報を配置するためのコンテナです。 プロパティーシートコンポーネントにはプロパティーシートセクションが含まれ、その中にさらにプロパティーコンポーネントが含まれます。
  9. 「プロパティーシートセクション 1」を選択します。 「プロパティー」ウィンドウで、「label」プロパティーを「旅行の詳細」に設定します。

    注: プロジェクトのソースレベルが 1.4 に設定されている場合は、「プロパティー」ウィンドウでプロパティーシートのラベルを変更してもラベルは更新されません。
  10. 「アウトライン」ウィンドウで、「propertySheet1」>「section1」を展開し、「property1」ノードを選択します。 「プロパティー」ウィンドウで、「label」プロパティーを「出発日:」に設定し、Enter キーを押します。
  11. 「アウトライン」ウィンドウで、「section1」を選択して右クリックして、ポップアップメニューから「追加 プロパティー」を選択します。 追加されたプロパティーの「プロパティー」ウィンドウで、「label」プロパティーを「出発地:」に設定し、Enter キーを押します。
  12. 「パレット」から「静的テキスト」コンポーネントをドラッグし、「アウトライン」ウィンドウの「property1」ノードの上にドロップします。

    静的テキストが「property1」のサブノードになります。 この静的テキストはビジュアルデザイナーにも表示されます。
  13. 静的テキストコンポーネントを右クリックし、ポップアップメニューから「データにバインド」を選択します。 必要に応じて、「データプロバイダにバインド」タブをクリックして、このタブを前面に表示します。 次の図に示すように、ダイアログの「データフィールド」で「TRIP.DEPDATE」を選択し、「了解」をクリックします。

    ビジュアルデザイナー内で静的テキストコンポーネントに現在の日付が表示されます。

    図 8: 「データにバインド」ダイアログ
    図 8: 「データにバインド」ダイアログ
  14. property2 に静的テキストコンポーネントを追加します。 静的テキストを TRIP.DEPCITY にバインドします。

コードの追加

ここでは、Page1 で格納された tripId を Trip ページで取得し、Trip ページで格納された personId を Page1 で取得できるようにするコードを追加します。
  1. 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 を実行しません。
  2. hyperlink1_action メソッドまでスクロールします。 personId を Page1 に渡す次のコード (太字部分) を追加します。

    コード例 3: Trip ページの hyperlink1_action メソッド
        public String hyperlink1_action() {
            getRequestBean1().setPersonId(
                    (Integer)tripDataProvider1.getValue("trip.personid"));
            return null;
        }
      

ページナビゲーションの定義

最後に、Page1 のツリーノードから Trip ページへのナビゲーションを指定します。
  1. 「プロジェクト」ウィンドウを開き、「ページナビゲーション」ノードをダブルクリックします。
  2. Page1.jsp アイコンの横にあるコネクタポートをクリックし、Trip.jsp アイコンまでコネクタをドラッグします。
  3. Trip.jsp アイコンをクリックして拡大し、ハイパーリンクコンポーネントから Page1.jsp アイコンまでコネクタをドラッグします。 ページナビゲーションの設定は次の図のようになります。

    図 9: ページナビゲーション
    図 9: ページナビゲーション
  4. アプリケーションを実行します。 ホームページで、旅行者の名前を展開し、旅行の出発日をクリックします。

    次の図に示すように、旅行の詳細を示す Trip ページが表示されます。

    図 10: 実行時の詳細ページ
    図 10: 実行時の詳細ページ
  5. Trip ページで「ホーム」リンクをクリックします。 ホームページでは、最後に選択した旅行の第 1 レベルノードが展開されたままです。
  6. ツリーのほかの第 1 レベルノードを展開または縮小したり、旅行の出発日をクリックしたりして、アプリケーションの動作を確認します。

その他の可能な操作: ツリーノードへのアクションメソッドのバインド

JavaServer Faces 1.2 のツリーコンポーネントを使用している場合は (プロジェクトのJava EE バージョンの設定が「Java EE 5」プラットフォームになっている場合)、ツリーノードにアクションメソッドをバインドできます。アクションメソッドでは、ツリーコンポーネントの getSelected() メソッドを呼び出して、クリックされたノードを判別できます。次に、その手順を示します。
  1. 要求 Bean に Integer 型の「tripId」プロパティーを追加します。
  2. 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";
       }
      
  3. 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]));
  4. Alt-Shift-F キーを押して、インポートを修正します。
  5. 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);
               }
       }
      
  6. アプリケーションを実行します。

ツリーノードの選択に関する注意事項

プロジェクトが 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 日


Bookmark this page

del.icio.us furl simpy slashdot technorati digg
Companion
Projects:
MySQL Database Server   Open JDK: an Open SourceJDK   GlassFish Community: an Open Source Application Server    Mobile & Embedded Community    Open Solaris   java.net - The Source for Java Technology Collaboration   Virtual Box - full virtualizer  Open ESB - The Open Enterprise Service Bus Powered by