|
Ajaxでリアルタイム検索結果表示の
インクリメンタルサーチを作ろう
〜 連載 「開発マネージャーのMyEclipse指南塾」 第5回 〜 |
今回から商品の検索機能を追加していきます。「インクリメンタルサーチ」と呼ばれるAjaxを活用した検索機能を使って、スムーズな商品検索を実現してみます。Ajaxの開発にはMyEclipseのAjax開発機能を用い、非常に効率よく開発できることを確認します。
前回(第4回)については日本語MyEclipseポータルサイトで |
第4回「ショッピングカートを作ろう」の主な内容
・組み込みデータベースDerbyとは
・購入商品を格納するデータベースの作成
・カート商品情報検索用のユーティリティメソッドの追加
・ショッピングカートの実装
|
|
|
Ajaxを使った検索機能
「インクリメンタルサーチ」とは |
|
今回から商品の検索機能を作っていきます。単純に文字列で検索するのではなく、「インクリメンタルサーチ」と呼ばれる検索機能を実装します。インクリメンタルサーチは、Ajaxを活用しリアルタイムに検索結果を表示するものです。
通常のWebアプリケーションだと、文字列の入力フォームを作り、送信ボタンをクリックすると、サーバ側で検索し、検索結果を表示します。Ajaxを利用すれば、入力フォームに入力途中の段階から検索を実行し、即座に検索結果を表示できます。
Google Suggestや、Googleツールバーでは、入力中の文字列に合わせてリアルタイムに候補の文字列が出てきますが、それに似たイメージだとお考えください。
完成時の画面イメージを以下に示します。
|
画面 作成するインクリメンタルサーチの画面 |
Ajax開発では、開発言語のJavaScriptが非常に手軽で誰もがなじみやすい反面、Webブラウザ間での互換性がなかったり、エラーに関する情報が乏しかったりという現状があります。さらには、通信が関わってくるため、どの段階で不具合が発生しているのか追及するのも大変です。読者の皆さまにもJavaScriptのデバッグで苦労した経験をお持ちの方がいらっしゃると思います。
ところでMyEclipseは、Ajax開発のサポート機能が非常に充実しています。Ajax開発のさまざまな悩みを解決し、非常に効率的に開発できる機能が備わっています。本記事では、それらの機能を実際に使いながら、Ajax開発におけるMyEclipseのメリットを紹介していきたいと思います。
|
|
インクリメンタルサーチの設計 |
|
では、インクリメンタルサーチをどういう方針で実装するかを考えていきましょう。
■ リアルタイムに検索を実行する方法
リアルタイムに検索を実行するには、まずJavaScriptの関数をリアルタイムに実行する必要があります。JavaScriptの関数をリアルタイムに実行するには2通りの方法が考えられます。
1つ目の方法は関数をタイマーで実行する方法です。JavaScriptでは、「setInterval」メソッドを使うと一定の間隔で関数を呼び出すことができます。常に入力フォームに入力されたものをチェックし、何か入力されたらAjaxでサーバの検索メソッドを呼び出します。
2つ目の方法はキーボード入力を検知する方法です。入力フォームのタグに「onkeyup」属性でJavaScript関数を指定すると、キーボード入力があったときにその関数が実行されます。
なお、キーボード入力に関する属性には、ほかに「onkeydown」と「onkeypress」があります。いずれもキーボードを押した瞬間にイベントが発生します。厳密には、文字が実際に入力されるのはキーボードを押して離した後になります。従って、「onkeyup」属性を使うのが最も適しています。
システムリソースのことを考えると、2つ目の方法の方がキー入力があったときだけしか実行しないので無駄がありません。1つ目の方法は何もしていないときでも常に関数を実行し続けているので、うまく作らないとWebブラウザを開いているだけでクライアントマシンに負荷を掛けることになってしまいます。
ところが、今回のアプリケーションでは2つ目の方法は適していません。例えば、「abcd」という文字列で検索をしたい場合を考えます。「onkeyup」属性だと、1文字入力するごとに検索が実行されるため、「abcd」とキー入力すると「a」「ab」「abc」「abcd」という4種類の文字列で検索が実行されます。
しかし、画面に表示するのは「abcd」の検索結果だけでよいはずです。「abcd」の入力に0.5秒掛かるとしたら、setIntervalで1秒ごとに検索が実行されるようにしておけば、無駄に何度も検索が実行されるのを防げるはずです。従って、今回は1つ目のタイマーを使う方法を選択することにします。
■ Ajaxライブラリの活用
Ajaxを実装する場合、Webブラウザごとの動作の違いに対応する必要があり、コードが複雑になってしまいます。こういった問題を解決して効率的に開発できるようにするライブラリやフレームワークが多数提供されています。
代表的なところでは「Prototype」「script.aculo.us」「Dojo」「Rico」などが挙げられます。これらはすべてクライアント側の開発のみをサポートしています。サーバ側の開発をサポートするものとしては「jMaki」や「DWR」などがあります。
これらはそれぞれサポートする範囲も異なり、単純にどれが一番良いと決められるものではありません。開発案件に必要な機能や環境、開発者のスキルなどに応じて適したものを選択しましょう。
ここでは、基本的なAjaxライブラリの1つ「Prototype」を利用します。PrototypeはAjaxに限らずJavaScriptのコーディングを簡易にしたり拡張したりするライブラリです。例えば「document.getElementById()」という関数を短く記述できるようにしたり、JavaScriptのクラス機能を拡張します。ほかのAjaxライブラリでもベースとしてPrototypeを使っているものがあります。
■ 全体の構成
全体としては以下のようなものを作ればよいでしょう。
- (a)入力フォームと検索結果のJSP
<keywordsearch.jsp>
検索結果の部分は空の<div>タグを用意しておくだけになります。
- (b)タイマーで呼び出すJavaScript関数
<keywordsearch.js>
入力フォームの内容をチェックし、入力されていたら入力値をサーバ側のJSPにリクエストします。
- (c)JavaScript関数から呼び出すサーバ側の検索JSP
<keywordsearch_Ajax.jsp>
requestからフォームの入力値を読み取り、検索を実行し、画面に出すタグを生成します。生成されたHTMLが(a)の<div>タグに流し込まれるイメージです。
- (d)検索JSPから呼び出すWebサービス検索メソッド
< AWSECommerceServiceClient # findByKeyword() >
Webサービスで検索を実行するにはややコードが煩雑になるので、ユーティリティメソッドとしてまとめます。AWSECommerceServiceClient.javaに追加します。
処理の流れとしては以下のようになります。
- ユーザーが検索ページにアクセスする
- 検索ページの描画が終わると(onload)、タイマーで関数が実行されるように設定される(setInterval)(a)
- 関数が一定間隔で実行され、フォームの入力値をチェックする(b)
- ユーザーが検索フォームに文字を入力する
- フォームの入力値が変化したので、その入力値を検索JSPに送信する(b)
- 検索JSPはrequestから入力値を取得し、AWSECommerceServiceClientのWebサービス検索メソッドを呼び出す(c)
- AWSECommerceServiceClientはAmazonのWebサービスを呼び出す(d)
- Amazonから検索結果が返ってくる
- AWSECommerceServiceClientは検索結果の必要な部分だけを取り出して検索JSPに返す(d)
- 検索JSPは検索結果のデータをHTMLに整形しJavaScript関数に返す(c)
- JavaScript関数は検索ページに検索結果のHTMLを挿入する(b)
|
図 各プログラムの処理の流れ(画像をクリックすると拡大します) |
続きは日本語MyEclipseポータルサイトでもご覧いただけます |
第5回の残りの主な内容
・インクリメンタルサーチの実装
検索ユーティリティメソッドの作成
検索結果を表示するJSPの作成
キーワード検索ページ全体のJSPの作成
第6回「MyEclipse JavaScriptエディタでJavaScriptを開発しよう」の主な内容
・Ajaxライブラリ「Prototype」の組み込み
・JavaScriptファイル「keywordsearch.js」の作成
・アウトライン・ビュー
・JavaScriptソースの検証
・コードの整形
・アプリケーションの動作確認
・バグ発見!!
|
|
|
インクリメンタルサーチの実装 |
|
それでは、実際に検索機能を実装していきましょう。
ところで、連載第3回の「MyEclipse ビジュアルJSPデザイナーで商品ページを作ろう」では、Webサービスを使って商品データを取得する機能をユーティリティメソッドとして切り出し、AWSECommerceServiceClient.javaに追加ました。ここでも同様に、文字列検索のメソッドをAWSECommerceServiceClient.javaに追加しましょう。
■ 検索ユーティリティメソッドの作成
以下のコードをAWSECommerceServiceClient.javaに追加します。最後の「}」の手前に挿入してください。
public static java.util.List<HashMap> findByKeyword(
String keyword) {
return findByKeyword(keyword, null);
}
public static java.util.List<HashMap> findByKeyword
(String keyword,String browseNode) {
AWSECommerceServiceClient client
= new AWSECommerceServiceClient();
AWSECommerceServicePortType service = client
.getAWSECommerceServicePort();
ItemSearch itemSearch = new ItemSearch();
itemSearch.setAWSAccessKeyId(accessKeyId);
ItemSearchRequest itemSearchRequest
= new ItemSearchRequest();
itemSearchRequest.setSearchIndex("HealthPersonalCare");
itemSearchRequest.setMerchantId("A1GZVRP0NRRC2W");
if (browseNode != null) {
itemSearchRequest.setBrowseNode(browseNode);
}
itemSearchRequest.setKeywords(keyword);
java.util.List<String> responseGroups
= itemSearchRequest.getResponseGroup();
responseGroups.add("Medium");
java.util.List<ItemSearchRequest> requests
= itemSearch.getRequest();
requests.add(itemSearchRequest);
ItemSearchResponse itemSearchResponse
= service.itemSearch(itemSearch);
java.util.List<Items> itemsList
= itemSearchResponse.getItems();
java.util.List<HashMap> shouhinList
= new LinkedList<HashMap>();
for (Items items : itemsList) {
java.util.List<Item> itemList = items.getItem();
for (Item item : itemList) {
HashMap shouhin = new HashMap();
shouhin.put("asin", item.getASIN());
if (item.getSmallImage() != null) {
shouhin.put("image",
item.getSmallImage().getURL());
}
shouhin.put("price", item.getOfferSummary()
.getLowestNewPrice().getFormattedPrice());
ItemAttributes itemAttributes
= item.getItemAttributes();
shouhin.put("shouhinmei", itemAttributes.getTitle());
shouhinList.add(shouhin);
}
}
return shouhinList;
} |
Amazon Webサービスのキーワード検索では、カテゴリー検索と同じくItemSearchクラスを使用します。カテゴリー検索の場合は、ItemSearchRequestオブジェクトにsetBrowseNode()メソッドでbrowseNodeを指定しましたが、キーワード検索の場合はsetKeywords()メソッドでキーワード文字列を指定します。
setKeywords()メソッドを使用した場合、ヒットする商品や結果のソート順は、Amazonのサイトでキーワード検索を行った場合と同様の結果が得られます。
■ 検索結果を表示するJSPの作成
続いてJavaScriptから呼び出され、先ほどの検索メソッドを使って商品データを検索し、検索結果のHTMLを返すJSPを作成します。
WebRootの下に新規にJSPファイルを作成します。[JSP(拡張テンプレート)]を指定し、ファイル名は「keywordsearch_Ajax.jsp」とします。このJSPはHTML全体の中の一部分になるところなので、自動的に作成されるテンプレート部分はすべて削除し、以下のコードに入れ替えます。
<%@ page language="java" import="java.util.*,com.oisix.myeclipse.*" pageEncoding="Shift_JIS"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
request.setCharacterEncoding("SJIS");
String keyword = request.getParameter("keyword");
List<HashMap> shouhinList
= AWSECommerceServiceClient.findByKeyword(keyword);
request.setAttribute("shouhinList", shouhinList);
%>
<c:forEach var="shouhin" items="${shouhinList}">
<div style="border-bottom-style: dotted; border-width: 2px;
border-color: gray; padding-top: 5px;">
<c:if test="${!(empty shouhin['image'])}">
<img src="<c:out value="${shouhin['image']}" />"
style="float: left;" />
</c:if>
<c:out value="${shouhin['shouhinmei']}" />
<c:out value="${shouhin['price']}" />
<br/>
<form action="cart.jsp" method="post">
<input type="hidden" name="asin"
value="<c:out value="${shouhin['asin']}" />" />
<input type="submit" value="お買い物かごに入れる" />
</form>
<br style="clear: left;" />
</div>
</c:forEach> |
requestからキーワードを取得し、先ほど作ったfindByKeyword()メソッドを呼び出しています。後の表示部分は商品ページと同様です。<html><body>といったタグがなく、直接<div>タグから始まっているところがポイントです。
このJSPは正式なHTMLではありませんが、表示をテストできます。[MyEclipse Webブラウザー]を開いて、以下のURLにアクセスしてみましょう。
http://localhost:8080/myeclipse-sample/keywordsearch_Ajax.jsp?keyword=oisix |
商品がいくつか表示されれば成功です。
なお、このJSPのみエンコーディングを「Shift_JIS」と指定しています。本連載では基本的にエンコーディングは「windows-31j」を指定していますが、Ajaxのレスポンスのcharsetがwindows-31jとなっていると、Internet Explorer 6.0では動作しないのでご注意ください。
■ キーワード検索ページ全体のJSPの作成
続いて、キーワード検索ページ全体のJSPを作成します。
WebRootの下に[JSP(拡張テンプレート)]で「keywordsearch.jsp」というファイル名でJSPを新規に作成します。
1行目のpageEncodingが「Windows-31J」になっていることを確認します。
もし「Windows-31J」以外のエンコーディングが指定されている場合は、以下のように変更します。
<%@ page language="java" import="java.util.*"
pageEncoding="windows-31j"%> |
20行目のstyles.cssの上と下の行のコメントアウト(<!-- -->)を行ごと削除します。以下のようになります。
<link rel="stylesheet" type="text/css" href="styles.css"> |
その下にJavaScriptファイル読み込み用のタグを2行追加します。
<script type="text/javascript" src="prototype.js" ></script>
<script type="text/javascript" src="keywordsearch.js" ></script> |
<body>から</body>までの間を以下のように変更します。
<body>
<jsp:include flush="true" page="header.jsp"></jsp:include>
<form name="searchform">
キーワードを入力してください。<br/>
<input type="text" size="50" name="searchword"
id="searchword" />
</form>
<div id="result">
</div>
</body> |
以上で完成です。これでJavaScript以外の部分はすべて作成されました。
次回はJavaScriptエディタの紹介をしつつ、Ajax部分のJavaScriptを開発していきます。
続き(第6回)は日本語MyEclipseポータルサイトで |
第6回「MyEclipse JavaScriptエディタでJavaScriptを開発しよう」の主な内容
・Ajaxライブラリ「Prototype」の組み込み
・JavaScriptファイル「keywordsearch.js」の作成
・アウトライン・ビュー
・JavaScriptソースの検証
・コードの整形
・アプリケーションの動作確認
・バグ発見!!
|
※本記事は、日立製作所の『日本語MyEclipseポータルサイト』に掲載された記事を許諾を得て、再構成したものです。
提供:株式会社 日立製作所
企画:アイティメディア 営業局
制作:@IT編集部
掲載内容有効期限:2008年3月31日 |