mb_language("uni"); mb_internal_encoding("utf-8"); mb_http_input("auto"); mb_http_output("utf-8"); ?>
前回は、Eclipseを利用したJSP開発手順と、APIを利用してJSPからXprioriに接続しデータを取得する方法を紹介しました。表示したページは実用的なWebアプリケーションとは呼べないものでしたが、JSPからXprioriを利用する流れは理解していただけたのではないでしょうか。
今回からは、いよいよWebアプリケーションの実装を開始します。今回と次回で実装するページは、アイテム一覧画面とアイテム詳細画面です。それぞれ下記の機能をもっています。
● アイテム一覧画面
1. 登録したアイテムのID、名前の一覧を表示(今回)
2. 選択したアイテムの詳細ページに遷移(今回)
3. 1ページ20件ずつのページング処理(次回)
4. アイテムを名前で検索(次回)
5. 新規アイテム登録ページに遷移(第5回)
● アイテム詳細画面
1. 選択したアイテムのID、名前、郵便番号、住所を表示(今回)
2. アイテム編集、削除ページに遷移(第6回)
アイテム閲覧のために作成するクラスを紹介します。
クラス名 |
概要 |
Xpriori接続クラス (ConnectXprioriBean) |
Xprioriへ接続し、クエリーの送信をおこなうクラス |
アイテムクラス (ItemBean) |
item要素に対応するアイテムオブジェクトを扱うクラス |
検索クラス (SearchAddressbookBean) |
Xpriori接続クラスを利用して住所録に必要な情報を取得するクラス |
汎用クラス (AddressbookUtils) |
文字列からDOM Documentを取得する関数など、汎用的に使用する関数をまとめたクラス |
なお、各クラスでXMLを処理するときは、JavaからXMLを扱うためのDOM APIを使用しています。DOM APIを使用することで、XMLを文字列ではなく構造を持ったノードの集合として扱うことができます。
ConnectXprioriBeanは、APIのSessionManagedNeoConnectionクラスをラップしたクラスであり、Xprioriへの接続を行います。ConnectXprioriBeanを作成することで、Xprioriへ接続する度に、接続ロジックを記述する必要がなくなり、冗長なコードを減らすことができます。また、このクラスを通してのみXprioriに接続するのでデバッグもやりやすくなります。このクラスが持つ機能を紹介します。
● 接続(コンストラクタ)
ConnectXprioriBeanのコンストラクタ呼び出し時に、Xprioriへの接続を確立します。ConnectXprioriBeanクラスはメンバ変数として接続に必要な情報を保持しています。流れとしては、まずサーバ名とポート番号をAPIのSessionManagedNeoConnectionクラスのコンストラクタに渡しXprioriに接続します。次に、ユーザ名とパスワードをAPIのlogin関数に渡しXprioriにログインします。
public ConnectXprioriBean() { try {// Xprioriへの接続をおこなう neosession = new SessionManagedNeoConnection(server, port_num); } catch (Exception e) { System.out.println("接続に失敗しました:" + e); return; } try {// Xprioriへログインする sid = neosession.login(username, password); } catch (Exception e) { System.out.println("ログインに失敗しました:" + e); } } |
● クエリー送信(query)
必要なデータを取得するためのXPathを送信します。APIがもつqueryXML関数をラップします。
public String query(String xpath) { String ret = ""; try {// queryXMLをラップする ret = neosession.queryXML(xpath); } catch (Exception e) { System.out.println("エラーが発生しました: " + e); } return ret; } |
● 切断(logout)
APIのlogout関数を利用してXprioriからログアウトし、接続を解放します。
public void logout() { try {// ログアウトをする neosession.logout(); } catch (Exception e) { System.out.println("ログアウトに失敗しました:" + e); } } |
ConnectXprioriBeanクラスで利用したSessionManagedNeoConnectionクラスの関数を説明します。
● SessionManagedNeoConnection(java.lang.String host, int port)
引数hostにXprioriのサーバ名、引数portにポート番号を与え、Xprioriに接続します。
● login(java.lang.String user, java.lang.String password)
引数userにDB接続ユーザ名、引数passwordにパスワードを与え、Xprioriにログインします。
● queryXML( java.lang.String query )
引数queryにXPathを与え、Xprioriに対してデータ問い合わせを行います。戻り値は問い合わせ結果のXMLの文字列です。
● logout()
Xprioriからログアウトします。
ItemBeanは、Xprioriから取得した1件のアイテム情報を保持するためのクラスです。メンバ変数として、ID、名前、郵便番号、住所を保持しています。
● アイテム情報の設定(コンストラクタ)
ItemBeanのコンストラクタ呼び出し時にitem要素に対応するDOMのノードを渡し、そこからID属性、name要素、zip要素、address要素の値を取得します。ここではitem要素の子ノードを取得するのに、AddressbookUtilsクラスのgetChildNodeByTagName関数を用いています。これは指定した要素名を持つ子ノードを返す関数です。
public ItemBean(Node itemnode) { // IDを取得 this.setID(itemnode.getAttributes().getNamedItem("id").getNodeValue()); // 名前を取得 this.setName(AddressbookUtils.getChildNodeByTagName(itemnode,"name") .getFirstChild().getNodeValue()); // 郵便番号を取得 this.setZip(AddressbookUtils.getChildNodeByTagName(itemnode,"zip") .getFirstChild().getNodeValue()); // 住所を取得 this.setAddress(AddressbookUtils.getChildNodeByTagName(itemnode,"address") .getFirstChild().getNodeValue()); } |
SearchAddressbookBeanは、JSPから呼び出され、ConnectXprioriBeanやItemBeanを組み合わせてXPathを発行し、アイテムの情報を取得するためのクラスです。JSP自体に複雑なロジックを書いて、コードが煩雑になってしまうのを避けるため、SearchAddressbookBean中にメインのロジックを記述します。
● アイテムの総数を取得する(CountAllItem)
アイテム一覧画面で必要な機能です。登録されているアイテムの数を取得するXPath
count(/ND/address_book/item) |
をXprioriに問い合わせ、返って来たXML文字列を解析し、アイテム数を取得します。なお、XprioriはXPathの検索結果のルート要素として、常にQuery-Resultsという要素を挿入するため、その部分を読み飛ばすコードを含めています。また、検索結果のXML文字列からDOM Documentを得るため、XML文字列をDOM Documentに変換する、AddressbookUtilsクラスのloadXMLFromString関数を用いています。
public int CountAllItem() { // アイテム数の初期化 int item_num = 0; // アイテム総数を取得するXPath String xpath = "count(/ND/address_book/item)"; // 検索結果を取得する String tmpItem_xml = xcon.query(xpath); // XMLを解析する Document doc = AddressbookUtils.loadXMLFromString(tmpItem_xml); /* * 検索結果として * <?xml version="1.0" encoding="UTF-8" ?> * <Query-Results> * 100 * </Query-Results> * という改行(\n)が入った文字列が返ってるので、 * Query-Results要素の値から\nを取り除いた値を取得する */ Element element = (Element) doc.getElementsByTagName("Query-Results").item(0); String nodevalue = element.getFirstChild().getNodeValue().replace("\n",""); // 文字列から整数値にキャストする item_num = Integer.parseInt(nodevalue); return item_num; } |
● 指定数のアイテムを取得(getItems)
取得開始番号とオフセット値から、指定した範囲のitem要素を取得するXPath
/ND/address_book/item[position() >= {取得開始番号} and position() < ( {取得開始番号} + {オフセット値} )] |
を生成しXprioriに問い合わせます。position()は指定したノードの位置を返すXPathの関数です。返ってきたXML文字列中の複数のitem要素を1つずつ取り出し、そこからItemBeanオブジェクトを生成して指定数のアイテムを取得します。
public ItemBean[] getItems(int start, int offset) { // オフセット分のItemBean配列を定義する ItemBean[] items = new ItemBean[offset]; // 引数からXPathの条件をつくる String xpathCondition = "position() >= " + start + " and " + "position() < " + (start + offset); // 指定した範囲の位置iのitemノードを取得するXPathを問い合わせ検索結果を取得する String itemsXML = xcon.query("/ND/address_book/item[" + xpathCondition + "]"); // 検索結果XMLからDOM Documentを作成する Document doc = AddressbookUtils.loadXMLFromString(itemsXML); NodeList itemnodeList = doc.getElementsByTagName("item"); for (int i = 0; i < itemnodeList.getLength(); i++) { items[i] = new ItemBean(itemnodeList.item(i)); } return items; } |
● IDからアイテムを取得する
IDの値からitem要素を取得するXPath
/ND/address_book/item[@id = {IDの値}] |
をXprioriに問い合わせ、検索結果に含まれるitemノードからItemBeanオブジェクトを生成し、アイテムを取得します。
public ItemBean getItemById(String id) { // 引数idと同じID属性値を持つitemノードを取得するXPathを問い合わせ、 // 検索結果を取得する String itemXML = xcon.query("/ND/address_book/item[@id = " + id + "]"); // 検索結果XMLからDOM Documentを作成する Document doc = AddressbookUtils.loadXMLFromString(itemXML); // DOM Documentから先頭のitemノードを取り出しItemBeanを作成する ItemBean item = new ItemBean(doc.getElementsByTagName("item").item(0)); return item; } |
では、これらのクラスを利用してJSPを書いてみます。
● アイテム一覧画面(itemlist.jsp)
使用するクラスはSearchAddressbookBeanとItemBeanです。コードを以下に示します。
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS"%> <%-- インポートする --%> <%@page import="addressbook.ItemBean"%> <jsp:useBean id="searchxpri" class="addressbook.SearchAddressbookBean"></jsp:useBean> <% // (1)登録されているアイテムの数を取得する int item_count = searchxpri.CountAllItem(); // (2)全てのアイテムを取得する ItemBean[] itemlist = searchxpri.getItems(1,item_count); // Xprioriからログアウトする searchxpri.logout(); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>アイテム一覧</title> </head> <body> <center> <table width="400"><tr><td> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr><td><h3>登録アイテム一覧</h3></td></tr> </table> <table width="100%" border="0" cellspacing="0" cellpadding="3"> <tr><td width="1%" nowrap align="left"> <font size="4" color="#000fff"><b><%= item_count %></b></font>件</td></tr> </table> <table width="100%" border="1" cellspacing="0" cellpadding="3"> <tr> <th width="100">ID</th><th width="250">名前</th><th width="50">詳細</th> </tr> <% /* *(3)for文によるループでアイテム情報を表示する */ for(int i = 0; i < item_count;i++){ %> <tr> <td width="100" align="center"><%= itemlist[i].getID() %></td> <td width="250" align="center"><%= itemlist[i].getName() %></td> <td width="50" align="center"> <a href="/address_book/itemdetail.jsp?id=<%= itemlist[i].getID() %>">詳細</a></td> <% }%> </tr></table> </td></tr></table> </center> </body> </html> |
処理の流れを説明します。
(1)登録されているアイテムの総数を、SearchAddressbookBeanクラスのCountAllItem関数を利用して取得する。
(2)SearchAddressbookBeanクラスのgetItems関数を利用して、登録されている全てのItemBeanオブジェクトが格納された配列を取得する。
(3)取得した配列をfor文でループし、IDと名前、詳細ページへのリンクを表示する。
実行結果は以下のようになります。
▲アイテム一覧画面
● アイテム詳細画面(itemdetail.jsp)
使用するクラスは一覧画面と同様にSearchAddressbookBeanとItemBeanです。コードを以下に示します。
<%@ page language="java" contentType="text/html; charset=Shift_JIS" pageEncoding="Shift_JIS"%> <%@page import="addressbook.ItemBean"%> <jsp:useBean id="searchxpri" class="addressbook.SearchAddressbookBean"></jsp:useBean> <% // (1)パラメータからIDを取得する String id = request.getParameter("id"); // (2)IDからアイテムを取得する ItemBean item = searchxpri.getItemById(id); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <title>アイテム詳細</title> </head> <center> <table width="400"><tr><td> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr><td ><h3>登録アイテム詳細</h3></td></tr> </table> <form target="/address_book/inputitem.jsp" method="get"> <table width="100%" border="0" cellspacing="0" cellpadding="3"> <tr> <td width="1%" nowrap ></td> <td width="99%" align="right"><a href="/address_book/itemlist.jsp">一覧に戻る</a></td> </tr> </table> <%--(3)ItemBeanから、アイテムのID、名前、郵便番号、住所を取得し表示する --%> <table width="100%" border="1" cellspacing="0" cellpadding="3"> <tr><th>ID</th><td><%= item.getID() %></td></tr> <tr><th>名前</th><td><%= item.getName() %></td></tr> <tr><th>郵便番号</th><td><%= item.getZip() %></td></tr> <tr><th>住所</th><td><%= item.getAddress() %></td></tr> <tr><td colspan="2" align="center"> <input type="button" value="編集"> <input type="button" value="削除"> </td></tr> </table> </form> </td></tr></table> </center> </body> </html> |
処理の流れを説明します。
(1)パラメータidを取得する。
(2)SearchAddressbookBeanのgetItemById関数を利用して、idからItemBeanを取得する。
(3)ItemBeanから、アイテムのID、名前、郵便番号、住所を取得し表示する。
実行結果は以下のようになります。
▲アイテム詳細画面
このようにして、アイテム一覧画面とアイテム詳細画面を作成することができました。しかし、実用的なWebアプリケーションとしては、これだけでは十分とはいえません。アイテム一覧画面では、検索による絞込みを行うことができませんし、1ページに全てのアイテムを表示すると、スクロールが長くなってしまい、見にくい画面となってしまいます。
次回はアイテム一覧画面に検索機能とページング機能を追加する部分を紹介します。
今回紹介した、住所録アプリケーションを利用するにあたり、初期データのインポートが必要となります。第2回で紹介したサンプルデータは既に格納済みかと思いますが、第3回以降のために初期データ(inititem.xml)を用意しました。XMS Consoleを利用して、Database AccessのStore画面から初期データのインポートを行ってください。なお、初期データの中にはaddress_book要素の最初の子要素としてdummy要素が存在しますが、これはユーザには見えない要素で、住所録が持つ何かの情報をあらわしているものではありません。第5回で紹介する、アイテム登録の実装時に必要な要素となります
今回作成したjavaクラス・jspファイルはこちらからダウンロードすることができます。
・ jspファイルはWebアプリケーションフォルダのaddress_book/WebContentに配置してください。
・ javaファイルはWebアプリケーションフォルダのaddress_book/WebContent/WEB-INF/srcに配置してください。
また、ご自分でクラスを新規作成する場合はEclipseのメニューバーより、[ファイル]→[新規]→[クラス]を選択し、[次へ]を押してください。
次の画面で[ソースフォルダ]に「address_book/src」、[パッケージ]に「addressbook」を入力し、[名前]に適切なクラス名を入力し、[終了]を押すことで、新規のクラスを作成することができます。
▲このページのTOPへ