
Java Web アプリケーションでの Ajax 入門
このドキュメントでは、Ajax の概要を説明し、Ajax 関連のテクノロジを使用するときにより短時間で効率よくプログラミングできる NetBeans IDE の機能を示します。Ajax の基本的な機能を学びながら、テキストフィールドの自動補完を行う簡単なアプリケーションを作成します。このドキュメントでは、「Java テクノロジを使用する Ajax の使用」に公開している Greg Murray の記事とサンプルアプリケーションを使用します。
Ajax は「Asynchronous JavaScript and XML」(非同期 JavaScript と XML) の略です。Ajax は基本的に、ユーザーによる Web ページの操作を Web アプリケーションで効率的に処理する方法であり、ユーザーが操作するたびにページを再表示したり、ページ全体を再読み込みしたりする必要を減らします。その結果、デスクトップアプリケーションやプラグインに基づいた Web アプリケーションのような、ブラウザを使用したスムーズな操作が可能になります。Ajax の相互作用はバックグラウンドで非同期で処理されます。このとき、ユーザーはページの操作を続けることができます。Ajax の相互作用は JavaScript コードによって開始されます。Ajax の相互作用が完了したら、JavaScript がそのページの HTML ソースを更新します。変更は、ページを再表示することなく、すぐに反映されます。Ajax の相互作用を使用して、ユーザーがフォームに入力している間にサーバー側ロジックを使用してその内容を検査したり、サーバーから詳細なデータを取り出したり、ページ上のデータを動的に更新したり、ページから部分フォームを送信したりできます。
目次

このチュートリアルを完了するには、次のソフトウェアとリソースが必要です。
注:
- Web および Java EE インストール版では、GlassFish サーバー 3.0.1 と Apache Tomcat サーブレットコンテナ 6.0.x を任意でインストールできます。
- このチュートリアルは、使用するさまざまなテクノロジ (HTML、CSS、JavaScript、Java、および JSP など) についての実用的な知識がある方を対象としています。コードが提供する機能の概要は説明しますが、コード行ごとの処理は説明しません。
- プロジェクトを、正常に機能するソリューションと比較する必要がある場合は、サンプルアプリケーションをダウンロードできます。
アプリケーションの概要
ユーザーが作曲家に関する情報を検索できる Web ページを考えます。このページには、ユーザーが作曲家の名前を入力できるフィールドがあります。サンプルアプリケーションの入力フィールドには、自動補完機能があります。つまり、ユーザーが作曲家の名前の一部を入力すると、入力した文字から氏名のいずれかが始まる作曲家のリストが表示されます。自動補完機能によってユーザーは作曲家の名前を完全に覚えている必要がなく、また求めている情報を直感的に、かつすんなりと入手できます。
検索フィールドへの自動補完の実装は、Ajax を使用して実行できます。Ajax は、XMLHttpRequest オブジェクトを使用してクライアントとサーバーの間で要求と応答を非同期で受け渡しすることで機能します。次の図は、クライアントとサーバーの間で行われる通信のプロセスフローを示します。
この図には、次の手順のプロセスフローを示しています。
- ユーザーが、たとえば名前を入力しているときにキーを解除して、イベントをトリガーします。すると、
XMLHttpRequest オブジェクトを初期化する関数への JavaScript 呼び出しが行われます。
XMLHttpRequest オブジェクトが、イベントをトリガーしたコンポーネントの ID を含む要求パラメータと、ユーザーが入力した値で構成されます。次に XMLHttpRequest オブジェクトが Web サーバーへの非同期要求を実行します。
- Web サーバーでは、サーブレットやリスナーなどのオブジェクトが要求を処理します。データストアからデータが取り出され、XML 形式のデータを含む応答が作成されます。
- 最後に、コールバック関数を使用して
XMLHttpRequest オブジェクトが XML データを受け取って処理し、新しいデータを含むページを表示するように HTML の DOM (文書オブジェクトモデル) を更新します。
このチュートリアルでは、前出の図で示したプロセスフローに従って自動補完のシナリオを構築する方法を示します。最初に、プレゼンテーション用、および XMLHttpRequest オブジェクトの生成に必要な機能用のクライアント側ファイルを作成します。次に、Java ベースのテクノロジを使用してデータストアとビジネスロジックを作成し、サーバー側を設定します。最後に、クライアント側に戻り、callback() と、HTML の DOM を更新するためのその他の JavaScript 機能を実装します。
クライアント側のプログラミング: 第 1 部
最初に IDE で新しい Web アプリケーションプロジェクトを作成します。IDE には、さまざまな種類のプロジェクト用のテンプレートが組み込まれています。
- 「ファイル」>「新規プロジェクト」を選択します。「カテゴリ」で「Web」を選択します。「プロジェクト」で「Web アプリケーション」を選択して、「次へ」をクリックします。
- 「名前と場所」パネルでプロジェクト名として「
MyAjaxApp」と入力します。「プロジェクトの場所」フィールドでコンピュータ上でのプロジェクトの場所を指定できます。ほかのオプションはデフォルトのままにして、「次へ」をクリックします。

- 「サーバーと設定」パネルで、アプリケーションを配備するサーバーを選択します。IDE に登録されているサーバーのみ表示されます。

- その他のデフォルト設定を受け入れ、「完了」をクリックします。プロジェクトがファイルシステムに生成され、IDE で開きます。
Java ベースの Web プロジェクトが作成されるとき、Ant 構築スクリプトが自動的に生成されます。このスクリプトによってプロジェクトをコンパイルし、IDE に登録されているサーバーにすぐに配備して実行できます。
デフォルトの index.php ページが生成され、IDE のソースエディタで開きます。また、「プロジェクト」ウィンドウにプロジェクトが表示されます。
コーディングを始める前に、アプリケーションを実行してみて、IDE、サーバー、ブラウザの間の構成が正しく設定されていることを確認します。
「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「実行」を選択します。
アプリケーションがコンパイルされ、アプリケーションサーバーが起動し、アプリケーションがサーバーに配備されて実行されます。IDE によってデフォルトのブラウザが開き、index.jsp に含まれるデフォルトの Hello World メッセージが表示されます。
HTML エディタの使用
環境が正しく設定されていることを確認できたら、まず index ページを、ユーザーに表示する自動補完インタフェースに変更します。
IDE を使用するメリットの 1 つは、作業を行うエディタには一般にコード補完機能が用意されていて、コーディングするときに適用すれば生産性を大幅に向上できることです。IDE のソースエディタは通常、使用しているテクノロジに適応するので、HTML ページの作業を行なっているときにコード補完のキーの組み合わせ (Ctrl- スペース) を押すと HTML のタグと属性の候補が表示されます。あとで示しますが、CSS や JavaScript などその他のテクノロジも同様です。
IDE のパレットも便利な機能です。パレットには、コーディングするテクノロジで一般的に適用する要素の、使いやすいテンプレートが用意されています。項目をクリックし、ソースエディタで開いているファイル内の任意の位置にドラッグするだけです。
この図のように大きなアイコンを表示するには、パレット内を右クリックし、「大きなアイコンを表示」を選択します。
<title> タグおよび <h1> タグの内容を「Auto-Completion using AJAX」に変更します。index ページにはサーバー側スクリプトコードは必要ないので、デフォルトで作成された残りの部分を削除してもかまいません。index ページは次のようになります。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Auto-Completion using AJAX</title>
</head>
<body>
<h1>Auto-Completion using AJAX</h1>
</body>
</html>
- テキストフィールドの目的を説明するテキストを追加します。次のテキストをコピーし、
<h1> タグのすぐ下にペーストしてもかまいません。
<p>This example shows how you can do real time auto-completion using Asynchronous
JavaScript and XML (Ajax) interactions.</p>
<p>In the form below enter a name. Possible names that will be completed are displayed
below the form. For example, try typing in "Bach," "Mozart," or "Stravinsky,"
then click on one of the selections to see composer details.</p>
- ページに HTML フォームを追加します。この操作を行うには、IDE のパレットに表示されている要素を使用します。パレットが開いていない場合は、メインメニューから「ウィンドウ」>「パレット」を選択します。次に「HTML フォーム」の下にある「フォーム」要素をクリックし、ページ内に追加した
<p> タグの下までドラッグします。「挿入フォーム」ダイアログが表示されます。次の値を指定します。
- アクション: autocomplete
- メソッド: GET
- 名前: autofillform
「了解」をクリックします。指定した属性を含む HTML の <form> タグがページに挿入されます。GET はデフォルトで適用されるので、明示的に宣言しません。
- HTML 表をページに追加します。パレットの「HTML」カテゴリの下で「表」要素をクリックし、
<form> タグの間の任意の位置までドラッグします。「挿入 表」ダイアログが開きます。次の値を指定します。
- 行: 2
- 列: 2
- ボーダーのサイズ: 0
- セルのパディング: 5
- ソースエディタ内を右クリックし、「整形」を選択します。これでコードの体裁が整います。フォームは次のようになります。
<form name="autofillform" action="autocomplete">
<table border="0" cellpadding="5">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</form>
- 表の 1 行目の 1 列目に次のテキストを入力します (ボールド部分が変更箇所)。
<td><strong>Composer Name:</strong></td>
- 1 行目の 2 列目では、パレットから「テキスト入力」フィールドをドラッグしないで、次のコードを手作業で入力します (ボールド部分が変更箇所)。
<td>
<input type="text"
size="40"
id="complete-field"
onkeyup="doCompletion();">
</td>
入力するときは、IDE に組み込まれているコード補完機能を使用してみてください。たとえば、「<i」と入力して Ctrl- スペースキーを押します。カーソルの下に候補のリストが表示され、選択されている要素の説明が上のボックスに表示されます。ソースエディタでコーディングしているときはいつでも Ctrl- スペースキーを押して候補リストを表示できます。候補が 1 つだけの場合は、Ctrl- スペースキーを押すと要素名が自動的に補完されます。
入力した onkeyup 属性は JavaScript 関数 doCompletion() を指しています。この関数は、フォームのテキストフィールド内でキーが押されるたびに呼び出され、Ajax のフロー図に示した JavaScript 呼び出しに対応します。
JavaScript エディタの使用
IDE の JavaScript エディタには多数の高度な編集機能が用意されています。たとえば、インテリジェントなコード補完、意味解釈の強調表示、名前の即時変更機能とリファクタリング機能などがあります。概要については「JavaScript の編集」を、詳細な仕様については、http://wiki.netbeans.org/JavaScript を参照してください。
JavaScript のコード補完は、.js ファイル内でコーディングするとき、またほかのテクノロジ (HTML、RHTML、JSP、PHP など) を使用しているときに <script> タグ内で自動的に提供されます。JavaScript エディタには、JavaScript の「オプション」パネルで指定するブラウザの種類とバージョンに従って、ブラウザの互換性情報が表示されます。JavaScript の「オプション」パネルを開くには、「ツール」>「オプション」(Mac の場合は「NetBeans」>「設定」) を選択してから「その他」>「JavaScript」を選択します。
IDE では、Firefox、Internet Explorer、Safari、および Opera をデフォルトでサポートしています。JavaScript の「オプション」パネルでは、コード補完を適用する JavaScript エンジンのバージョンを指定することもできます。
アプリケーションに JavaScript ファイルを追加し、doCompletion() の実装を始めます。
- 「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「新規」>「JavaScript ファイル」を選択します。「JavaScript ファイル」がリストにない場合は「その他」を選択します。次に「新規ファイル」ウィザードで「Web」カテゴリから JavaScript ファイルを選択します。
- ファイル名を
javascript にし、「フォルダ」テキストフィールドに「web」と入力してファイルを web サブフォルダに入れます。
- 「完了」をクリックし、新しい JavaScript ファイルが「プロジェクト」ウィンドウで「Web ページ」フォルダ内に表示されることを確認します。
注: なぜ「web」フォルダが表示されないのかわからない場合は、「ファイル」ウィンドウ (「ウィンドウ」>「ファイル」) をクリックします。「プロジェクト」ウィンドウはプロジェクト内の重要な項目の論理ビューを示します。これに対して「ファイル」ウィンドウは、プロジェクトのすべての内容がディレクトリ階層で表示されます。
- 次のコードを
javascript.js に入力します。
var req;
var isIE;
function init() {
completeField = document.getElementById("complete-field");
}
function doCompletion() {
var url = "autocomplete?action=complete&id=" + escape(completeField.value);
req = initRequest();
req.open("GET", url, true);
req.onreadystatechange = callback;
req.send(null);
}
function initRequest() {
if (window.XMLHttpRequest) {
if (navigator.userAgent.indexOf('MSIE') != -1) {
isIE = true;
}
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
isIE = true;
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
上のコードは、Firefox 3 および Internet Explorer version 6 と 7 の簡単なブラウザ互換性チェックを行います。互換性の問題に対してさらに堅牢なコードを取り込むには、http://www.quirksmode.org のブラウザ検出スクリプトを使用することを検討してください。
index.jsp に戻り、JavaScript ファイルへの参照を <head> タグの間に追加します。
<script type="text/javascript" src="javascript.js"></script>
Ctrl-Tab キーを押すと、ソースエディタ内で開いているページ間を簡単に切り替えることができます。
init() への呼び出しを開始 <body> タグ内に挿入します。
<body onload="init()">
このようにすると、ページが読み込まれるたびに init() が呼び出されます。
doCompletion() には次の役割があります。
- サーバー側で利用できるデータを含む URL を作成すること
XMLHttpRequest オブジェクトを初期化すること
- 非同期要求をサーバーに送信するように
XMLHttpRequest オブジェクトに要求すること
XMLHttpRequest オブジェクトは Ajax の中核であり、HTTP を使用して XML データを非同期で送信するときの事実上の標準になっています。相互作用が非同期であるということは、要求の送信後にブラウザで引き続きイベントを処理できることを意味します。データはバックグラウンドで送信され、ページを再表示しないで自動的にページに読み込むことができます。
XMLHttpRequest オブジェクトは実際には initRequest() で作成し、これは doCompletion() から呼び出されます。この関数では、ブラウザで XMLHttpRequest を理解できるかどうかを確認し、理解できる場合は XMLHttpRequest オブジェクトを作成します。理解できない場合は、ActiveXObject (Internet Explorer 6 で XMLHttpRequest に相当するもの) を確認し、識別された場合は ActiveXObject を作成します。
XMLHttpRequest オブジェクトを作成するときは 3 つのパラメータを指定します。URL、HTTP メソッド (GET または POST)、そして相互作用が非同期であるかどうかです。前出の例では、これらのパラメータは次のとおりです。
- URL
autocomplete と、ユーザーが complete-field に入力したテキスト
var url = "autocomplete?action=complete&id=" + escape(completeField.value);
GET (HTTP の相互作用で GET メソッドを使用)
true (相互作用は非同期)
req.open("GET", url, true);
相互作用を非同期に設定する場合は、コールバック関数を指定します。この相互作用のコールバック関数は次の文で設定します。
req.onreadystatechange = callback;
そして callback() 関数をあとで定義する必要があります。HTTP の相互作用は XMLHttpRequest.send() の呼び出し時に開始します。このアクションは、前出のフロー図で Web サーバーに送信されている HTTP 要求に対応します。
サーバー側のプログラミング
IDE では、サーバー側の Web プログラミングが総合的にサポートされています。これには多くの一般的なプログラミング言語とスクリプト言語の基本的なエディタサポートが含まれており、SOAP、REST、SaaS などの Web サービスと、JSF、Spring、Struts、Ruby on Rails、Grails などの MVC 指向フレームワークなども網羅されています。Ajax のサポートは、JSF Visual Web プロジェクトの Woodstock コンポーネントと、AJAX 機能を提供する JSF 拡張である Dynamic Faces に含まれます。また、GWT、Struts2、および jMaki など、Ajax 駆動型フレームワーク用のプラグインも多数あります。
アプリケーションのビジネスロジックでは、データストアからデータを取り出し、応答を作成して送信することで、要求を処理します。ここではサーブレットを使用してこの処理を実装します。サーブレットのコーディングを始める前に、データストアと、サーブレットからデータにアクセスするために必要な機能を設定します。
データストアの作成
この簡単なアプリケーションでは、HashMap を使用して作曲家のデータを保持する ComposerData というクラスを作成します。HashMap によって、リンクされている項目のペアをキーと値のペアで保存できます。また、サーブレットで、HashMap 内のエントリからデータを取り出すための Composer クラスも作成します。
- 「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「新規」>「Java クラス」を選択します。
- クラス名を
ComposerData にし、「パッケージ」フィールドに「com.ajax」と入力します。このクラス、およびあとで作成するほかのクラスを含めるための新しいパッケージが作成されます。
- 「完了」をクリックします。クラスが作成され、ソースエディタで開きます。
- ソースエディタ内に、次のコードをペーストします。
package com.ajax;
import java.util.HashMap;
/**
*
* @author nbuser
*/
public class ComposerData {
private HashMap composers = new HashMap();
public HashMap getComposers() {
return composers;
}
public ComposerData() {
composers.put("1", new Composer("1", "Johann Sebastian", "Bach", "Baroque"));
composers.put("2", new Composer("2", "Arcangelo", "Corelli", "Baroque"));
composers.put("3", new Composer("3", "George Frideric", "Handel", "Baroque"));
composers.put("4", new Composer("4", "Henry", "Purcell", "Baroque"));
composers.put("5", new Composer("5", "Jean-Philippe", "Rameau", "Baroque"));
composers.put("6", new Composer("6", "Domenico", "Scarlatti", "Baroque"));
composers.put("7", new Composer("7", "Antonio", "Vivaldi", "Baroque"));
composers.put("8", new Composer("8", "Ludwig van", "Beethoven", "Classical"));
composers.put("9", new Composer("9", "Johannes", "Brahms", "Classical"));
composers.put("10", new Composer("10", "Francesco", "Cavalli", "Classical"));
composers.put("11", new Composer("11", "Fryderyk Franciszek", "Chopin", "Classical"));
composers.put("12", new Composer("12", "Antonin", "Dvorak", "Classical"));
composers.put("13", new Composer("13", "Franz Joseph", "Haydn", "Classical"));
composers.put("14", new Composer("14", "Gustav", "Mahler", "Classical"));
composers.put("15", new Composer("15", "Wolfgang Amadeus", "Mozart", "Classical"));
composers.put("16", new Composer("16", "Johann", "Pachelbel", "Classical"));
composers.put("17", new Composer("17", "Gioachino", "Rossini", "Classical"));
composers.put("18", new Composer("18", "Dmitry", "Shostakovich", "Classical"));
composers.put("19", new Composer("19", "Richard", "Wagner", "Classical"));
composers.put("20", new Composer("20", "Louis-Hector", "Berlioz", "Romantic"));
composers.put("21", new Composer("21", "Georges", "Bizet", "Romantic"));
composers.put("22", new Composer("22", "Cesar", "Cui", "Romantic"));
composers.put("23", new Composer("23", "Claude", "Debussy", "Romantic"));
composers.put("24", new Composer("24", "Edward", "Elgar", "Romantic"));
composers.put("25", new Composer("25", "Gabriel", "Faure", "Romantic"));
composers.put("26", new Composer("26", "Cesar", "Franck", "Romantic"));
composers.put("27", new Composer("27", "Edvard", "Grieg", "Romantic"));
composers.put("28", new Composer("28", "Nikolay", "Rimsky-Korsakov", "Romantic"));
composers.put("29", new Composer("29", "Franz Joseph", "Liszt", "Romantic"));
composers.put("30", new Composer("30", "Felix", "Mendelssohn", "Romantic"));
composers.put("31", new Composer("31", "Giacomo", "Puccini", "Romantic"));
composers.put("32", new Composer("32", "Sergei", "Rachmaninoff", "Romantic"));
composers.put("33", new Composer("33", "Camille", "Saint-Saens", "Romantic"));
composers.put("34", new Composer("34", "Franz", "Schubert", "Romantic"));
composers.put("35", new Composer("35", "Robert", "Schumann", "Romantic"));
composers.put("36", new Composer("36", "Jean", "Sibelius", "Romantic"));
composers.put("37", new Composer("37", "Bedrich", "Smetana", "Romantic"));
composers.put("38", new Composer("38", "Richard", "Strauss", "Romantic"));
composers.put("39", new Composer("39", "Pyotr Il'yich", "Tchaikovsky", "Romantic"));
composers.put("40", new Composer("40", "Guiseppe", "Verdi", "Romantic"));
composers.put("41", new Composer("41", "Bela", "Bartok", "Post-Romantic"));
composers.put("42", new Composer("42", "Leonard", "Bernstein", "Post-Romantic"));
composers.put("43", new Composer("43", "Benjamin", "Britten", "Post-Romantic"));
composers.put("44", new Composer("44", "John", "Cage", "Post-Romantic"));
composers.put("45", new Composer("45", "Aaron", "Copland", "Post-Romantic"));
composers.put("46", new Composer("46", "George", "Gershwin", "Post-Romantic"));
composers.put("47", new Composer("47", "Sergey", "Prokofiev", "Post-Romantic"));
composers.put("48", new Composer("48", "Maurice", "Ravel", "Post-Romantic"));
composers.put("49", new Composer("49", "Igor", "Stravinsky", "Post-Romantic"));
composers.put("50", new Composer("50", "Carl", "Orff", "Post-Romantic"));
}
}
次の Composer クラスを作成します。
- 「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「新規」>「Java クラス」を選択します。
- クラス名を
Composer にし、「パッケージ」フィールドのドロップダウンリストから「com.ajax」を選択します。「次へ」をクリックします。
- 「完了」をクリックします。クラスが作成され、ソースエディタで開きます。
- ソースエディタ内に、次のコードをペーストします。
package com.ajax;
public class Composer {
private String id;
private String firstName;
private String lastName;
private String category;
public Composer (String id, String firstName, String lastName, String category) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.category = category;
}
public String getCategory() {
return category;
}
public String getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
サーブレットの作成
受信要求によって受け取る autocomplete URL を処理するサーブレットを作成します。
- 「プロジェクト」ウィンドウでプロジェクトのノードを右クリックし、「新規」>「サーブレット」を選択します。(「サーブレット」が表示されない場合は、「その他」を選択し、「Web」カテゴリから「サーブレット」を選択します。)「新規サーブレット」ウィザードが開き、「名前と場所」パネルが表示されます。

- サーブレット名を
AutoCompleteServlet にし、「パッケージ」フィールドのドロップダウンリストから「com.ajax」を選択します。
- 「次へ」をクリックします。「サーブレット配備を構成」パネルが開きます。

- 「サーブレット配備を構成」パネルで、URL パターンを
/autocomplete にし、XMLHttpRequest オブジェクトで以前に設定した URL と一致するようにします。このパネルによって、これらの詳細を配備記述子に手作業で追加する必要がなくなります。
- あるいは、「サーブレット情報を配備記述子に追加」を選択します。これにより、プロジェクトがダウンロードしたサンプルと同じになります。最近のバージョンの IDE では、サーブレットはデフォルトで
@WebServlet 注釈によって登録され、配備記述子には登録されません。配備記述子の代わりに @WebServlet 注釈を使用した場合も、プロジェクトは引き続き機能します。
- 「完了」をクリックします。サーブレットが作成され、ソースエディタで開きます。
オーバーライドする必要があるメソッドは、サーブレットで autocomplete GET 要求を処理する方法を定義する doGet() と、サービスを開始後にサーブレットからアプリケーション内のほかのクラスにアクセスできるように ServletContext を初期化する init() だけです。
スーパークラスのメソッドは、IDE の「コードを挿入」ポップアップメニューを使用してオーバーライドできます。この方法で init() を実装します。
- ソースエディタで、
AutoCompleteServlet クラスの宣言の下にカーソルを置きます。Alt-Insert キー (Mac では Ctrl-I) を押して「コードを生成」ポップアップメニューを開きます。

- 「メソッドをオーバーライド」を選択します。表示されるダイアログで、
AutoCompleteServlet の継承元クラスがすべて表示されます。「GenericServlet」ノードを展開し、「init(Servlet Config config)」を選択します。

- 「了解」をクリックします。
init() メソッドがソースエディタに追加されます。
ServletContext オブジェクトの変数を追加し、init() を変更します (ボールド部分が変更箇所)。
private ServletContext context;
@Override
public void init(ServletConfig config) throws ServletException {
this.context = config.getServletContext();
}
ServletContext のインポート文を追加します。そのためには、ソースエディタの左側の余白に表示される電球のアイコンをクリックします。

doGet() メソッドでは要求の URL を解析し、データストアからデータを取り出し、XML 形式で応答を作成する必要があります。メソッドの宣言は、クラスの作成時に生成されています。これを表示するには、左側の余白にある展開アイコン ( ) をクリックして HttpServlet メソッドを展開し、宣言を表示する必要がある場合もあります。
AutocompleteServlet クラスの宣言の下に次の変数宣言を追加します。
private ComposerData compData = new ComposerData();
private HashMap composers = compData.getComposers();
これで、すべての作曲家データの HashMap が作成されます。これは doGet() で使用されます。
doGet() までスクロールし、次のようにメソッドを実装します。
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String action = request.getParameter("action");
String targetId = request.getParameter("id");
StringBuffer sb = new StringBuffer();
if (targetId != null) {
targetId = targetId.trim().toLowerCase();
} else {
context.getRequestDispatcher("/error.jsp").forward(request, response);
}
boolean namesAdded = false;
if (action.equals("complete")) {
// ユーザーが空の文字列を送信したかどうかを確認
if (!targetId.equals("")) {
Iterator it = composers.keySet().iterator();
while (it.hasNext()) {
String id = (String) it.next();
Composer composer = (Composer) composers.get(id);
if ( // targetId が名と一致
composer.getFirstName().toLowerCase().startsWith(targetId) ||
// targetId が姓と一致
composer.getLastName().toLowerCase().startsWith(targetId) ||
// targetId がフルネームと一致
composer.getFirstName().toLowerCase().concat(" ")
.concat(composer.getLastName().toLowerCase()).startsWith(targetId)) {
sb.append("<composer>");
sb.append("<id>" + composer.getId() + "</id>");
sb.append("<firstName>" + composer.getFirstName() + "</firstName>");
sb.append("<lastName>" + composer.getLastName() + "</lastName>");
sb.append("</composer>");
namesAdded = true;
}
}
}
if (namesAdded) {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<composers>" + sb.toString() + "</composers>");
} else {
//表示なし
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
if (action.equals("lookup")) {
// ターゲットコンポーザを表示する要求スコープに置く
if ((targetId != null) && composers.containsKey(targetId.trim())) {
request.setAttribute("composer", composers.get(targetId));
context.getRequestDispatcher("/composer.jsp").forward(request, response);
}
}
}
サーブレットを見ればわかるように、Ajax 処理用のサーバー側コードを記述するために新たに覚えることはありません。XML ドキュメントを交換する場合は、応答の内容の種類を text/xml に設定します。Ajax ではプレーンテキストを交換することもできます。JavaScript のスニペットの交換は、クライアントのコールバック関数によって評価または実行できます。一部のブラウザでは結果がキャッシュに保存される場合があるので、Cache-Control HTTP ヘッダーを no-cache に設定する必要がある場合もあります。
この例では、氏名のいずれかが、ユーザーが入力した文字から始まる作曲家がすべて含まれる XML ドキュメントがサーブレットによって生成されます。このドキュメントは、前出のフロー図に示す XML データに対応します。XMLHttpRequest オブジェクトに返される XML ドキュメントの例を示します。
<composers>
<composer>
<id>12</id>
<firstName>Antonin</firstName>
<lastName>Dvorak</lastName>
</composer>
<composer>
<id>45</id>
<firstName>Aaron</firstName>
<lastName>Copland</lastName>
</composer>
<composer>
<id>7</id>
<firstName>Antonio</firstName>
<lastName>Vivaldi</lastName>
</composer>
<composer>
<id>2</id>
<firstName>Arcangelo</firstName>
<lastName>Corelli</lastName>
</composer>
</composers>
アプリケーションが完成したら、返される XML データを確認するために IDE の HTTP モニターを使用できます。
クライアント側のプログラミング: 第 2 部
サーバーの応答を処理するコールバック関数を定義し、ユーザーに表示するページに変更を反映するために必要な機能を追加する必要があります。そのためには HTML の DOM を変更する必要があります。要求が成功した場合はその結果を表示し、要求が失敗した場合はエラーメッセージを表示する、JSP ページを作成する必要があります。最後に、IDE の CSS エディタを使用して、簡単なスタイルシートをプレゼンテーションに追加できます。
コールバック機能の追加
コールバック関数は、HTTP の相互作用中に XMLHttpRequest オブジェクトの「readyState」プロパティーが変化したとき、非同期で呼び出されます。ここで構築しているアプリケーションでのコールバック関数は callback() です。doCompletion() では、callback を関数の「XMLHttpRequest.onreadystatechange」プロパティーとして設定しました。ここで、コールバック関数を次のように実装します。
javascript.js をソースエディタで開き、次のコードを入力します。
function callback() {
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages(req.responseXML);
}
}
}
readyState が「4」のとき、HTTP の相互作用は完了しています。XMLHttpRequest.readState の API は、設定できる値が 5 つあることを示します。これらを次に示します。
| 0 |
非初期化 |
| 1 |
読み込み中 |
| 2 |
読み込み済み |
| 3 |
対話式 |
| 4 |
完了 |
parseMessages() 関数は、XMLHttpRequest.readyState が「4」で、status (要求の HTTP 状態コード定義) が「200」、つまり成功の場合にのみ呼び出しています。parseMessages() は、次の「HTML DOM の更新」で定義します。
HTML DOM の更新
受信する XML データは parseMessages() 関数で処理します。このとき、appendComposer()、getElementY()、および clearTable() などの補助的関数を使用します。また、index ページに新しい要素を追加する必要があります。新しい要素とは、自動補完ボックスとして機能する別の HTML 表や、要素を javascript.js で参照できるようするための要素の ID などです。最後に、index.jsp 内の要素の ID に対応する新しい変数を作成し、前に実装した init() 関数で初期化し、index.jsp が読み込まれるたびに必要とされる機能を追加します。
注: 次の手順で作成する関数と要素は、依存しあって動作します。この節の最後まで行い、コードが完成してからその内容を確認することをお勧めします。
index.jsp をソースエディタで開き、前に作成した HTML 表の 2 行目として次のコードを入力します。
<tr>
<td id="auto-row" colspan="2">
<table id="complete-table" />
<td/>
</tr>
表の 2 番目の行は、別の HTML 表を含んでいます。この表は、作曲家の名前を挿入するための自動補完ボックスを表します。
javascript.js をソースエディタで開き、次の 3 つの変数をファイルの先頭に追加します。
var completeField;
var completeTable;
var autoRow;
- 次のボールドの行を
init() 関数に追加します。
function init() {
completeField = document.getElementById("complete-field");
completeTable = document.getElementById("complete-table");
autoRow = document.getElementById("auto-row");
completeTable.style.top = getElementY(autoRow) + "px";
}
init() の目的の 1 つは、index ページの DOM を変更するほかの関数から index.jsp 内の要素にアクセスできるようにすることです。
appendComposer() を javascript.js に追加します。
function appendComposer(firstName,lastName,composerId) {
var row;
var cell;
var linkElement;
if (isIE) {
completeTable.style.display = 'block';
row = completeTable.insertRow(completeTable.rows.length);
cell = row.insertCell(0);
} else {
completeTable.style.display = 'table';
row = document.createElement("tr");
cell = document.createElement("td");
row.appendChild(cell);
completeTable.appendChild(row);
}
cell.className = "popupCell";
linkElement = document.createElement("a");
linkElement.className = "popupItem";
linkElement.setAttribute("href", "autocomplete?action=lookup&id=" + composerId);
linkElement.appendChild(document.createTextNode(firstName + " " + lastName));
cell.appendChild(linkElement);
}
この関数は、表に新しい行を作成し、3 つのパラメータによって関数に渡されたデータを使用して作曲家へのリンクを挿入してから、行を index ページの complete-table 要素に挿入します。
getElementY() を javascript.js に追加します。
function getElementY(element){
var targetTop = 0;
if (element.offsetParent) {
while (element.offsetParent) {
targetTop += element.offsetTop;
element = element.offsetParent;
}
} else if (element.y) {
targetTop += element.y;
}
return targetTop;
}
この関数は、親要素の縦方向表示位置を見つけるために適用します。要素の実際の表示位置は、一般にブラウザの種類とバージョンによって異なるためこの関数が必要です。complete-table 要素は、作曲家の名前が表示されるときに、表の右下に移動します。正しい縦方向の配置は getElementY() で決まります。
注: http://www.quirksmode.org/ にある offset に関する説明を参照してください。
clearTable() を javascript.js に追加します。
function clearTable() {
if (completeTable.getElementsByTagName("tr").length > 0) {
completeTable.style.display = 'none';
for (loop = completeTable.childNodes.length -1; loop >= 0 ; loop--) {
completeTable.removeChild(completeTable.childNodes[loop]);
}
}
}
この関数は complete-table 要素の表示を 'none' に設定し (非表示にし)、作成された既存の作曲家の名前を削除します。
callback() 関数を変更して、サーバーから新しいデータを受け取るたびに clearTable() を呼び出すようにします。自動補完ボックスに作曲家のエントリがある場合は、新しいエントリが入力される前に削除されます。
function callback() {
clearTable();
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages(req.responseXML);
}
}
}
parseMessages() を javascript.js に追加します。
function parseMessages(responseXML) {
// 一致なし
if (responseXML == null) {
return false;
} else {
var composers = responseXML.getElementsByTagName("composers")[0];
if (composers.childNodes.length > 0) {
completeTable.setAttribute("bordercolor", "black");
completeTable.setAttribute("border", "1");
for (loop = 0; loop < composers.childNodes.length; loop++) {
var composer = composers.childNodes[loop];
var firstName = composer.getElementsByTagName("firstName")[0];
var lastName = composer.getElementsByTagName("lastName")[0];
var composerId = composer.getElementsByTagName("id")[0];
appendComposer(firstName.childNodes[0].nodeValue,
lastName.childNodes[0].nodeValue,
composerId.childNodes[0].nodeValue);
}
}
}
}
parseMessages() 関数は、AutoComplete サーブレットから返される XML ドキュメントのオブジェクト表現をパラメータとして受け取ります。この関数はプログラムで XML ドキュメント内を横断し、各エントリの firstName、lastName、および id を抽出して、このデータを appendComposer() に渡します。その結果、complete-table 要素の内容が動的に更新されます。たとえば、次のようなエントリが生成され、complete-table に挿入されます。
<tr>
<td class="popupCell">
<a class="popupItem" href="autocomplete?action=lookup&id=12">Antonin Dvorak</a>
</td>
</tr>
complete-table 要素の動的な更新は、Ajax を使用して行われる通信の、プロセスフローの最後の手順を表します。この更新は、前出のフロー図のプレゼンテーションに送信される HTML と CSS データに対応します。
結果の表示
結果を表示するには、composers.jsp という名前の JSP ファイルが必要です。このページは、ルックアップ処理中に AutoCompleteServlet から呼び出されます。error.jsp ファイルも必要で、これはコンポーザが見つからない場合に AutoCompleteServlet から呼び出されます。
結果とエラーを表示するには:
- 「プロジェクト」ウィンドウで、アプリケーションの「Web ページ」フォルダを右クリックし、「新規」>「JSP」を選択します。「新規 JSP」ウィザードが開きます。
- 「ファイル名」フィールドに「
composer」と入力します。「作成されるファイル」フィールドに、/web/composer.jsp で終わるパスが表示されるはずです。
- 「完了」をクリックします。ファイル
composer.jsp がエディタで開きます。「プロジェクト」ウィンドウの「Web ページ」フォルダに、このファイルのノードが表示されます。
composer.jsp 内のプレースホルダコードを次のコードで置き換えます。
<html>
<head>
<title>Composer Information</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body>
<table>
<tr>
<th colspan="2">Composer Information</th>
</tr>
<tr>
<td>First Name: </td>
<td>${requestScope.composer.firstName}</td>
</tr>
<tr>
<td>Last Name: </td>
<td>${requestScope.composer.lastName}</td>
</tr>
<tr>
<td>ID: </td>
<td>${requestScope.composer.id}</td>
</tr>
<tr>
<td>Category: </td>
<td>${requestScope.composer.category}</td>
</tr>
</table>
<p>Go back to <a href="index.jsp" class="link">application home</a>.</p>
</body>
</html>
- プロジェクトの「Web ページ」フォルダに、別の JSP ファイルを作成します。ファイルに
error.jsp という名前を付けます。
error.jsp 内のプレースホルダコードを次のコードで置き換えます。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Seach Error</title>
</head>
<body>
<h2>Seach Error</h2>
<p>An error occurred while performing the search. もう一度試してください。</p>
<p>Go back to <a href="index.jsp" class="link">application home</a>.</p>
</body>
</html>
スタイルシートの適用
これでアプリケーションの機能に必要なコードが完成しました。作業の結果を確認するため、今すぐアプリケーションを実行してみてください。
- 「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「実行」を選択します。プロジェクトが再コンパイルされ、ターゲットサーバーに配備されます。ブラウザが開き、index ページが表示されます。

アプリケーションにスタイルシートを適用するには、.css ファイルを作成し、プレゼンテーションページからそのファイルにリンクします。.css ファイルで作業する場合、IDE には、コード補完機能や、スタイルシート規則の作成に役立つほかのいくつかの機能が提供されています。これには次のものが含まれています。
- スタイル規則エディタ: クラス、ID、HTML 要素に基づいて規則を作成し、ドキュメント階層における位置を設定できるダイアログです。
- 「CSS プレビュー」ウィンドウ: 規則内にカーソルを置くと、その規則の宣言ブロックに従ってサンプルテキストが描画されるプレビューウィンドウです。
- CSS スタイルビルダー: 一連のコントロールやウィジェットを使用して規則を作成できるインタフェースです。
アプリケーションにスタイルシートを適用するには、次の手順に従います。
- 「プロジェクト」ウィンドウでプロジェクトノードを右クリックし、「新規」>「階層式スタイルシート」を選択します (「階層式スタイルシート」が表示されない場合は、「その他」を選択します。その後「新規ファイル」ウィザードで「Web」カテゴリから「階層式スタイルシート」を選択します)。
- 「CSS ファイル名」テキストフィールドに、「
stylesheet」と入力します。
- 「完了」をクリックします。CSS エディタ内を右クリックして「CSS の検査」を選択し、CSS コードの妥当性を検査します。
stylesheet.css に、次の規則を入力します。IDE のコード補完機能を利用するには、候補を呼び出したい場所で Ctrl- スペースキーを押します。
body {
font-family: Verdana, Arial, sans-serif;
font-size: smaller;
padding: 50px;
color: #555;
width: 650px;
}
h1 {
letter-spacing: 6px;
font-size: 1.6em;
color: #be7429;
font-weight: bold;
}
h2 {
text-align: left;
letter-spacing: 6px;
font-size: 1.4em;
color: #be7429;
font-weight: normal;
width: 450px;
}
table {
width: 550px;
padding: 10px;
background-color: #c5e7e0;
}
td {
padding: 10px;
}
a {
color: #be7429;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.popupBox {
position: absolute;
top: 170px;
left: 140px;
}
.popupCell {
background-color: #fffafa;
}
.popupCell:hover {
background-color: #f5ebe9;
}
.popupItem {
color: #333;
text-decoration: none;
font-size: 1.2em;
}
CSS エディタ内を右クリックして「CSS の検査」を選択し、CSS コードの妥当性を検査します。エラーがあった場合は「出力」ウィンドウ (「ウィンドウ」>「出力」) に表示されます。
- 「ウィンドウ」>「その他」>「CSS プレビュー」を選択し、「CSS プレビュー」ウィンドウを開きます。
- テキストと色を変更する規則内にカーソルを置きます (たとえば
h1)。「CSS プレビュー」ウィンドウに、テキストがブラウザにどのように描画されるかを示すサンプル表示が生成されます。

- ソースエディタで
index.jsp ページに切り替え、<head> タグの間にスタイルシートへの参照を追加します。
<link rel="stylesheet" type="text/css" href="stylesheet.css">
- スタイルシートで定義されている
popupBox クラスを complete-table 要素に追加します (ボールド部分が変更箇所)。
<tr>
<td id="auto-row" colspan="2">
<table id="complete-table" class="popupBox" />
<td/>
</tr>
stylesheet.css で指定されているように、この規則では、complete-table 要素が親要素の少し右に表示されるように配置されます。
プロジェクトの実行
アプリケーションを再実行すると、作成したスタイルシートを使用してブラウザに表示されます。文字を入力するたびに非同期の要求がサーバーに送信され、AutoCompleteServlet によって作成された XML データが返されます。さらに文字を入力すると、新しい一致リストを反映して作曲家の名前の数が減ります。
HTTP サーバーモニターの使用
IDE の HTTP サーバーモニターを使用して、要求と応答がクライアントとサーバーの間で受け渡されるときに実行される HTTP 通信を確認できます。HTTP サーバーモニターには、クライアントとサーバーのヘッダー、セッションプロパティー、Cookie の詳細、要求パラメータなどの情報が表示されます。
HTTP モニターを使用する前に、使用しているサーバーでモニターを有効にする必要があります。
- メインメニューから「ツール」>「サーバー」を選択して、「サーバー」ウィンドウを開きます。
- 左区画で、プロジェクトで使用しているサーバーを選択します。次に右区画で、「HTTP モニターを有効化」オプションを選択します。
注: このオプションは、GlassFish サーバーでは「共通」タブに表示されます。Tomcat では「接続」タブに表示されます。
- 「閉じる」をクリックします。
サーバーが実行中の場合、変更を有効にするにはサーバーを再起動する必要があります。サーバーを再起動するには、「サービス」ウィンドウを開き (「ウィンドウ」>「サービス」)、「サーバー」ノードの下で使用しているサーバーを右クリックし、「再起動」を選択します。
次にアプリケーションを実行すると、IDE の下部に HTTP モニターが開きます。左区画でレコードを選択し、メインウィンドウ内のタブをクリックすると、各要求に関する情報が表示されます。
ユーザーが自動補完フィールドに文字を入力したときに送信される非同期要求の結果としてサーバーから送信される XML データを確認できます。
- HTTP モニターの左側にあるツリー表示で、要求レコードを右クリックし、「再実行」を選択します。
応答がブラウザに生成されます。この場合、応答は XML データから構成されるので、ブラウザではデータがネイティブ XML ビューアで表示されます。
まとめ
これで Ajax 入門を終了します。Ajax は単に HTTP を使用してバックグラウンドで情報を交換し、その結果に基づいてページを動的に更新していることをおわかりいただけましたでしょうか。
ここで作成したアプリケーションは完全ではありません。たとえば、自動補完ボックスで作曲家の名前を選択しても何も起こりません。ソリューションプロジェクトをダウンロードし、JSP テクノロジを使用して、この処理を実装する方法を確認できます。また、ユーザーがデータストアにない名前を要求しないようにサーバー側で検査する方法を検討することもできます。これらの手法とテクノロジについては、「Java EE および Java Web の学習」にある、ほかのチュートリアルで紹介しています。
関連項目
netbeans.org での Ajax および Java テクノロジについての詳細は、次のリソースを参照してください。
|
|