商品データ(商品XML)検索処理
画面遷移
商品情報 検索・一覧表示の画面遷移を以下の図に示します。
「商品情報 新規登録」画面は、商品一覧の「商品名検索」テキストボックスに商品名を入力し「検索」ボタンを押下することによって、商品名に該当する商品の一覧が表示される画面です。
「商品情報一覧」画面の初期表示処理は、ただ単にJSPを表示するだけですので、説明は割愛し「検索」ボタンが押下された場合のXMLデータ検索処理について説明します。
コントローラ(ItemCRUDServlet)
コントローラとなるサーブレットでは、HTMLから「action="read"」というパラメータを受け取り、以下の順に処理を実行します。
- ItemDaoの
findByItemName
メソッドを呼び出す - リクエスト属性に検索結果のListを保存する
- 商品一覧画面(list.jsp)にForwardする
以下にItemCRUDServletのソースを示します。
}else if (action.equals("read")) { // 【商品検索】→一覧表示 List itemList = null; try { // 検索処理 itemList = itemDao.findByItemName( req.getParameter( "item_name" ) ); } catch (Exception e) { e.printStackTrace(); forwardToErrorPage(req, res); return; } req.setAttribute("itemList", itemList); forwardToJSP(req, res, "list.jsp");
Daoクラス
ItemDaoImplクラス
次にサーブレットから呼ばれるItemDaoImplクラスの実装を説明します。ItemDaoImplクラスのfindByItemName
メソッドでは、以下の順でXQueryを実行しています。
- XQueryのテンプレートファイルで変換するパラメータをMapで作成
- LuxeonDaoクラスの
executeXQuery
メソッドを呼び出し、XQueryを実行 - XQueryの実行結果(List)を戻す
以下にItemDaoImplクラスのfindByItemName
メソッドのソースを示します。
public List<Object> findByItemName(String itemName) throws IOException,JAXBException,Exception{ Map<String, Object> templeteMap = new HashMap<String, Object>(); Item item = new Item(); item.setItemName( itemName ); templeteMap.put( "item" , item ); return LuxeonDao.executeXQuery( "items/item_container.bnd" , TEMPLATE_RESOURCE_PATH + "Item_findByItemName.vm" , templeteMap , Item.class ); }
LuxeonDaoクラス
次に、ItemDaoImplクラスのfindByItemName
メソッドから呼ばれるLuxeonDaoクラスのexecuteXQuery
メソッドを説明します。ここでは、以下の順でXQueryを実行しています。
- セッション、XMLStore、検索対象XML(バインダドキュメント)を順に取得
- Velocityを使用してXQueryのテンプレートとオブジェクト値をマージしてXQueryの文字列を取得
- XQueryの実行
- XQueryの実行結果(NodeList)をJAXBを使用してItemクラスのListに変換して戻す
- セッションを閉じる
以下にLuxeonDaoクラスのexecuteXQuery
メソッドのソースを示します。
public static List<Object> executeXQuery( String xmlName, String templateName,Map<String, Object> templateObjMap , Class clazz ) throws IOException,JAXBException,Exception{ Session clientSession = null; try { // XMLストア clientSession = XlnClientSessionFactory.getSession(); XMLStore xmlStore = clientSession.getXMLStore(XML_STORE_NAME); // バインダドキュメントの取得 XMLDocument xmlDoc = (XMLDocument)xmlStore.getFile(xmlName); // XQuery文字列生成 VelocityWrapper vw = new VelocityWrapper(); vw.put( templateObjMap ); String xqueryStr = vw.merge( templateName ); // XQuery実行 XQuery xQuery = clientSession.createXQuery( xqueryStr ); xQuery.execute(xmlDoc); // XQuery結果の取得 XQuerySequence results = xQuery.getResults(); XQuerySequenceIterator iter = results.getIterator(); JAXBContext jc = JAXBContext.newInstance( clazz ); Unmarshaller u = jc.createUnmarshaller(); // JAXB XMLデータ(Node)→オブジェクト変換 List<Object> list = new ArrayList<Object>(); while( iter.hasNext() ){ XQueryItem xQueryItem = iter.nextItem(); Node node = (Node)xQueryItem.getValue(); list.add( u.unmarshal( node ) ); } return list; } finally{ if ( clientSession != null ) clientSession.release();+ } }
XQuery文字列のテンプレート変換
LuxeonDaoクラスのexecuteXQuery
メソッドの説明でも触れましたが、本稿のサンプルでは、XQueryの構文をVelocityのテンプレートファイルとして用意し、JavaオブジェクトとマージすることでXQuery文字列を生成しています。以下に、商品名検索で使用するXQueryを記述したテンプレートファイルを示します。
for \$item in /MultiDoc_Container/item where contains(\$item/item_name/text(),'$item.itemName') return \$item
「$item.itemName」が画面で入力された商品名に変換されてXQuery文字列となります。なお「\$item」は「\」で$をエスケープしているだけですので、変換されず「$item」として出力されます。
Velocityによる変換処理の詳細な説明については、別稿Jakarta Velocityでテンプレートを変換しメールを送信するに説明を委ね、ここではVelocityWrapperクラスのソースを示すのみにします。
public class VelocityWrapper { /** Velocityエンジンにアクセスするためのクラス */ private static VelocityEngine engine = null; /** テンプレート変換時に使用するオブジェクトを
* 格納するためのクラス
*/ private VelocityContext context = null; /**
* デフォルトコンストラクタ
*/ public VelocityWrapper() throws FileNotFoundException, IOException,Exception{ if ( engine == null ){ engine = new VelocityEngine(); Properties props = new Properties(); props.load( getClass().getResourceAsStream( "/velocity.properties" ) ); engine.init( props ); } context = new VelocityContext(); } /**
* @param templateObjMap
*/ public void put(Map<String, Object> templateObjMap){ Set keySet = templateObjMap.keySet(); for (Iterator iter = keySet.iterator(); iter.hasNext();) { String objName = (String) iter.next(); Object obj = templateObjMap.get( objName ); put( objName, obj ); } } /**
* @param key
* @param value
*/ public void put(String key, Object value) { context.put( key , value ); } /**
* @param templateResourceName
* テンプレートファイルのリソース名
* (クラスパスからスラッシュ区切り)
* @return マージ結果の文字列
*/ public String merge(String templateResourceName) throws ResourceNotFoundException,ParseErrorException, MethodInvocationException,Exception{ // テンプレートの取得 Template template = engine.getTemplate( templateResourceName ); StringWriter sw = new StringWriter(); template.merge( context , sw ); return sw.toString(); }