サーバーとの通信
第5回 RemoteObject を利用する(2)

RemoteObject - 型変換と結果ハンドラー

RemoteObject タグを使ってユーザー定義クラスで情報を交換する方法と結果ハンドラーについて見ていきます。

 


この章のはじめに

今回は、住所録アプリケーションを段階的に作っていきます。この作成の過程を通してさらに詳しく RemoteObject の使い方を見ていきたいと思います。

この章ではFlex アプリケーションから呼び出されるJava クラスがいくつか登場してきます。これらの Java クラスについて、ソースコードと、コンパイル済みクラスファイルを、アーカイブ化して次に用意しました。 利用するには ZIP 解凍ツールでファイルを解凍、中にある MyFirstRo.jar ファイルを WEB-INF\lib ディレクトリの下に保存します。

MyFirstRo.zip (展開して中にある MyFirstRo.jar を WEB-INF\lib の中にコピーします。)

データの送り方、結果の受け取り方(型変換とレスポンス処理)

名前一覧を表示する (result イベント、データ型の変換ルール)

サーバーから取得した情報をもとに名前一覧を表示するアプリケーションを作ってみます。 まず名前一覧を追加/閲覧する Java クラスを次のように定義します。

 Java クラス myfirst.MyAddressBookManager

package myfirst;

import java.util.ArrayList;

public class MyAddressBookManager {

  private static ArrayList list = null;

  public MyAddressBookManager() {
    if (list == null) {
      list = new ArrayList();
      list.add("鈴木 一郎");
      list.add("本田 太郎");
      list.add("川崎 俊介");
    }
  }

  public ArrayList getList() {
						
    return list;
  }

  public void addList(String newList) {
    list.add(newList);
  }
}

これは名前リストを管理する Java クラスです。 getList メソッドを呼び出すことで管理されている名前リストが取得されます。 また addList メソッドを呼び出し、文字列を引数に渡すことで、名前リストを追加することができます。

次はこの Java クラスを利用する Flex アプリケーションです。

 Flex アプリケーション MyAddressBook1.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script>
<![CDATA[
  private function showResult(event) {
    datagrid1.dataProvider = event.result;
  }
]]>
</mx:Script>
  <mx:RemoteObject id="myRo" source="myfirst.MyAddressBookManager" 
               type="stateful-class" result="showResult(event)"/>

  <mx:Button label="get address book" click="myRo.getList()"/>
  <mx:List id="datagrid1" />
</mx:Application> 

次はこのアプリケーションを実行したときの画面です。

このアプリケーションではいくつかの新しい機能を使っています。

  • result イベントを使っています。 result イベントは RemoteObject がリモート処理の結果を取得したときに発生します。 このときイベントオブジェクトの result プロパティーにはリモートメソッドの処理結果が収められています。
  • getList メソッドは ArrayList のクラスオブジェクトを返します。 ArrayList クラスオブジェクトは Flex アプリケーションが受け取ったときは Array 型で処理されます。

Flex アプリケーションは Action Script をベースに動いています、それに対して RemoteObject を介してサーバー側で処理されるプログラムは Java 言語です。 それぞれのプログラミング言語の間の型変換には一定のルールがあります。 ActionScript の Array 型は Java 言語では java.util.ArrayList 型などに変換されます。 ActionScript の Number 型は Java では double 型などで扱われます。 変換ルールについて詳細は次のドキュメントに紹介されています。

http://livedocs.macromedia.com/flex/15/flex_docs_en/00002246.htm

名前を追加する機能を加える(リモートメソッドごとにハンドラーを振り分ける <mx:method> タグ)

さて、次に名前リストに名前情報を追加する機能を加えたいと思います。 次のように処理を加えます。

  • 名前を入力するテキスト入力エリアを加えます。
  • ボタンを追加します。ボタンが押されると、テキスト入力エリアの情報を addList メソッドでサーバーに送ります。
  • addList が成功すると、getList を再び呼び出し、最新の名前リストを取得します。

一見これまでの知識ですべての機能が実現できそうなのですが、一つ厄介なものがあります。「addList が成功すると、getList を再び呼び出し、最新の名前リストを取得します」です。 addList が終了した結果を受け、result イベントハンドラーを使って最新のリストを取得するというアイデアが思い浮かびます。しかし、 result イベントハンドラーはすでに getList メソッドの結果処理のために使用しています。RemoteObject では複数のリモートメソッドにアクセスできるのですが、結果ハンドラーは一つしかないのです。この問題を解決するために RemoteObject タグには、このタグの中だけで有効なチャイルド・タグ <mx:method> があります。このタグを使って、各リモートメソッドに専用のイベントハンドラーを設定することができます。

次は名前情報の追加機能を組み込んだサンプルプログラムです。 <mx:method> タグを使って getList、addList それぞれに別々のイベントハンドラーを定義する例がここにあります。

 Flex アプリケーション MyAddressBook2.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script>
<![CDATA[
  private function showResult(event) {
    datagrid1.dataProvider = event.result;
  }

  private function addListDone(event) {
    myRo.getList();
  }

]]>
</mx:Script>
  <mx:RemoteObject 
          id="myRo" source="myfirst.MyAddressBookManager" type="stateful-class" >
     <mx:method name="getList" result="showResult(event)"/>
     <mx:method name="addList" result="addListDone(event)"/>
  </mx:RemoteObject>	 
  <mx:Button label="get address book" click="myRo.getList()"/>
  <mx:List id="datagrid1" />
  <mx:HBox>
    <mx:TextInput id="newAddress" />
    <mx:Button label="Add" click="myRo.addList(newAddress.text)" />
  </mx:HBox>
</mx:Application>

実行結果

( 更新したリストは他のブラウザーや他のクライアントでも閲覧することができます。 これはJava クラスの中でリストを管理している変数が static で定義されているからです。 static で定義された変数は一つの JVM の中で一つだけ作られます。ですから各クライアント用に MyAddressBookManager クラスオブジェクトが作られても、同じリスト情報が参照されるのです)

ユーザー定義クラスでサーバーと通信する

ユーザー定義クラスを用いて、クライアントサーバー間で通信を行いたい場合があります。例えば今回の例のように住所録アプリケーションを作りたいとするならば、一人分の住所録データをユーザー定義クラスとして作成し、これをクライアント、サーバー間で交換するようにすればアプリケーションの構造は非常にシンプルになり、かつ論理的に整理されたものになります。ユーザー定義クラスをクライアント/サーバー間で交換する場合の基本的な方法は次の手順を行います

  1. ユーザ定義クラスは java.io.Serializable インターフェースを実装した Java クラスとして定義する。(Java側)
  2. ユーザー定義クラスで交換されるデータ項目を setXxx、getXxx メソッドで実装する (Java側)
  3. Java クラスに対応する ActionScript クラスを定義する。(Flex 側)
  4. 定義した ActionScript には setXxx, getXxx に相当するパブリック・プロパティーと _remoteClass というパブリック・プロパティーを定義する。 _remoteClass にはこの ActionScript クラスに対応づく Java クラスの名前を完全修飾クラス名で代入するようにする。

これを踏まえて住所録アプリケーションを改良したいと思います。 一人分の住所録を Person という Java クラスが保有するようにし、Flex では Person のリストを DataGrid で表示するようにします。 また Person 情報をサーバーに送り一人分の住所情報が追加できるようにします。

まず、クライアント/サーバー間での情報交換に使われる Person クラスの Java 側の実装について確認しましょう。 ポイントは 「1.java.io.Serializable インターフェースを実装していること、2.交換されるデータが setXxx、getXxx で定義されていること」、の2点です。

 一人分の住所情報 Java 側 - myfirst.Person クラス

package myfirst;

import java.io.Serializable;

public class Person implements Serializable {

    private String name;
    private String phone;
    private String email;

    public Person() {

    }

    public Person(String name, String phone, String email) {

        this.name=name;
        this.phone=phone;
        this.email=email;

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

 (住所録といいながら肝心の住所 (Address ) プロパティーを持っていないのですが、、、 E-mail アドレスの住所録とご理解いただければと、、)

このクラスを使って Flex アプリケーションと情報を交換する Java 側のプログラムを次のように定義しました。

 Person クラスを使って Flex アプリケーションと情報交換をする、Javaクラス - myfirst.MyAddressBookManager

package myfirst;

import java.util.ArrayList;

public class MyAddressBookManager2 {

   private static ArrayList list = null;

   public MyAddressBookManager2() {
      Person aPerson;

      if (list == null) {
         list = new ArrayList();
         list.add(new Person("鈴木 一郎","03-1234-1234", "suzuki@myflex.com"));
         list.add(new Person("本田 太郎","03-2222-3333", "honda@myflex.com"));
         list.add(new Person("川崎 俊介","03-4444-5555", "kawasaki@myflex.com"));
      }
   }

   public ArrayList getList() {						
      return list;
   }

   public void addList(Person newPerson) {
      list.add(newPerson);
   }
}

次に Flex 側です。まず Java クラス myfirst.Person に対応する ActionScript クラスを定義します。 ここでポイントは、「Javaクラスの setXxx, getXxx に相当するパブリックプロパティーと _remoteClass というプロパティーを定義する。 _remoteClass にはこの ActionScript クラスに対応づく Java クラスの名前を完全修飾クラス名で代入するようにする。」 です。これに従うと次のようになります。

 Java クラス myfirst.Person に対応づく ActionScript クラス Person.as

class Person {
	
   public var name:String;
   public var phone:String;
   public var email:String;
   public var _remoteClass;
	
   public function Person(aName, aPhone, aEmail) {
      _remoteClass = "myfirst.Person";
		
      name = aName;
      phone = aPhone;
      email = aEmail;
		
   }
}

 サーバーにある myfirst.MyAddressBookManager2 にアクセスし、Person.as を使ってサーバーと情報交換をする Flex アプリケーションは次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script>
<![CDATA[

   private function showResult(event) {
      datagrid1.dataProvider = event.result;
   }

   private function addList() {
      var aPerson:Person = new Person(newName.text, newPhone.text, newEmail.text);
      myRo.addList(aPerson);
   }
	
   private function addListDone(event) {
      myRo.getList();
   }

]]>
</mx:Script>
   <mx:RemoteObject id="myRo" 
          source="myfirst.MyAddressBookManager2" type="stateful-class" >
      <mx:method name="getList" result="showResult(event)"/>
      <mx:method name="addList" result="addListDone(event)"/>
   </mx:RemoteObject>	 
   <mx:Button label="get address book" click="myRo.getList()"/>
   <mx:DataGrid id="datagrid1">
      <mx:columns>
         <mx:Array>
            <mx:DataGridColumn headerText="Name" columnName="name" />
            <mx:DataGridColumn headerText="Phone" columnName="phone" />
            <mx:DataGridColumn headerText="E-Mail" columnName="email" />
         </mx:Array>
      </mx:columns>
   </mx:DataGrid>
   <mx:VBox horizontalAlign="left"  width="{datagrid1.width}"  >
      <mx:Label text="Name" />
      <mx:TextInput id="newName" />
      <mx:Label text="Phone" />
      <mx:TextInput id="newPhone" />
      <mx:Label text="E-mail" />
      <mx:TextInput id="newEmail" />
      <mx:Button label="Add" click="addList()" />
   </mx:VBox>
</mx:Application>

実行結果

続く


ご意見・ご感想

技術レポート一覧へ

トップページ


作成日:2005年4月4日
更新日:2005年4月4日