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を使ってサーバー側のサービスを呼び出しています。

EclipseとMavenでGWTアプリケーションを作成する:04 簡単なアプリケーションを作成する

環境など

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

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

アプリケーションの作成

前回のコードを土台として、簡単なアプリケーションを作成して動かしてみます。

1. Eclipseのプロジェクト・エクスプローラーからApplication.java (src/main/java/jp/ne/hatena/paz3/GwtSample/client/Application.java) をダブルクリックし、エディタで開きます。

2. コードを次のように変更します。

Application.java

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

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Application
    implements EntryPoint
{

	private Label nameLabel;
	private TextBox nameTextBox;
	private Button greetButton;
	private HorizontalPanel horizontalPanel;
	private Label messageLabel;
	private VerticalPanel verticalPanel;

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad()
	{
		// Make input area.
		nameLabel = new Label("Name");
		nameTextBox = new TextBox();
		greetButton = new Button("Hi !");
		horizontalPanel = new HorizontalPanel();
		horizontalPanel.add(nameLabel);
		horizontalPanel.add(nameTextBox);
		horizontalPanel.add(greetButton);
		
		// Make output area.
		messageLabel = new Label();
		
		// Combine two areas vertically.
		verticalPanel = new VerticalPanel();
		verticalPanel.add(horizontalPanel);
		verticalPanel.add(messageLabel);
		
		// Add panel to web page.
		RootPanel.get().add(verticalPanel);
		
		// Listen for click event on greetButton.
		greetButton.addClickHandler(new ClickHandler() {
			
			public void onClick(ClickEvent event) {
				showGreetingMessage();
			}
			
		});
	}
	
	private void showGreetingMessage() {
		String name = nameTextBox.getText();
		String message = "Hello " + name + " !";
		messageLabel.setText(message);
	}
	
}

3. 保存します。

アプリケーションの実行

前回の手順 で実行してください。実行すると、「Name」と書かれたテキストボックスが表示されます。

テキストボックスに名前を入れて「Hi !」をクリックすると、その下にメッセージが表示されます。

日本語も使用できます。

コードの解説

画面レイアウト

今回作成した画面は次のようになっています。

horizontalPanelはコンポーネントを横方向に並べるパネルです。horizontalPanelの上にnameLabel(「Name」と書かれたラベル)、nameTextBox(名前を入れるテキストボックス)、greetButton(「Hi !」と書かれたボタン)が横方向に並んで乗っています。

verticalPanelはコンポーネントを縦方向に並べるパネルです。verticalPanelの上にhorizontalPanelとmessageTextBox(メッセージを表示するテキストボックス)が縦方向に並んで乗っています。

コンポーネントを配置する

GWTのアプリケーションでは、ページを表示したときにonMouseLoadが実行されます。

onMouseLoadの中では、次のコードでnameLabel、nameTextBox、greetButtonを作成し、horizontalPanelのaddメソッドで配置しています。

// Make input area.
nameLabel = new Label("Name");
nameTextBox = new TextBox();
greetButton = new Button("Hi !");
horizontalPanel = new HorizontalPanel();
horizontalPanel.add(nameLabel);
horizontalPanel.add(nameTextBox);
horizontalPanel.add(greetButton);

次のコードでmessageLabelを作成し、horizontalPanelと共にverticalPanelのaddメソッドで配置しています。

// Make output area.
messageLabel = new Label();

// Combine two areas vertically.
verticalPanel = new VerticalPanel();
verticalPanel.add(horizontalPanel);
verticalPanel.add(messageLabel);

次のコードでverticalPanelをWebページに追加しています。RootPanelはWebページ内でコンポーネントを配置できる場所を表すクラスで、getメソッドで実際の場所を取得します。画面に表示するコンポーネントは必ずRootPanelのaddメソッドで画面に配置する必要があります。

// Add panel to web page.
RootPanel.get().add(verticalPanel);
ボタンクリック時の処理

次はgreetButtonをクリックしたときの処理です。

// Listen for click event on greetButton.
greetButton.addClickHandler(new ClickHandler() {
	
	public void onClick(ClickEvent event) {
		showGreetingMessage();
	}
	
});

ボタンをクリックしたときの処理は、ButtonクラスのaddClickHandlerで登録します。addClickHandlerメソッドの引数として、ClickHandlerインターフェイスを実装した無名クラスのインスタンスを作成(new ClickHandler() {…})して渡しています。

ClickHandlerインターフェイスにはonClickメソッドがあります。ここにクリック時の処理を記述します。ここではshowGreetingMessageメソッドを呼び出しています。

showGreetingMessageメソッドは、messageLabelに「Hello 名前 !」という文字列を設定するメソッドです。

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

EclipseとMavenでGWTアプリケーションを作成する:03 実行、コンパイル、Webアーカイブ化

環境など

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

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

実行する

gwt-mavenプラグインで作成したプロジェクトには、そのまま実行できるアプリケーションが含まれています。次の手順で実行します。

実行構成に登録する

1. Eclipseのプロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->実行の構成 をクリックします。

2. 「実行構成」ダイアログが表示されます。

3. 「Maven build」を右クリックし、表示されたメニューから「新規」をクリックします。

4. 名前に「GWT run」と入力します。「変数」ボタンをクリックします。

5. 「変数の選択」ダイアログが表示されます。「project loc」を選択して「OK」をクリックします。

6. ゴールに「gwt:run」と入力し、「適用」をクリックし、「閉じる」をクリックします。

これで実行構成に登録されました。実行構成への登録は1度だけやれば大丈夫です。

実行する

1. プロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->Maven build をクリックします。「構成の選択」ダイアログが表示された場合には「GWT run」を選択します。

2. 少し時間がかかった後、「GWT Development Mode」というウィンドウが表示されます。「Launch Default Browser」をクリックします。

3. 通常使っているブラウザが起動し、「gwt-maven-plugin Archetype :: Project org.codehaus.mojo.gwt-maven-plugin」という文字列が表示されます。

この文字列はApplication.javaに記述されているものなので、これが表示されたら無事に実行できています。

Application.java(抜粋):

public void onModuleLoad()
{
   final Label label = new Label ( "gwt-maven-plugin Archetype :: Project org.codehaus.mojo.gwt-maven-plugin" );
   RootPanel.get().add( label );
}

実行後は「GWT Development Mode」ウィンドウを閉じておいてください。

GWT Development Mode」は、GWTのホストモードというもので実行されています。ホストモードはJavaで書かれたクライアント側コードをJavaScriptに変換しないで実行するモードで、JavaScriptファイルは生成されません。その代わりにJavaのclassファイルが作成されています。実行に必要なファイルはGwtSample/war以下に生成されます。

コンパイルする

アプリケーションをWebサーバー上に配置する場合には、JavaScriptファイルを生成する必要があります。JavaScriptファイルを生成するには以下の手順でコンパイルをします。

実行構成に登録する

1. Eclipseのプロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->実行の構成 をクリックします。

2. 「実行構成」ダイアログが表示されます。

3. 「Maven build」を右クリックし、表示されたメニューから「新規」をクリックします。

4. 名前に「GWT compile」と入力します。「変数」ボタンをクリックします。

5. 「変数の選択」ダイアログが表示されます。「project loc」を選択して「OK」をクリックします。

6. ゴールに「gwt:compile」と入力し、「適用」をクリックし、「閉じる」をクリックします。

これで実行構成に登録されました。実行構成への登録は1度だけやれば大丈夫です。

コンパイルする

1. プロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->Maven build をクリックします。「構成の選択」ダイアログが表示された場合には「GWT compile」を選択します。

2. しばらく時間がかかった後、GwtSample/target/GwtSample-0.0.1-SNAPSHOT/jp.ne.hatena.paz3.GwtSample.Application以下にファイルが出力されます。

プロジェクト・エクスプローラーにファイルが表示されない場合には、「target」ディレクトリをクリックし、キーボードの「F5」キーを押してリフレッシュします。

なお、「GwtSample-0.0.1-SNAPSHOT」は、プロジェクト名+バージョン名という構成になっています。これはpom.xmlで設定したArtifact IdとVersionになっています。

Webアーカイブ(war)を作成する

Webアーカイブ(war)ファイルを作成するには次のようにします。

1. プロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->Maven package をクリックします。

2. しばらく時間がかかった後、GwtSample/targetにGwtSample-0.0.1-SNAPSHOT.warというファイルが生成されます。

このファイルをサーバーに配置すれば実行することができます。


生成したファイルを削除する

生成したファイルを削除するには次のようにします。

1. プロジェクト・エクスプローラーからプロジェクト名(GwtSample)を右クリックし、表示されたメニューから 実行->Maven clean をクリックします。

2. しばらく時間がかかった後、以下のディレクトリの中身が削除されます。

  • GwtSample/target(ディレクトリごと削除)
  • GwtSample/war/WEB-INF/classes

04 簡単なアプリケーションを作成する