バイナリ・データを渡すWebサービス(パート5): Swingクライアントの作成

この課題の目標は、すでに作成、デプロイしたWebサービスのクライアントを作成し、そのクライアントにGUIインタフェースを追加することです。このインタフェースには、Webサービスがバイナリ・データとして渡すイメージが表示されます。

クライアントの完全版サンプルは、NetBeansサンプル・カタログからダウンロードできます。

このチュートリアルのレッスン

このページの内容は、NetBeans IDE 7.2、7.3および7.4に適用されます
  1. 概要
  2. Webサービスの作成
  3. Webサービスのコーディングおよびテスト
  4. バイナリ・データを渡すためのスキーマとWSDLファイルの変更
  5. => Swingクライアントの作成

このレッスンの目次

  1. クライアント・アプリケーションの作成

  2. JFrameのデザイン
  3. JFrameコンポーネントのバインディング

  4. メイン・クラスのコーディング

クライアント・アプリケーションの作成

この項では、Webアプリケーションを作成します。このアプリケーション内で、前のチュートリアルで作成および変更したWebサービスを使用するクライアントを作成します。

クライアント・アプリケーションを作成するには:

  1. 「ファイル」>「新規プロジェクト」(LinuxおよびWindowsでは[Ctrl]-[Shift]-[N]、MacOSでは[⌘]-[Shift]-[N])を選択します。新規プロジェクト・ウィザードが表示されます。
  2. 「Java」カテゴリから「Javaアプリケーション」を選択します。「次」をクリックします。新規Javaアプリケーション・ウィザードが表示されます。「プロジェクト名」に「FlowerClient」と入力します。プロジェクトの場所を選択し、「終了」をクリックします。IDEにより新しいJavaアプリケーション・プロジェクトが作成されます。
  3. FlowerClient」プロジェクト・ノードを右クリックし、コンテキスト・メニューから「新規」>「Webサービス・クライアント」を選択します。新規Webサービス・クライアント・ウィザードが開きます。
  4. 「WSDL URL」ラジオ・ボタンを選択し、WSDLファイルのURLをそのフィールドに貼り付けます。デフォルトでは、URLはhttp://localhost:8080/FlowerAlbumService/FlowerServiceService?wsdlです。ブラウザでURLを見つけるには、Webサービスをテストし、URLの末尾を?Testerから?wsdlに置き換えます。空のパッケージ名を含め、他のデフォルト値をすべて受け入れます。
    WSDLのURLが表示されたWebサービス・クライアント・ウィザード
  5. 「終了」をクリックします。IDEによりWSDLファイルがダウンロードされ、Webサービスと対話するためのクライアント・スタブが追加され、Javaアプリケーション・プロジェクトの「プロジェクト」ウィンドウにノードが追加されます。
    新しいWebサービス・クライアントが表示された「プロジェクト」ビュー

JFrameフォームのデザイン

この項では、JFrameをWebアプリケーションに追加し、Swingコンポーネントを使用してJFrame内にGUIインタフェースをデザインします。最後に、SwingコンポーネントをWebサービス・クライアント・コードにバインドします。

自分でJFrameフォームをデザインしない場合は、すでにデザインされたJFrame Javaファイルをここからダウンロードできます。

  1. FlowerClient」ノードを右クリックし、「新規」>「JFrameフォーム」を選択します。フレームに「FlowerFrame」という名前を付けます。このフレームをflowerclientパッケージに配置します。
  2. FlowerFrameがエディタに表示されます。パレットが開かれていない場合は、パレットを開きます。フレームの下部の境界線をおよそ3分の1まで拡げます。
    エディタの「デザイン」ビューにFlowerフォームが表示され、パレットも開いた状態
  3. パレットの「Swingコンテナ」セクションからJPanelをFlowerFrameにドラッグします。FlowerFrame全体を埋めるように拡げます。
    FlowerFrameでJPanelを追加して拡張した状態
  4. 「デザイン」ビューでこのパネルを右クリックします。コンテキスト・メニューから「変数名を変更...」を選択します。パネルに「gardenFlowersPanel」という名前を付けます。
  5. パレットからJLabelをgardenFlowersPanelの上にドラッグします。ラベルを右クリックし、ラベルの変数名をtitleLabelに変更します。「titleLabel」を再度右クリックし、「テキストを編集」を選択します。テキストを「Garden Flowers」に変更します。必要に応じて、titleLabelのプロパティを表示して、目立つフォントに変更します。
  6. 「ボタン・グループ」を「デザイン」ビューにドラッグします。ボタン・グループの変数名はデフォルトのbuttonGroup1のままにします。
  7. 4つの「ラジオ・ボタン」を、titleLabelの真下に横一列に並ぶようにドラッグします。各ボタンのプロパティで、buttonGroup1のメンバーとして設定します。これらのボタンの他のプロパティは、次のとおりです。
    buttonGroup1のラジオ・ボタン
    変数名 選択状態 テキスト
    asterRadioButton true Aster
    honeysuckleRadioButton false Honeysuckle
    roseRadioButton false Rose
    sunflowerRadioButton false Sunflower
  8. 「スクロール・ペイン」をラジオ・ボタンの下にドラッグします。横のスペースのすべて、および縦のスペースのおよそ3分の2を埋めるようにスクロール・ペインを拡げます。スクロール・ペインの変数名をmainScrollPaneに変更します。
  9. 「パネル」をmainScrollPaneにドラッグします。パネルの変数名をmainPanelに変更します。
  10. 「デザイン」ビューでmainPanelを右クリックし、「レイアウトを設定」>「境界線レイアウト」を選択します。
  11. 「ボタン」をmainPanelにドラッグします。mainPanelに境界線レイアウトが設定されているため、ボタンはパネル全体を埋めるように自動的に拡げられます。ボタンの変数名をmainPictureButtonに、ボタンのテキストを「Waiting for picture...」に変更します。
  12. もう1つの「スクロール・ペイン」をmainScrollPaneの下のスペースにドラッグします。残りの全スペースを埋めるように、このスクロール・ペインを拡げます。新しいスクロール・ペインの変数名をthumbnailScrollPaneに変更します。
  13. 「パネル」をthumbnailScrollPaneにドラッグします。このパネルの変数名をthumbnailPanelに変更します。thumbnailPanelのレイアウトを「グリッド・レイアウト」に設定します。
  14. 4つの「ボタン」をthumbnailPanelにドラッグします。thumbnailPanelにグリッド・レイアウトが設定されているため、すべてのボタンが自動的に同じサイズになり、パネル全体を埋めるように拡げられます。これらのボタンのプロパティは、次のとおりです。 thumbnailPanelのボタン
    変数名 テキスト
    asterButton 待機中...
    honeysuckleButton 待機中...
    roseButton 待機中
    sunflowerButton 待機中...

これでJFrameフォームのデザインは完成です。この段階で、FlowerFrameは次のように表示されます。
イメージのかわりにボタンのテキストが表示された、完成したFlowerFrame

JFrameコンポーネントのバインディング

この項では、コンストラクタでコンポーネントを初期化し、そのコンポーネントをリスナーにバインドします。リスナーは、花のイメージを表示するコードをコールします。

コンポーネントの初期化

この項では、FlowerFrameコンストラクタを記述します。

  1. エディタの「ソース」ビューに変更します。FlowerFrameクラス本文の先頭とFlowerFrameコンストラクタを探します。
    空のFlowerFormコンストラクタが表示された、エディタの「ソース」ビュー
  2. コンストラクタの前にあるFlowerFrameのクラス本文の先頭に、すべての花の名前の文字列配列を作成します。
    protected static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
  3. FLOWERS文字列配列とコンストラクタの間に、flowersという名前のjava.util.Mapを初期化する行を追加します。このマップはStringを取ってImageにマップします。
    private Map<String, Image> flowers;
  4. java.util.Mapjava.awt.Imageのインポート文を追加します。
  5. flowersマップの特定のインスタンスで特定のImageを特定のStringに関連付けるコードを、FlowerFrameコンストラクタに追加します。
    public FlowerFrame(Map<String, Image> flowers) {
    
        this.flowers = flowers;
        for (String flower:FLOWERS) {
            flowers.put(flower,null);
        }
    
        initComponents();    
    } 
  6. ラジオ・ボタン用のItemListenerと4つの花のボタン用のActionListenerを初期化し、デフォルトのタイトルを設定します。
    public FlowerFrame(Map<String, Image> flowers) {
    
        this.flowers = flowers;
        for (String flower:FLOWERS) {
            flowers.put(flower,null);
        }
    
        initComponents(); 
        
        setTitle("Garden Flowers [waiting for picture]");
        
        ItemListener rbListener = new RBListener();
        asterRadioButton.addItemListener(rbListener);
        honeysuckleRadioButton.addItemListener(rbListener);
        roseRadioButton.addItemListener(rbListener);
        sunflowerRadioButton.addItemListener(rbListener);
        
        ActionListener bListener = new ButtonListener();
        asterButton.addActionListener(bListener);
        honeysuckleButton.addActionListener(bListener);
        roseButton.addActionListener(bListener);
        sunflowerButton.addActionListener(bListener);
    }
  7. java.awt.event.ItemListenerjava.awt.event.ActionListenerのインポート文を追加します。

これでコンストラクタは完成しました。ただし、コードにRBListenerクラスとButtonListenerクラスが含まれていないため、コンパイル・エラーの警告が表示されます。この2つのクラスは、それぞれItemListenerActionListenerのカスタム実装です。この2つのクラスの記述は、次の項で行います。

花の表示

この項では、ラジオ・ボタンと花のボタンのカスタム・リスナーを記述します。また、ボタンによって選択された花を判断し、その花のImageflowersマップから取得するメソッドを記述します。最後に、Mainクラスによってコールされ、各サムネイルのImageを取得するメソッドを記述します。

  1. FlowerFrameのクラス本文でpublic static void main(String args[])メソッドを探します。このメソッドとそのドキュメントを削除します。このアプリケーションでは、かわりにMainクラスを使用します。
  2. mainメソッドのかわりに、カスタムItemListenerをラジオ・ボタン用に記述します。このリスナーは、ラジオ・ボタンが選択されたときに新しい花のイメージを表示します。
    private class RBListener implements ItemListener {
        public void itemStateChanged(ItemEvent e) {
            showFlower();
        }
    }
  3. java.awt.event.ItemEventのインポート文を追加します。
  4. カスタムItemListenerの下に、カスタムActionListenerを4つの花のボタン用に記述します。ボタンがクリックされると、リスナーは関連するラジオ・ボタンを選択します。
    private class ButtonListener implements ActionListener {
    
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == asterButton) asterRadioButton.setSelected(true);
            else if (e.getSource() == honeysuckleButton) honeysuckleRadioButton.setSelected(true);
            else if (e.getSource() == roseButton) roseRadioButton.setSelected(true);
            else if (e.getSource() == sunflowerButton) sunflowerRadioButton.setSelected(true);
        }
    }
  5. java.awt.event.ActionEventのインポート文を追加します。
  6. カスタムActionListenerの下にshowFlowerメソッドを記述します。このメソッドは、選択されているラジオ・ボタンを判断し、対応する花のImageflowersマップから取得します。
    void showFlower() {
        Image img = null;
        if (asterRadioButton.isSelected()) {
            img = flowers.get("aster");
            if (img != null) {
                mainPictureButton.setIcon(new ImageIcon(img));
                setTitle("Garden Flowers [Aster]");
            }
        } else if (honeysuckleRadioButton.isSelected()) {
            img = flowers.get("honeysuckle");
            if (img != null) {
                mainPictureButton.setIcon(new ImageIcon(img));
                setTitle("Garden Flowers [Honeysuckle]");
            }
    
        } else if (roseRadioButton.isSelected()) {
            img = flowers.get("rose");
            if (img != null) {
                mainPictureButton.setIcon(new ImageIcon(img));
                setTitle("Garden Flowers [Rose]");
            }
        } else if (sunflowerRadioButton.isSelected()) {
            img = flowers.get("sunflower");
            if (img != null) {
                mainPictureButton.setIcon(new ImageIcon(img));
                setTitle("Garden Flowers [Sunflower]");
            }
        }
        if (img == null) {
            mainPictureButton.setIcon(null);
            setTitle("Garden Flowers [waiting for picture]");            
        } else mainPictureButton.setText("");
    }
  7. javax.swing.ImageIconのインポート文を追加します。
  8. setThumbnailsメソッドを記述します。このメソッドは、各サムネイルのイメージをflowersマップから取得します。Mainクラスがこのメソッドをコールします。
    void setThumbnails(Map<String, Image> thumbs) {
        Image img = thumbs.get("aster");
        if (img != null) {
            asterButton.setIcon(new ImageIcon(img));
            asterButton.setText("");
        }
        img = thumbs.get("honeysuckle");
        if (img != null) {
            honeysuckleButton.setIcon(new ImageIcon(img));
            honeysuckleButton.setText("");
        }
        img = thumbs.get("rose");
        if (img != null) {
            roseButton.setIcon(new ImageIcon(img));
            roseButton.setText("");
        }
        img = thumbs.get("sunflower");
        if (img != null) {
            sunflowerButton.setIcon(new ImageIcon(img));
            sunflowerButton.setText("");
        }
    }
  9. FlowerFrameのコードに貼り付けたときにインポートを修正していない場合は、インポートを修正します。エディタで右クリックし、コンテキスト・メニューから「インポートを修正」を選択すると、すべてのインポートを一度に修正できます。完成した一連のインポート文は次のようになります。
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.util.Map;
    import javax.swing.ImageIcon;

これでFlowerFrameは完成しました。

メイン・クラスのコーディング

この項では、Mainクラスを完成させ、FlowerFrameの表示、Webサービスへの接続、およびWebサービスの操作のコールを実行できるようにします。

  1. Main.javaクラスをエディタで開きます。
    空のMainクラス
  2. クラス本文のmainメソッドの前で、ダウンロードした写真の数を示すint変数を初期化します。
     private static int downloadedPictures;
  3. mainメソッドの本文で、4つの花用のHashMapと、4つのサムネイル用に別のHashMapを作成します。
    final Map<String,Image> flowers = new HashMap<String,Image>(4);
    final Map<String,Image> thumbs = new HashMap<String,Image>(4);
  4. java.awt.Imagejava.util.Mapおよびjava.util.HashMapのインポート文を追加します。
  5. mainメソッドの本文で、FlowerFrameを表示するコードを追加します。
    // Show the FlowerFrame.
    final FlowerFrame frame = new FlowerFrame(flowers);
    frame.setVisible(true);  
  6. mainメソッドの本文で、クライアントをサービスに接続するコードを追加します。
    // The client connects to the service with this code.
    FlowerServiceService service = new FlowerServiceService();
    final FlowerService port = service.getFlowerServicePort();
  7. org.flower.service.FlowerServiceorg.flower.service.FlowerServiceServiceのインポート文を追加します。
  8. mainメソッドの本文で、4つのRunnableスレッドの配列を作成し、WebサービスのgetFlower操作をスレッドごとに一度コールするコードを追加します。
    // The web service getFlower operation
    // is called 4 times, each in a separate thread.
    // When the operation finishes the picture is shown in
    // a specific button.
    Runnable[] tasks = new Runnable[4];
    
    for (int i=0; i<4;i++) {
        final int index = i;
        tasks[i] = new Runnable() {
            public void run() {
                try {
                
                    // Call the getFlower operation
                    // on the web service:
                    Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
                    System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
                         
                    // Add strings to the hashmap:
                    flowers.put(FlowerFrame.FLOWERS[index],img);
                            
                    // Call the showFlower operation
                    // on the FlowerFrame:
                    frame.showFlower();
                            
                } catch (IOException_Exception ex) {
                    ex.printStackTrace();
                }
                downloadedPictures++;
            }
        };
        new Thread(tasks[i]).start();
    }
  9. org.flower.service.IOException_Exceptionのインポート文を追加します。
  10. themainメソッドの本文で、WebサービスのgetThumbnails操作を別スレッドでコールするコードを追加します。
    // The web service getThumbnails operation is called
    // in a separate thread, just after the previous four threads finish.
    // When the images are downloaded, the thumbnails are shown at 
    // the bottom of the frame.
    Runnable thumbsTask = new Runnable() {
        public void run() {
            try {
                while (downloadedPictures < 4) {                        
                    try {Thread.sleep(100);} catch (InterruptedException ex) {}
                }
                     
                // Call the getThumbnails operation
                // on the web service:
                List<Image> images = port.getThumbnails();
                System.out.println("thumbs downloaded");
                        
                if (images != null && images.size() == 4) {
                    for (int i=0;i<4;i++) {
                        thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
                    }
                    frame.setThumbnails(thumbs);
                }
            } catch (IOException_Exception ex) {
                ex.printStackTrace();
            }
        }            
    };
    new Thread(thumbsTask).start();
    
  11. Main.javaのコードに貼り付けたときにインポートを修正していない場合は、インポートを修正します。エディタで右クリックし、コンテキスト・メニューから「インポートを修正」を選択すると、すべてのインポートを一度に修正できます。インポートするListクラスの選択肢が表示されたら、「java.util.List」を選択します。完成した一連のインポート文は次のようになります。
    import flower.album.FlowerService;
    import flower.album.FlowerService_Service;
    import flower.album.IOException_Exception;
    import java.awt.Image;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

これでMainクラスは完成しました。

public class Main {

     private static int downloadedPictures;
    
     public static void main(String[] args) {
    
        final Map<String,Image> flowers = new HashMap<String,Image>(4);
        final Map<String,Image> thumbs = new HashMap<String,Image>(4);
        
        // Show the FlowerFrame.
        final FlowerFrame frame = new FlowerFrame(flowers);
        frame.setVisible(true);
        
// The client connects to the service with this code. FlowerService_Service service = new FlowerService_Service(); final FlowerService port = service.getFlowerServicePort(); Runnable[] tasks = new Runnable[4]; // The web service getFlower operation // is called 4 times, each in a separate thread. // When the operation finishes the picture is shown in // a specific button. for (int i=0; i<4;i++) { final int index = i; tasks[i] = new Runnable() { public void run() { try { // Call the getFlower operation // on the web service: Image img = port.getFlower(FlowerFrame.FLOWERS[index]); System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]); // Add strings to the hashmap: flowers.put(FlowerFrame.FLOWERS[index],img); // Call the showFlower operation // on the FlowerFrame: frame.showFlower(); } catch (IOException_Exception ex) { ex.printStackTrace(); } downloadedPictures++; } }; new Thread(tasks[i]).start(); } // The web service getThumbnails operation is called // in a separate thread, just after the previous four threads finish. // When the images are downloaded, the thumbnails are shown at // the bottom of the frame. Runnable thumbsTask = new Runnable() { public void run() { try { while (downloadedPictures < 4) { try {Thread.sleep(100);} catch (InterruptedException ex) {} } // Call the getThumbnails operation // on the web service: List<Image> images = port.getThumbnails(); System.out.println("thumbs downloaded"); if (images != null && images.size() == 4) { for (int i=0;i<4;i++) { thumbs.put(FlowerFrame.FLOWERS[i],images.get(i)); } frame.setThumbnails(thumbs); } } catch (IOException_Exception ex) { ex.printStackTrace(); } } }; new Thread(thumbsTask).start(); } }

これでクライアント・アプリケーションは完了です。EJBモジュールに委譲してそのイメージを公開するWebサービスと対話するコードを作成しました。クライアントを右クリックし、「実行」を選択します。Swingアプリケーションが起動し、しばらくするとWebサービスから受信されるイメージが表示されます。表示されないイメージがある場合は、FlowerServiceプロジェクトを消去およびビルドしてから、再度実行します。メイン・フレームに表示されるイメージは、ラジオ・ボタンを選択するか、サムネイルをクリックすることによって変更できることに注意してください。

メーリング・リストに登録することによって、NetBeans IDE Java EE開発機能に関するご意見やご提案を送信したり、サポートを受けたり、最新の開発情報を入手したりできます。

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo