この記事と関連の高い記事
関連キーワード:Java関連キーワード:リッチクライアント
突然ですがキーワードです。Ajax。“えいじゃっくす”と読むのでしょうか?ともかく最近のリッチなUIを持つWebアプリケーションに関わるキーワードのようです。でも、まずは“リッチクライアント”という言葉についておさらいしておきましょう。
近年、業務システムを中心によく使われていたサーバ・クライアントシステムが急速にWebアプリケーション1にリプレースされていきました。この急激な変化の理由はなんだったでしょうか。
Webアプリケーションというフレームワークは、これまでのサーバ・クライアントシステムにあった厄介な問題を解決してくれました。たとえばサーバ・クライアントシステムでは、クライアントソフトウェアのバージョンを管理する必要があり、システムのバージョンアップをしたら、サーバだけでなく、各クライアントのソフトウェアについてもバージョンアップ作業を行わなければなりません。こうした管理コストを考えると、Webアプリケーション化し、クライアント側の管理コストを低減させるというのは魅力的な選択肢でした。また、Webアプリケーションは開発コストを比較的抑えやすいという点も大きな原動力となったと言えるかもしれません。
もちろんWebアプリケーションは”銀の弾丸”ではありません。管理コストや開発コストの低減により、フレームワークとしては進化を遂げたわけですが、退化した部分ももちろんありました。
Webアプリケーションは、基本的なHTMLのみを用いてシステムを構築するため、HTMLで表現できない機能については処理することができません。また、同一ページ内で動的に内容を更新・変更するような仕組みを実現するには、毎回ポストバック2を行う必要があります。この処理は大抵秒単位の時間が掛かるため、ユーザにとってはストレスを引き起こす原因ともなります。
Webアプリケーション化によって、ユーザの操作性・利便性が犠牲となり、特に業務アプリケーションにおいてはWebブラウザが標準で持つ入力系機能の弱さが問題となってきました。そこで新たに考案されたのがリッチクライアントあるいはRIA(リッチインターネットアプリケーション)というアイデアです。
リッチクライアントは、Webアプリケーションシステムでありながら、かつてのサーバ・クライアントシステムで実現していたような“リッチな”操作性を実現する技術です。たとえばファンクションキーを使った入力や、待ち時間を感じさせない画面遷移を実現することができます。リッチクライアントの大半はWebブラウザ上のプラグインで実現されています。
しかし、そうしたリッチクライアントにも弱点があります。最大の弱点は、「Webブラウザほどに普及していない」という点です。リッチクライアントを使用するには、前述のプラグイン等の追加のソフトウェアをインストールする必要がありますし、そのソフトウェアが対応するOS・ブラウザを使用していなければなりません。対象ユーザの環境をある程度絞り込むことのできる社内システム等であればクライアントの管理コストが掛かるという弱点はあるものの対応は可能ですが、インターネットに公開するシステムの場合、ユーザ全員にソフトウェアのインストールを強いるというのは大きな弱点となってしまいます3。クライアント管理コストを低減するためのWebアプリケーションシステムで、クライアントに関する悩みが増えるというのは困ったものです。Ajaxはこうした問題に対する一つの解となるアイデア、技術です。
ではAjaxはどんな技術を用いてリッチクライアントに必要な操作性を実現しているのでしょうか?発想は実にシンプルで、「ほぼすべてのWebブラウザに共通して組み込まれている機能だけを使い、追加のクライアントソフトウェア無しでリッチクライアントを実現しよう」というものです。したがって、鍵となるのは、略号の元の単語となっている“JavaScript”と“XML”という二つの技術、そして“Asynchronous”という手法です。
JavaScriptとXMLについては説明の必要もないでしょう。今日のほとんどのWebブラウザで追加のソフトウェア無しに使用することができ、また将来的にもサポートされ続けるだろう、という観点からしても、普及率という問題を解決しながら、標準のHTML以上の表現力を利用することができます。
そして“Asynchronous”(非同期的な)という手法です。Webアプリケーションを使う際にイライラさせられるのは、何か操作する度にポストバックが発生してWebサーバとの通信が行われ、その間ユーザが待っていなければならない、という点です。JavaScriptを用いたとしても、サーバから情報を取得する際にユーザを待たせてしまうのならば操作性の改善とは言えません。
Ajaxでは、XMLHttpRequestというJavaScriptのオブジェクトを使用してこの問題を解決します。このオブジェクトはWebサーバとのXMLベースの通信を行いますが、通信終了を待たずに処理を返す非同期処理を行うことができます。通信終了時にコールバック関数が呼ばれますので、そのコールバック関数で通信後の処理を記述することで、「ボタンを押すとしばらく何もできずに待たされてしまう」ということが無くなります。
したがってAjaxを簡単にまとめると「各Webブラウザで共通に使用できるJavaScriptを用い、ユーザの操作に応じてWebサーバとXMLベースの非同期通信を用いて情報をやり取りし、画面全体の再描画を避けることで操作性を向上させる技術である」といえます4。
しかし、JavaScriptそしてXMLHttpRequestというソフトウェア部品だけを用いて、サーバと複雑な連携を行う、Ajaxシステムとするのはなかなか大変です。そのため、Ajaxの実装を助けてくれるライブラリが幾つか開発されています。今回取り扱うDWRもその一つです。
DWRはDirect Web Renderingの略で、クライアントサイドのJavaScriptとサーバサイドのJavaを連携させるためのオープンソースライブラリです(http://www.getahead.ltd.uk/dwr/index.html)。Servletコンテナに搭載して使用します。DWRの現バージョンである0.6は以下のブラウザに対応しています。一部のブラウザ(Mac OS X上のFireFox、Safari )では非ASCII文字列に関する不具合があるようです。
ブラウザ同士のJavaScriptの非互換部分に関しては、DWRで使用されるJavaScriptコード内で吸収しています。リスト1はXMLHttpRequestを作成するコード例です。
Internet Explorerとそれ以外のブラウザで処理が異なっています。では早速DWRを用いてAjaxなWebアプリケーションを試してみましょう。
ここでは、サーバ側DWRコンポーネントのWebアプリケーションへの組み込み方法を説明します。お使いのServletコンテナに合わせ、あらかじめWebアプリケーションを作成しておいてください。筆者はWindowsXP Professional上のTomcat5.0を使用してテストを行いました。Tomcatのポート番号は8080、Webアプリケーション名はdwr-testとします。
1. JARファイルのコピー
前述のhttp://www.getahead.ltd.uk/dwr/index.htmlにアクセスし、右側の”Download”リンクから辿ってdwr.jarをダウンロードします。このJARファイルを組込先のWebアプリケーションフォルダのWEB-INF/libフォルダにコピーします。
2. web.xmlの編集
WebアプリケーションフォルダのWEB-INF/web.xmlを編集し、ルートのwebapp要素に以下の記述を追加してください。以下の記述により、/dwr/以下のURLについては、DWR側で処理されることになります(リスト2)。
3. サーバ側クラスの作成
Webブラウザから呼び出したいクラスを作成し、WEB-INF/src以下に保存してください。特別な作法は必要なく、通常のJavaコードを記述可能です。ただし、以下の2点に注意してください。
・ 引数無しのコンストラクタ(デフォルトコンストラクタ)をpublicとする。
・ 関数名にJavaScriptの予約語を使用しない。
基本的にはJavaの予約語と同じですが、Javaには無いdeleteという予約語がありますので、使用しないように注意してください。
今回はリスト3のような2つのメソッドを定義したクラスを作成しました。このDWRTestクラスは“DWR Test”という文字列を返すgetTextメソッドと、引数の値に応じて都道府県名の文字列配列を返すgetPrefsメソッドを持っています。これらのメソッドをWebブラウザから呼び出し、getTextの返値を表示したりgetPrefsの返値を用いてドロップダウンの内容を書き換えたりする、というのが今回のサンプルです。
public String getText(){
return "DWR Test";
}
//都道府県リストを返すメソッド 北海道と東北のみ実装
public String[] getPrefs(int no){
switch(no){
case 0: //北海道だったら
return new String[]{"北海道"};
case 1: //東北だったら
return new String[]{"青森","秋田","福島","山形","岩手"};
default: //それ以外
return new String[]{""};
}
}
}
4. dwr.xmlの作成
WebアプリケーションフォルダのWEB-INFフォルダにリスト4のような内容のdwr.xmlを作成します。これにより、サーバサイドのJavaクラスをJavaScriptに対して公開することができます。
create要素でクラスの定義を行います。class属性に対象クラスの(パッケージ名を含んだ)名前を、javascript属性にJavaScript上で扱う際の名前(パッケージが入ると長くなりますので、任意の名前で再定義します。)を記述します。creator属性はnewないしはsessionを記述することができ、newの場合はWebブラウザからのアクセスごとにJavaクラスが生成され、sessionの場合はWebブラウザのセッションごとにJavaクラスが生成されます。
今回は先ほど作成したDWRTestクラスを、アクセスごとに新規作成するという設定で、DWRTestという名前でJavaScriptに対して公開します。
5. 公開されたクラスの確認
以上までの記述が済めば、JavaScriptから公開されたJavaクラスを呼び出すことができます。まずは標準のサンプルを見てみましょう。
http://localhost:8080/dwr-test/dwrにアクセスしてみてください。図1のような画面が表示されます。上に公開されているJavaクラスの一覧が表示されます。DWRTestをクリックすると図2の画面が表示されます。DWRTestクラスの公開されているメソッドの一覧と、その呼び出し方法が表示されます。
図1:公開されているJavaクラスの一覧
図2:DWRTestクラスの公開されているメソッド一覧
興味深いのは、このページ自体がDWRを用いて書かれており、各メソッドをここから呼び出すことができる、と言う点です。たとえば、getText()の右の[Execute]ボタンを押すと、Webサーバとの通信が行われ、図3のように表示が変化します。
図3:getText()実行後 "DWR Test"という文字列が表示されていることに注目
以上でサーバサイドの設定は終わりです。
1. HTMLファイルの作成
まず、DWRを組み込むためのHTMLファイルを作成します。今回はtest.htmlというHTMLファイルを作成しました。
2. DWRスクリプトの組み込み
DWRのライブラリをインポートします。先ほど見たメソッド一覧画面にも表示されていましたが、
の2行、そして以下の行をHTMLファイルに追加します。
3行目は後述のDWRUtilクラスを使用するための記述です。
3. DWRスクリプトの呼び出し
HTML上に適宜ボタンや表示するためのコントロールを配置し、ボタンを押した時のイベントハンドラにDWRスクリプトを呼び出すようにします。では、サーバサイドで定義したgetTextメソッドとgetPrefsメソッドを呼び出してみましょう。
まずgetTextですが、サーバから取得した文字列をtextTestというIDを持つspanタグ内に表示させることにします。以下のようにボタンとspanタグを配置します。
ボタンを押した時のイベントハンドラUpdateTextは以下のように定義します。
DWRTestは、dwr.xmlのjavascript属性で定義したクラス名です。通常のクラスのメソッド呼び出しに見えますが、引数を持たないはずのgetTextメソッドが、setTextという引数付きで呼び出されていることに注目してください。これは、非同期通信が終了した時にコールバック関数として呼び出されるJavaScriptのメソッド名です。そのsetTextメソッドは以下のように定義しています。
引数のdataにはサーバから取得したデータ(ここでは文字列)が入っています。DWRUtilはutils.jsで定義されたDWRのユーティリティクラスで、ここではtextTestというIDを持つタグにdataをセットする操作を行っています。
以上のように記述することで、サーバ側のgetTextメソッドを呼び出してそれをブラウザ上に表示させることができます。
次に、getPrefsメソッドを呼び出してみましょう。getPrefsメソッドは地方に対応した都道府県リストを返すメソッドです。地方を選択するためのドロップダウン(ID='district')と、都道府県を表示するためのドロップダウン(ID='selectTest')、そしてボタンを配置し、以下のように記述します。
ボタンを押した時のイベントハンドラUpdateSelectは以下のように定義します。
DWRTestクラスのgetPrefsメソッドを呼び出していますが、今回もサーバ側と引数が異なっています。第一引数はコールバック関数定義、第二引数以降がサーバ側で定義した引数となります。
したがって、コールバック関数はsetSelectメソッド、サーバのgetPrefsメソッドへの引数はdistrictドロップダウンの値になります。setSelectは以下のように定義します。
引数のdataにはサーバから取得したデータ(ここでは文字列配列)が入っています。通常であれば配列をループしながらoptionタグを作成する必要がありますが、DWRUtilクラスには配列からoptionタグを生成してselectタグにセットするfillListというメソッドがあるので、それを使用しています。ここではselectTestというIDを持つselectタグにdataをセットしています。
getText・getPrefsメソッドを実行すると、それぞれ以下のように画面表示が変わります(図4~6)。
図4:実行前の画面
図5:getTextメソッド実行後 “DWR Test“が表示されている
図6:“東北”を選択してgetPrefsメソッド実行 都道府県がドロップダウンにセットされている
以上のような動作を、画面の再読込無しに、非同期に行うことができます。非常に簡潔な記述でサーバとの連携を行うことができるDWRのおかげですね。
DWRはまだバージョンも0.6で、ドキュメントもそれほど揃っていません。特に日本語の情報源はほとんど無いため、サンプルやソースコードを見ながら試行錯誤が必要な段階です。
DWRを用いることで直接JavaScriptからXMLHttpRequestを使う場合よりもずっと簡潔な記述とすることができます。とはいえ、DWRはサーバサイドJavaへの基本的なインタフェースを提供するのみであり、リッチクライアントに必要な様々な機能、たとえばASP.NETで実現されているような豊富なバリデーション機能をすぐに使用できるわけではありません。今後、DWRを基として、サーバ技術とさらに連携を図ることができるタグライブラリなどが登場して、Ajax実装環境がさらに整備されていくことを期待しましょう。
DWR公式サイト5(http://www.getahead.ltd.uk/dwr/index.html)には、サンプルも含め有益な情報が多く掲載されていますので、DWRを使用する際には目を通されることをオススメします。ではみなさま、快適なAjaxライフをDWRでお楽しみください!