EclipseとMavenでGWTアプリケーションを作成する:05 サーバーと通信する

環境など

私は日本語化されたEclipseを使用しているので、英語版とはメニューや項目名が異なります。お使いの環境と異なる場合には、適宜読み替えてください。

この説明で使用しているソフトウェアのバージョンは次の通りです。

サーバーとの通信と2つのインターフェイス

Webアプリケーションではブラウザ側で処理が完結するといったことはあまりなく、多くの場合にはサーバーと接続し、何らかの情報のやり取りをします。

GWTではサーバーと通信する方法が複数用意されています。ここではリモート・プロシジャ・コール(RPC)を使ってサーバーと通信するサンプルを作成します。

前回までに作成したアプリケーションで挨拶メッセージを作成する部分をサーバー側のサービスとして独立させ、それをクライアント側から呼び出すことにします。

サービスを作成するためには2つのインターフェースが必要です。ひとつはサービス用インターフェース、もうひとつは呼び出し用インターフェースです。

サービス用インターフェースは次のような特徴を持っています。

  • サーバー上のサービスが実装するインターフェースです。
  • GWTのRemoteServiceインターフェースをextendsします。

呼び出し用インターフェースは次のような特徴を持っています。

  • クライアント側のコードがサーバー上のサービスを呼び出すときに使うインターフェースです。
  • サービス用インターフェースと同じ名前のメソッドを持ちますが、最後の引数としてAsyncCallback型を持ちます。ここでTは元のメソッドの戻り値の型です。メソッド自体の戻り値はvoidになります。
  • 慣例として、サービス用インターフェースの後ろに「Async」を付けた名前にします。

呼び出し用インターフェースが自動生成されないようにする

gwt-mavenプラグインで作成されたpom.xmlには、呼び出し用インターフェースを自動生成するための記述があります。ここではインターフェースは自分で作成しますので、以下の手順で自動生成されないようにします。

1. プロジェクト・エクスプローラーからpom.xmlをダブルクリックし、エディタで開きます。「pom.xml」タブに切り替えます。

2. gwt-maven-pluginの設定のの下にあるgenerateAsyncを削除します。

変更前

<goals>
  <goal>compile</goal>
  <goal>generateAsync</goal>
  <goal>test</goal>
</goals>

変更後

<goals>
  <goal>compile</goal>
  <goal>test</goal>
</goals>

サービス用インターフェースを作成する

次のようなインターフェースを作成します。

  • 名前はGreetingMessageService
  • clientパッケージに含める
  • RemoteServiceインターフェースをextendsする

GreetingMessageSerivce:

package jp.ne.hatena.paz3.GwtSample.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("GreetingMessageService")
public interface GreetingMessageService extends RemoteService {

	public String getGreetingMessage(String name);

}

getGreetingMessageは、引数として指定された名前を受け取り、挨拶メッセージを返すメソッドです。

@RemoteServiceRelativePathでサービスを呼び出すときのURL相対パスを指定します。

呼び出し用インターフェースを作成する

次のようなインターフェースを作成します。

  • 名前はGreetingMessageServiceAsync
  • clientパッケージに含める

GreetingMessageSerivceAsync:

package jp.ne.hatena.paz3.GwtSample.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface GreetingMessageServiceAsync {
	
	void getGreetingMessage(String name, AsyncCallback<String> callback);
	
}

サービスの実装を作成する

サービスを実装します。サービスを実装するクラスは次のようにします。

  • RemoteServiceServletをextendsする
  • サービス用インターフェースを実装する
  • serverパッケージに含める

そこで、次のようなクラスを作成します。

  • 名前はGreetingMessageServiceImpl
  • RemoteServiceServletをextendsする
  • GreetingMessageServiceインターフェースをimplementsする
  • serverパッケージに含める

GreetingMessageSerivceImpl:

package jp.ne.hatena.paz3.GwtSample.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import jp.ne.hatena.paz3.GwtSample.client.GreetingMessageService;

public class GreetingMessageServiceImpl extends RemoteServiceServlet
		implements GreetingMessageService {

	public String getGreetingMessage(String name) {
		String message = "Hello " + name + " !";
		return message;
	}

}

サービスを登録する

作成したサービスをweb.xmlに登録します。

src/main/webapp/WEB-INF/web.xmlの間に次の行を追加します。

web.xml(抜粋):

<servlet>
	<servlet-name>GreetingMessageService</servlet-name>
	<servlet-class>jp.ne.hatena.paz3.GwtSample.server.GreetingMessageServiceImpl</servlet-class>
</servlet>

<servlet-mapping>
	<servlet-name>GreetingMessageService</servlet-name>
	<url-pattern>/jp.ne.hatena.paz3.GwtSample.Application/GreetingMessageService</url-pattern>
</servlet-mapping>

呼び出し側コードを作成する

前回までで作成したApplication.javaを、サービスを呼び出すように変更します。

importに次の行を追加します。

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

showGreetingMessageメソッドを変更します。

変更前:

private void showGreetingMessage() {
	String name = nameTextBox.getText();
	String message = "Hello " + name + " !";
	messageLabel.setText(message);
}

変更後:

private void showGreetingMessage() {
	String name = nameTextBox.getText();
	
	GreetingMessageServiceAsync greetingMessageService =
		GWT.create(GreetingMessageService.class);
	
	greetingMessageService.getGreetingMessage(name, new AsyncCallback<String>() {
		
		public void onSuccess(String result) {
			messageLabel.setText(result);
		}
		
		public void onFailure(Throwable caught) {
			String message = "Error: " + caught.toString();
			messageLabel.setText(message);
		}
		
	});
}

ホストモードで実行できるようにする

ここまでの設定をして、warファイルを作成しアプリケーションサーバーに配置すれば、リモートサービスを呼び出すアプリケーションは動作します。しかし、Mavengwt:runターゲットで動作するホストモードでは実行できません。

ホストモードで実行させるには、以下の2つの設定をします。

サービスを.gwt.xmlに登録する

Application.gwt.xmlの間に次の行を追加します。

Application.gwt.xml(抜粋):

<servlet path="/GreetingMessageService" class="jp.ne.hatena.paz3.GwtSample.server.GreetingMessageServiceImpl" />
war/WEB-INF/web.xmlを作成する

war/WEB-INF/web.xmlを作成します。上記で修正したweb.xmlをwar/WEB-INFの下にコピーしても良いでしょう。

src/java/main/WEB-INF/web.xmlを読み込んでくれれば便利だと思うのですが、そうなっておらず、別々のファイルを読み込むようになっています。ファイルを分けている理由について http://mojo.codehaus.org/gwt-maven-plugin/user-guide/hosted.html には「ホストモードはテスト用であり、配備用の設定とは別にすべきである」と書かれています。

実行する

前々回の方法で実行してください。動作は前回とまったく同じになりますが、内部ではRPCを使ってサーバー側のサービスを呼び出しています。