« Flickrとのマッシュアップ! (PopBoxとdhtmlxGrid) その2 | メイン | CSSボタンあれこれ »

題材となるStrutsアプリですはてなブックマークに追加 livedoorクリップに追加 Yahoo!ブックマークに追加 del.icio.usに追加 イザ!ブックマーク ニフティクリップに追加

前回のエントリでは、Javaの世界で長年に渡り標準の地位だったStrutsのアーキテクチャの復習と、それをAjax対応アプリケーションにしてみましょう!という導入のみを取り上げました。本当にStrutsはよく使われたフレームワークですので、ちょっと周りを見渡せばStrutsでできたWebアプリケーションは簡単に見つけることができるでしょう。もちろん、Strutsを使った開発の経験者についても、比較的多いことと思います。そんな方々に、Ajaxやマッシュアップの世界をぜひ見て欲しいと思います。

さて、今回から具体的な題材を取り上げて、それをAjax対応していく過程を紹介していきます。が、いきなりガラリとフルAjax対応を行うのはあまり良い方法とは言えませんので、部分的にAjax対応を進めていくことにしましょう。題材として、「イベント検索アプリケーション」を取り上げます。これは、すでにStrutsで作られていて、実際に稼働していたWebアプリケーションという想定です。ただし、本当に稼働しているものだと、本質ではないコードが随所に記述されていることでしょうから、今回は非常にシンプルな題材とします。稼働中のアプリから一部分を抜粋してきた、というイメージを持ってください。

最初に、画面と遷移を確認しましょう。画面数は、たった2枚です。

java-a-2-1.jpg

検索画面では、検索条件としてコミュニティ名とイベント名を入力し、検索ボタンを押します。すると、同じ画面ですが、画面の下部に検索結果としてイベントの一覧が表示されます。さらに、一覧の中の参照リンクをクリックすると、そのイベントの詳細情報ページに遷移します。よくある検索画面と詳細表示画面の組み合わせですね。

では、次にクラス構成です。まずは、モデルクラスの構成から見ましょう。

java-a-2-2.jpg

Eventクラスが、イベントの情報を保持しています。Eventクラスは、そのイベントを主催するコミュニティであるCommunityクラスをcommunityプロパティとして保持できます。

次に、アプリケーション全体の構成を見ていきましょう。

java-a-2-3.jpg

top.jspファイルによって検索画面がレンダリングされます。ここからSearchEventActionクラスの処理が呼び出されます。SearchEventActionクラスの中では、実際の検索処理はEventBeanクラスに委譲しています。各イベントの参照ボタンが押下された際は、ShowEventActionクラスの処理が呼び出されます。そして、やはりEventBeanクラスの処理を利用して、参照するイベントの情報を取得し、それがevent.jspファイルによってレンダリングされます。EventBeanクラスの中では、データベースに情報を問い合わせる想定として、EventDaoインタフェースを利用して実際のモデルオブジェクトを取得しています。

ここで注目すべき点として、2つの検索処理は、Actionクラス内ではなく、EventBeanクラスによって記述されていることがあげられます。例えば、ShowEventActionクラスのコードを見てみましょう。

(コード ShowEventActionクラス)

public class ShowEventAction extends Action {
  public ActionForward execute(
      ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response) {
    ShowEventForm showEventForm = (ShowEventForm)form;
    String id = showEventForm.getId();
    EventBean bean = new EventBean();
    Event event = bean.getEvent(id);
    request.setAttribute("event", event);
    return mapping.findForward("success");
  }
}

このように、Actionクラスから直接Daoインタフェースを利用せずに、EventBeanとして業務ロジックを挟めておくことにより、結果としてAjax対応もやりやすくなります。それは、Web層としてStruts以外の機構を利用した際に、そのまま業務ロジックが使い回せるからですね。

一般的に、Strutsアプリケーションを構築する際には「Actionクラスに直接ビジネスロジックを実装してはいけない」ということが盛んに言われました。この指針に基づいていれば、上記のようなクラス構造になっているはずですね。

その他のコードも紹介しておきましょう。

(コード top.jsp)

<html:html locale="true">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title><bean:message key="welcome.title"/></title>
  <html:base/>
 </head>
 <body style="background-color: white">

  <html:form action="/search.do">
   <table>
    <tr>
     <td>コミュニティ名:</td>
     <td><html:text property="communityName"></html:text>
    </tr>
    <tr>
     <td>イベント名:</td>
     <td><html:text property="eventName"></html:text>
    </tr>
    <tr>
     <td colspan="2"><html:submit value="検索"></html:submit></td>
    </tr>
   </table>
  </html:form>

  <logic:present name="result" scope="request">
   <table>
    <tr>
     <td>ID</td>
     <td>コミュニティ名</td>
     <td>イベント名</td>
     <td><br /></td>
    </tr>
    <logic:iterate id="event" name="result" scope="request">
     <tr>
      <td><bean:write name="event" property="id"></bean:write></td>
      <td><bean:write name="event" property="community.name"></bean:write></td>
      <td><bean:write name="event" property="name"></bean:write></td>
      <td><html:link paramName="event" paramId="id" paramProperty="id" action="/show.do">参照</html:link></td>
     </tr>
    </logic:iterate>
   </table>
  </logic:present>

 </body>
</html:html>

(コード SearchEventActionクラス)

public class SearchEventAction extends Action {
   public ActionForward execute(
      ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response) {
    SearchEventForm searchEventForm = (SearchEventForm)form;
    Map conditionMap = new HashMap();
    String communityName = searchEventForm.getCommunityName();
    if (communityName != null && communityName.length() > 0) {
      conditionMap.put(SearchCondition.COMMUNITY_NAME, communityName);
    }
    String eventName = searchEventForm.getEventName();
    if (eventName != null && eventName.length() > 0) {
      conditionMap.put(SearchCondition.EVENT_NAME, eventName);
    }
    EventBean bean = new EventBean();
    List result = bean.search(conditionMap);
    request.setAttribute("result", result);
    return mapping.findForward("success");
  }
}

(コード EventBeanクラス)

public class EventBean {

  private EventDao eventDao;

  public EventBean() {
    super();
    eventDao = new EventDaoMock();
  }

  public Event getEvent(String id) {
    return eventDao.findByPrimaryKey(id);
  }

  public List search(Map conditionMap) {
    return eventDao.findAll(conditionMap);
  }

}

(コード event.jsp)

<html:html locale="true">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title><bean:message key="welcome.title"/></title>
  <html:base/>
 </head>
 <body style="background-color: white">

  <table>
   <tr>
    <td>ID</td>
    <td><bean:write name="event" property="id" /></td>
   </tr>
   <tr>
    <td>コミュニティ名</td>
    <td><bean:write name="event" property="community.name" /></td>
   </tr>
   <tr>
    <td>イベント名</td>
    <td><bean:write name="event" property="name" /></td>
   </tr>
   <tr>
    <td>開始日時</td>
    <td><bean:write name="event" property="startDate" format="yyyy/MM/dd HH:mm:ss" /></td>
   </tr>
   <tr>
    <td>終了日時</td>
    <td><bean:write name="event" property="endDate" format="yyyy/MM/dd HH:mm:ss" /></td>
   </tr>
  </table>

  <br />

  <html:link action="/search.do">戻る</html:link>

 </body>
</html:html>

taglib関連のコードや、import文などは省略してあります。また、SearchEventFormクラスは、communityNameプロパティとeventNameプロパティを持つActionFormクラスであり、ShowEventFormクラスは、idプロパティのみを持つActionFormクラスです。

最後に、struts-config.xmlファイルの内容を一部紹介しておきましょう。これで、どのようなアプリケーションなのかはイメージを持つことができると思います。

(コード struts-config.xml)

<struts-config>
 <form-beans>
  <form-bean name="searchEventForm" type="jp.tkrb.event.struts.forms.SearchEventForm" />
  <form-bean name="showEventForm" type="jp.tkrb.event.struts.forms.ShowEventForm" />
 </form-beans>
 <action-mappings>
  <action path="/search"
    type="jp.tkrb.event.struts.actions.SearchEventAction"
    name="searchEventForm"
    scope="session"
    validate="false">
   <forward name="success" path="/WEB-INF/jsp/top.jsp" />
  </action>

  <action path="/show"
    type="jp.tkrb.event.struts.actions.ShowEventAction"
    name="showEventForm"
    scope="request"
    validate="false">
   <forward name="success" path="/WEB-INF/jsp/event.jsp" />
  </action>
 </action-mappings>
 ・・・
</struts-config>

今回は、題材とするStrutsアプリケーションを紹介しました。Ajax対応のコードを期待していた読者の方には、今回の内容は肩透かしだったかもしれません。いよいよ次回から、上記のStrutsアプリケーションをAjaxアプリケーションに変身させていきます。お楽しみに!