Google Web Toolkitを使ってみた

Google Web Toolkit(GWT)をちょっと使ってみた。のでその備忘録です。
(すこし長いです)。



GWTのサイトを見ればわかるけど、このツールキットを使えば、簡単にAjaxを使える。JavaScriptとHTMLの格闘をしなくて、Javaで書けるので、Javaに慣れた人にとっては結構楽チンかもしれない。既に、色々なJavaScriptライブラリがあるので、それらを使うには、めんどくさい方法が必要になりそうだけれど。


最初の目標として、RPCを利用してサーバと通信するアプリを作ってみることにする。


まずは、GWTのサイトからパッケージ(このときVersion 1.1.0(Beta)があった)をダウンロードして展開する。いくつか、ファイルがあるけど、サンプルとかドキュメントとかツールが展開される。


Getting Started Guide に沿って、ツールの使い方のお勉強をする。Hosted ModeとWeb Modeがあって、Hosted Modeで色々確認しつつ開発をすれば良いみたいだ。そして、簡易ブラウザで動作確認も可能ということだな。


家では、Eclipseを使っているので、Eclipseで開発する場合を確認する。Creating an Application from Scratch (with Eclipse)あたりを確認すると 「プロジェクト作成」 -> 「アプリケーション作成」という流れみたい。

Windowsだとこんな風(出力先を指定してみた。オプションは、projectCreatorと引数なしで実行すれば表示される)になる。

F:\tmp\gwt-windows-1.1.0>projectCreator -eclipse TestProject -out c:\temp\TestProject
Created directory c:\temp\TestProject\src
Created directory c:\temp\TestProject\test
Created file c:\temp\TestProject\.project
Created file c:\temp\TestProject\.classpath

.projectとかEclipseのプロジェクトの雛形を作成してくれた。次にアプリケーションの雛形を作成する。

F:\tmp\gwt-windows-1.1.0>applicationCreator -eclipse TestProject -out c:\temp\Te
stProject hoge.foo.client.MyApplication
Created directory c:\temp\TestProject\src\hoge\foo
Created directory c:\temp\TestProject\src\hoge\foo\client
Created directory c:\temp\TestProject\src\hoge\foo\public
Created file c:\temp\TestProject\src\hoge\foo\MyApplication.gwt.xml
Created file c:\temp\TestProject\src\hoge\foo\public\MyApplication.html
Created file c:\temp\TestProject\src\hoge\foo\client\MyApplication.java
Created file c:\temp\TestProject\MyApplication.launch
Created file c:\temp\TestProject\MyApplication-shell.cmd
Created file c:\temp\TestProject\MyApplication-compile.cmd

これ、落としたディレクトリがf:\tmpとかになってるけど、作成された.cmdファイルとかはそのディレクトリを見るので、実際にはちゃんとした?場所に置いとくほうが良いかな。


このアプリをEclipseで使えるようにするには、EclipseのFile->Importで、出力先のディレクトリを指定してやればOK。Existing project into workspaceとかを選んでc:\temp\TestProjectを選べば、あとは自動で読み込んでくれる。Webのドキュメントの説明には、実行ボタンを押せばOKとあるのだが、何を実行するのかちょっとよくわからん。MyApplication-shell.cmd を実行すれば、コンパイルして、JVMが立ち上がって、簡易ブラウザで動作確認できるのでとりあえずは、これで良いのだろう。

確認できたので、作成された雛形を眺めてみる。大体の感じからすると、src以下にあるMyApplication.javaというのが、clientというパッケージの下にあって、こいつがJavaScriptに変換されるやつで、デフォルトでボタンのマウスクリックのイベントが登録されている。そして、別の場所にHTMLと設定ファイルがある。このデフォルトのアプリ自体は、単なるJavaScriptなので面白くない。なので、サーバと通信するやつを作ってみる。


雰囲気をつかむ為に、サンプルを探す。
Example Project から DynamicTable というやつが、RPCを使っているので、これを見てみる。すると、serverというパッケージを追加して(実際には、これじゃなくてもよさそうな感じだ)、サーバ側でサーブレットを使い、またインターフェイスを幾つか用意すれば良いみたいだ。そこから、たどって Remote Procedure Callsとかも読んでみる。

お手軽に要約すると

  • クライアント/サーバ間の呼び出しのインターフェイスの定義(MyServiceとか)
  • 非同期通信用のインターフェイスの定義(MyServiceAsyncとか)。必ず、クライアント/サーバ間の通信+Asyncという名前にしないとだめ。
  • 非同期通信用のインターフェイスは、引数の最後にAsyncCallback というのを追加。
  • さらに返り値をvoidにする(これ、Webで出てるドキュメント間違ってるみたいで、Forum検索したら、出てた。2時間ぐらい悩んだ)。
  • 実際の処理をサーバ側のサーブレットに記述する。返り値をとりあえず、Serialize可能にしとけば、そのままサーバ/クライアント間で通信できるようなので(詳細はあまり見ていない)、あとは適当に実装すればいい。GWTが通信の中身とかは面倒みてくれるので、その辺は楽そうだ。


ということで、サービスをインターフェイスで実装してみる。RemoteServiceというのがサーバと通信するためのインターフェイスを表すマーカみたいなものかな。なので、その派生として定義。

package hoge.foo.client;

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

public interface MyService extends RemoteService {
	public String echo(String s);
}

名前の付け方から、Asyncも作成。

package hoge.foo.client;

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

public interface MyServiceAsync {
	public void echo(String s, AsyncCallback callback);
}

サーバ側の実装をServletで行う。

package hoge.foo.server;

import hoge.foo.client.MyService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class MyServiceImpl extends RemoteServiceServlet
implements MyService {
	public String echo(String s) {
		return "server: " + s;
	}
}

Developer Guide > Remote Procedure Calls > Actually Making a Call

あたりを参照して、ボタンを押したらサーバと通信して文字を表示するようにしてみる。

    button.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
    	  MyServiceAsync service = (MyServiceAsync) GWT.create(MyService.class);
    	  ServiceDefTarget endpoint = (ServiceDefTarget) service;
    	  endpoint.setServiceEntryPoint("/echo");

    	  AsyncCallback callback = new AsyncCallback() {
    		  public void onSuccess(Object result) {
    			  label.setText(result.toString());
    		  }
    		  public void onFailure(Throwable caught) {
    		  }
    	  };
    	  
    	  service.echo("Hello World!", callback);
      }
    });

という感じでテキストにサーバからの返り値を設定する。ここで、endpoint.setServiceEntryPoint("/echo")とか書いているが、このままではだめで、先ほど書いたサーブレットを登録しないといけない。

Developer Guide > Fundamentals > Modules > Module XML Format

というところを参考に次の設定を追加する。

今回はこんな風にしてみた。そして、Hosted ModeのJVM を起動している場合は、再起動が必要みたいなので、一度終了させて再度実行させてみる。

こんな感じで、画像小さいけどサーバからの文字列(Server: Hello World!)を表示することができた。


やってみると、Javaが書けるならほとんど違和感なくつかえる。GUIの部品とかもJava1.0とかの頃を思い出す感じだ。XMLパーサも付いているみたいなので、通信でXMLを送ってそれをParseして、結果を表示とか、色々できそう。Documentを見た感じでは、JUnitと統合できそう。そうなるとJavaScriptのテストも統合できそうなので、強力になるかもしれない。あとは、既にあるJavaScriptのライブラリをどうするか。この辺は、全く試していないので、なんともいえないが、アプリで扱えるけど、テストまでできないとなると微妙なところか。きっと、今後GUIツールやら、色々なJavaScriptライブラリがJavaから使えるようになるんじゃないかと思ったりする。サーバ側がServletなので、それがだめだとどうしようもないが、良いなら検討してもいいかもしれない。どうやって実際のServletの設定をするかとか、そもそも既存のプロジェクトとどうやってマージするかとか、もう少し、ドキュメントを読んでみないとわからん。

追記: http://d.hatena.ne.jp/ushisama/20060827