広告 |
---|
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 2010年02月21日 Java総合講座 - 初心者から達人へのパスポート vol.192 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:毎週日曜の夜に発行 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:毎週水曜の夜に発行 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ======================================================== ◆ 01.Strutsのアプリケーション開発 ======================================================== さて、前回までで、(U-1)〜(U-3)まで(vol.188参照)の部分をコーディングし、 動作を確認しました。 このとき、一番最初に開くitemSelect.jspのWebページにおいて、カテゴリーの欄 がありましたが、カテゴリーをユーザーに手入力させることに違和感を感じた人 もいるのではないでしょうか。 そもそもカテゴリーはデータベース上に、決まった小数のもの(具体的には 食品、雑貨、文具の3つ)が登録されているだけです(vol.189参照)。 それなら、予めカテゴリー名のリストを画面上に表示しておいて、そのリストから 選択させるような形式にしてあげたほうが親切で簡単ではないか、と思った人も いることと思います。 そこで、itemSelect.jspのWebページにおいて、カテゴリーをリストから選択 する形式に変更してみましょう。 リストするカテゴリー名としては、データベースから取り出したものを使用する こととします。 (データベースとは関係なく直接JSPファイル上にカテゴリー名を書いておく という方法もありますが、そうすると、カテゴリー名に変更があった場合に データベースとJSPファイルの複数個所で重複して修正が必要になり、煩雑 かつ修正ミスの原因にもなりかねません。というわけで、このようなやり方 は好ましくありません。) ただし、itemSelect.jspのWebページを表示するたびに毎回データベースから 読み取るのでは、コンピューター資源の無駄使いになってしまいますので、 最初に一回読み取ったら、その後はそれらをずっと使い続けることにします。 さて、どのように変更すればいいと思いますか? 説明にはいる前に、自分で一寸考えてみて下さい。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ では、典型的なやり方をお話しましょう。 まず、ActionFormのreset()メソッドは、対応するFORMを含むJSPのWebページが クライアント(Webブラウザー)のコンピューターに送られる前に実行される ということを頭に入れておいて下さい。 そうすると、このreset()メソッドの中で、データベースからカテゴリー名のリスト を取り出す作業を行っておき、取り出したリストをWebページ(JSPファイル)の FORM上に組み込んでおけばいいわけです。 そうすれば、そのWebページがWebブラウザー上に表示されるときには、カテゴリー名 のリストが表示されることになります。 ただし、カテゴリー名のリストはデータベースから1回取り出したら、以後はそれを ずっと使い続けるような仕組みにしなければなりません。 このようなときに使えるのがapplicationスコープです。 1回取り出したカテゴリー名のリストは、applicationスコープに保管しておけば、 以後そのWebアプリケーション内でずっと保持し続けられますので、ずっと使い 続けることができます。 では、ItemSelectForm.javaを下記のように編集しましょう。 -------------------------------------------------------- package jp.co.flsi.lecture.struts; import java.io.UnsupportedEncodingException; import java.util.Vector; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import jp.co.flsi.lecture.struts.db.Category; import jp.co.flsi.lecture.struts.db.CategoryDbManager; import jp.co.flsi.lecture.struts.db.StruShopDbException; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionMapping; public class ItemSelectForm extends ActionForm { private static Logger logger = Logger.getLogger(ItemSelectForm.class); private String keyword = null; // private String category = null; private String categoryNum = null; public void reset(ActionMapping mapping, HttpServletRequest request) { logger.info("Start ..............."); CategoryDbManager dbManager = new CategoryDbManager(); try { request.setCharacterEncoding("UTF-8"); ServletContext serv = getServlet().getServletContext(); Vector<Category> categoryList = (Vector<Category>) serv.getAttribute("categoryList"); if (categoryList == null) { dbManager.connect(); categoryList = dbManager.getDataByName(""); serv.setAttribute("categoryList", categoryList); } } catch (UnsupportedEncodingException e) { logger.error(e, e); } catch (StruShopDbException e) { logger.error(e, e); } finally { try { dbManager.disconnect(); } catch (Exception e) { logger.info("Disconnect failed or there is no connection."); } logger.info("End ..............."); } } public void setKeyword(String keyword) { this.keyword = keyword; } public String getKeyword() { return keyword; } // public void setCategory(String category) { // this.category = category; // } // public String getCategory() { // return category; // } public void setCategoryNum(String categoryNum) { this.categoryNum = categoryNum; } public String getCategoryNum() { return categoryNum; } } -------------------------------------------------------- 上記のソース・コードのうち ServletContext serv = getServlet().getServletContext(); によって取り出したserv(ServletContextオブジェクト)に対して serv.getAttribute("categoryList"); や serv.setAttribute("categoryList", categoryList); を実行していることに注意してください。 これらが、applicationスコープからオブジェクト(bean)を取り出したり、 保管したりする操作(定石的なやり方)です。 上記のソースコードでは、すでにapplicationスコープにカテゴリーのリストを 保管済みの場合は Vector<Category> categoryList = (Vector<Category>) serv.getAttribute("categoryList"); という行でそれを取り出して使用し、まだ保管されていない場合は代わりに categoryListにnullが返ってくるので、その場合は categoryList = dbManager.getDataByName(""); という行でデータベースにアクセスしてカテゴリーのリストを取り出し、categoryList に代入したあと、applicationスコープに保管しています。 (データベースの処理をしているところは、いつものパターンなので説明を 省略します。) なお、上記のソース・コードでは、プロパティーの名前をcategoryから categoryNumに変更していることにも注意して下さい。これは、あとでJSP側 を変更するときにWebページからカテゴリー名ではなくカテゴリーの番号を 受け取るように変えるために、それに対応して改名したものです。 ┌補足─────────────────────────┐ 「わざわざプロパティー名を変える必要はないんじゃないか。 カテゴリー番号でもそのままcategoryというプロパティー名を 使えばいいじゃないか。」と思うかもしれませんが、オブジェ クト指向プログラミングにおいては、名前はとても大切で、その 意味にふさわしい名前にすべきなのです。 その意味を的確に表現する名前にしておくことは、プログラム がわかりやすくなるだけでなく、プログラミング・ミスの減少 にもつながります。 そして、プロパティーの名前を変えるということは、そのsetter やgetterメソッドの名前も変えることを意味します。 上記のソース・コードの中で変数名、setterメソッド名、getter メソッド名すべて変えていることに注意して下さい。(比較でき るように以前のプロパティーに関する行はコメント(//)にして 残してあります。) このように、扱う対象をカテゴリー名からカテゴリー番号に変更 したことに対応してプロパティー名を変更しておくと、それを 参照している他のプログラムが影響を受ける場所も明確になり ます。 たとえば、ItemListActionクラスの中でこのプロパティーを参 照していたところがエラー(コンパイラーがエラーを見つけて くれる)になるので、変更すべきところが明確になりますね。 └───────────────────────────┘ なお、このソースコードをEclipseに入力すると、 Vector<Category> categoryList = (Vector<Category>) serv.getAttribute("categoryList"); の行に警告のマーク(橙色のアンダーラインがつく)が付くことと思います。 これは、以前もお話したように(Vector<Category>)というような複雑なキャストの 妥当性はコンパイラーではチェックできないからです。 というわけで、この警告は(本人が正しいコーディングをしていると確信して いれば)気にしなくていいものです。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ 続いて、itemSelect.jspを下記のように編集しましょう。 -------------------------------------------------------- <%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="/tags/struts-bean" prefix="bean" %> <%@ taglib uri="/tags/struts-logic" prefix="logic" %> <%@ taglib uri="/tags/struts-html" prefix="html" %> <%@ taglib uri="/tags/struts-nested" prefix="nested" %> <html:html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>商品の検索</title> </head> <body bgcolor="#77ffff" text="#fa5a00"> <h1>商品の検索</h1> <html:form method="POST" action="/itemlist"> キーワード(商品名の一部)やカテゴリーを入力し、「商品検索」ボタンをクリックしてください。 <br> <br> キーワード:<html:text property="keyword" size="20" /> <br> カテゴリー: <html:select property="categoryNum"> <html:options collection="categoryList" property="num" labelProperty="name" /> </html:select> <br> <br> <html:submit property="submit" value="商品検索" /> </html:form> </body> </html:html> -------------------------------------------------------- どこを編集したかというと、 <html:text property="category" size="20" /> だったところを <html:select property="categoryNum"> <html:options collection="categoryList" property="num" labelProperty="name" /> </html:select> に書き換えていますね。 この部分も新しく出てきたタグなので解説しておきましょう。 まず、<html:select>というタグは、vol.178に出てきた<select>タグに相当する Struts専用のタグで、</html:select>との間に囲まれたオプションをリストして 表示するものです。 そのオプションはvol.178では<option>というタグを複数並べてリストしていました が、それに相当するStruts専用のタグとして、ここでは<html:options>というタグ を使用しています。(このようにStrutsを使うと随分と簡単なコードで済んでしまう ことが分かりますね。) 具体的には、 <html:options collection="categoryList" property="num" labelProperty="name" /> という指定をしていますが、ここではcollectionという属性に、先ほどItemSelectForm の中でapplicationスコープに保管しておいた"categoryList"を指定していることに注意 して下さい。このcategoryListはVector型のコレクションでしたから、このオブジェ クトは複数の要素を含みます。 html:optionsタグは、指定されたコレクションの複数の要素をリストするという機能を 持っているので、optionsというようにoptionの複数形のタグ名になっているのです。 あと、property属性とlabelProperty属性には、そのコレクションの要素のプロパティー を指定します。 このうちproperty属性に指定したものが値として使われ(Webブラウザー上でユーザー がその項目を選択すると、サーバー側へはそのproperty属性に指定された値が送られる ことになる)、labelProperty属性に指定したものは実際にWebブラウザー上でリストの 中に表示されるものになります。 categoryListの中の要素はCategory型のオブジェクトで、Categoryにはnumという プロパティー(getNum()メソッドで取得できる)とnameというプロパティー(getName() メソッドで取得できる)がありましたね。これらを上記のproperty属性とlabelProperty 属性に指定しているわけです。 さて、先ほどの<html:select>タグのproperty属性には"categoryNum"という値が指定 されていましたが、このcategoryNumがItemSelectFormのcategoryNumプロパティー を表します。 そして、このリストの中で選択された項目のnumプロパティー(Categoryオブジェクト のnumプロパティー)の値がこのcategoryNumプロパティーの値としてItemSelectForm オブジェクトにセットされることになるのです。 (文章だけで説明すると頭が混乱しそうですが、各ソース・ファイルを見比べていけば 用意に理解できることと思います。) ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ では、今度は、このItemSelectFormのデータを受け取って処理するItemListAction のほうも変更しましょう。 ItemListActionのエディターを開いてみると、先ほどItemSelectFormの中で行った変更 に対応してエラーになっている部分がありますね。その部分を修正しておきましょう。 下記のように編集して下さい。 -------------------------------------------------------- package jp.co.flsi.lecture.struts; import java.util.Vector; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jp.co.flsi.lecture.reflect.ValueLogStringMaker; import jp.co.flsi.lecture.struts.db.Item; import jp.co.flsi.lecture.struts.db.ItemDbManager; import jp.co.flsi.lecture.struts.db.StruShopDbException; import org.apache.log4j.Logger; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class ItemListAction extends Action { private static Logger logger = Logger.getLogger(ItemListAction.class); public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { logger.info("Start ..............."); ValueLogStringMaker stringMaker = new ValueLogStringMaker(); logger.info("Method parameter: <<<<<" + stringMaker.getValues("mapping", mapping)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("form", form)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("request", request)); logger.info(">>>>>"); logger.info("Method parameter: <<<<<" + stringMaker.getValues("response", response)); logger.info(">>>>>"); ItemSelectForm itemSelectForm = (ItemSelectForm) form; ItemDbManager itemDbManager = new ItemDbManager(); try { itemDbManager.connect(); Vector<Item> itemList = null; itemList = itemDbManager.getDataByItemNameAndCatNum(itemSelectForm.getKeyword(), itemSelectForm.getCategoryNum()); request.setAttribute("itemList", itemList); } catch (StruShopDbException e) { logger.error(e, e); } catch (Throwable e) { logger.error(e, e); } finally { try { itemDbManager.disconnect(); } catch (Exception e) { logger.info("Disconnect failed or there is no connection."); } logger.info("End ..............."); } logger.info("Method return: <<<<<" + stringMaker.getValues("mapping", mapping)); logger.info(">>>>>"); return mapping.findForward("success"); } } -------------------------------------------------------- どこをどう修正したか分かりますね。 ヒント:引数が変わると、その引数を使用するメソッドもその引数にふさわしいものに なっているかどうか確認する必要があります。 ここでは変更後の引数も以前と同じStringという型なので、その引数を使用するメソッド がエラーになることはありませんが、メソッド名がその引数にふさわしい名前かどうか 見てみるとメソッドも変更する必要があることがわかります。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ では、各ファイルの修正&保管が終わったら、再度このWebアプリケーション (Strutsのアプリケーション)を実行してみましょう。 (1) 「サーバー」ビューの中の「ローカル・ホストのTomcat v5.5サーバー」を 右クリックし、「開始」を選択します。しばらくして、 ローカル・ホストのTomcat v5.5サーバー[始動済み,同期済み] というように、後ろに「始動済み」の表示が出たら、Tomcatの起動が完了しています。 (2) Webブラウザー(Internet Explorer)を起動して、URL http://localhost:8080/StrutsShop/itemSelect.jsp を入力しましょう。 どうですか。「カテゴリー」欄が選択式(三角形ボタンをクリックするとリストが 表示されますね)に変わった以外は、前回と同様に動作しますね。 これで、「カテゴリー」欄の入力が楽になりました。 では続いて、(U-3)〜(U-5)までの部分をコーディングしましょう。 ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ (次回に続く) では、今日はここまでにします。 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: http://www.flsi.co.jp/Java_text/ ★このメールマガジンは 「まぐまぐ(http://www.mag2.com)」 を利用して発行しています。 ★バックナンバーは http://www.flsi.co.jp/Java_text/ にあります。 ★このメールマガジンの登録/解除は下記Webページでできます。 http://www.mag2.com/m/0000193915.html ★このメールマガジンへの質問は下記Webページにて受け付けて います。わからない所がありましたら、どしどしと質問をお寄 せください。 http://www.flsi.co.jp/Java_text/ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製 |