ログイン-一覧画面のStruts2による実装

では、具体的にTODO管理アプリケーションをStruts 2上に再構築することでStruts 2での開発を確認していきましょう。
まず、ログイン画面から一覧画面までを実装してみましょう。

アクション名 Actionクラス Actionメソッド 結果 転送先(JSPファイル/アクション) 役割
login test.LoginAction show success /WEB-INF/jsp/login.jsp ログイン画面を表示します。
成功した場合はsuccessに転送し、
エラーが発生した場合はerrorに転送します。
error /WEB-INF/jsp/error.jsp
login_action test.LoginAction execute success list ログイン処理を実行します。
成功した場合はsuccessに転送し、
エラーが発生した場合はerrorに転送します。
error /WEB-INF/jsp/error.jsp
list test.ListAction execute success /WEB-INF/jsp/list.jsp 一覧画面を表示します。
成功した場合はsuccessに転送し、
エラーが発生した場合はerrorに転送します。
error /WEB-INF/jsp/error.jsp


プロジェクトの作成


struts2todoアプリケーションを作成するため、Eclipseワークスペース上にプロジェクトを作成しましょう。
なお、プロジェクト名はコンテキストパスに対応して、 struts2todo とします。
また、Struts 2を利用するためにはStruts 2によって提供されるライブラリファイルをクラスパス上に配置する必要があります。 以下の手順で作業をおこなってください。

  1. struts2todoプロジェクトを作成します。
    ログイン画面の作成 と同じ要領でTomcatプロジェクトを作成してください。

  2. 以下のファイルをダウンロードし、適当なディレクトリに展開してください。

    ダウンロード struts-2.1.6-all.zip


  3. Struts2に関連するJARファイルをWEB-INF/libにコピーします。
    zipファイルのstruts-2.1.6/libディレクトリから以下のファイルをWEB-INF/libにコピーしてください。

    • commons-fileupload-1.2.1.jar
    • commons-io-1.3.2.jar
    • commons-logging-1.0.4.jar
    • freemarker-2.3.13.jar
    • ognl-2.6.11.jar
    • struts2-core-2.1.6.jar
    • xwork-2.1.2.jar


  4. WEB-INF/libにH2 DatabaseのJARをコピーします。

    C:\Program Files\H2\bin\h2-1.1.108.jarを、 (struts2todoプロジェクト)/WEB-INF/libにコピーしてください。

  5. struts2todoプロジェクトを右クリックし「Properties」を選択し、「Java Build Path」に WEB-INF/lib以下のJARファイルを設定してください。

    これで、JavaプログラムからJARファイル内にあるクラスを参照可能になります。


Actionクラスの実装

以下のようなクラス構成で実装します。

クラス名 説明
test.AbstractDBAction すべてのアクションに共通の処理(JDBC接続確立など)を定義した抽象クラスを実装します。
test.LoginAction ログイン処理を実装します。test.AbstractDBActionを継承します。
test.ListAction 一覧処理を実装します。test.AbstractDBActionを継承します。
test.User ユーザ情報保持オブジェクトを実装します。
test.Item 作業項目保持オブジェクトを実装します。
  1. データを保持するためのUser, Itemクラスを記述します。
    WEB-INF/src以下に「test」パッケージを作成し、以下のようなクラスを作成します。

    ダウンロード User.java Item.java


  2. 抽象Actionクラスを記述します。
    ここでは、全アクションに共通な、JDBC接続の確立処理とセッション情報の管理処理を実装します。

    ダウンロード AbstractDBAction.java
    15~16行目:
     15: public abstract class AbstractDBAction extends ActionSupport
     16:     implements SessionAware{

    インタフェースorg.apache.struts2.interceptor.SessionAwareを実装することの宣言。
    セッション情報を格納・取得するためにはこのインタフェースを実装する必要があります。
    63~65行目:
     63: public void setSession(Map<String, Object> session) {
     64:     _session = session;
     65: }

    SessionAwareインタフェースのメソッドの実装。
    セッション情報を格納・取得するためのMapオブジェクトが設定されます。
    79~81行目:
     79: protected void setCurrentUser(User user) {
     80:     _session.put(SESSION_CURRENT_USER, user);
     81: }

    現在ログインしているユーザ情報を取得する処理。
    セッション情報を格納したMapからUserオブジェクトを取得しています。
    100~118行目:
    100: protected Connection getConnection() throws SQLException {
    101:     // Connectionの準備
    102:     if (_pooledConnection != null) {
    103:         return _pooledConnection;
    104:     }
    105:     try {
    106:         // 下準備
    107:         Class.forName("org.h2.Driver");
    108:         _pooledConnection = DriverManager.getConnection(
    109:                 "jdbc:h2:tcp://localhost/~/test", "sa", "");
    110:         return _pooledConnection;
    111:     } catch (ClassNotFoundException e) {
    112:         _pooledConnection = null;
    113:         throw new SQLException(e);
    114:     } catch (SQLException e) {
    115:         _pooledConnection = null;
    116:         throw e;
    117:     }
    118: }

    JDBC接続の確立処理。


  3. Actionクラスを記述します。
    さきほどの抽象Actionクラスを継承し、Action固有の処理を実装します。

    アクションとクラス・メソッドの対応関係は以下のようにします。また、パラメータに関してはServlet実装と同じにします。

    アクション クラス メソッド
    login LoginAction String show()
    login_action LoginAction String execute()
    list_action ListAction String show()

    ダウンロード LoginAction.java
    41~43行目:
     41: public void setUser_id(String userID) {
     42:     _userID = userID;
     43: }

    リクエスト中のuser_idパラメータ受付処理。
    リクエストパラメータはsetterメソッドにより受け入れることが可能です。 ActionクラスではHttpServletRequestなどのクラスを考慮する必要はありません。
    49~51行目:
     49: public void setPassword(String password) {
     50:     _password = password;
     51: }

    リクエスト中のpasswordパラメータ受付処理。
    56~58行目:
     56: public String show() {
     57:     return "success";
     58: }

    loginアクションの処理。
    戻り値はアクション処理後にどのJSPファイルへ転送するかを示します。
    63~75行目:
     63: public String execute() {
     64:     try{
     65:         User user = queryUser();
     66:         if(user == null) {
     67:             return showError("ユーザIDもしくはパスワードが不正です。");
     68:         }
     69:         
     70:         setCurrentUser(user);
     71:         return "success";
     72:     }catch(SQLException e) {
     73:         return showError(e.getMessage());
     74:     }
     75: }

    login_actionアクションの処理。
    戻り値はアクション処理後にどの処理へ転送するかを示します。
    ユーザIDとパスワードが不正などのエラーが発生した場合はerrorを、ログイン成功した場合はsuccessを返します。
    この戻り値はStruts2で解釈され、この後記述するstruts.xmlに従って別の処理に転送されます。
  4. 同じ要領でListActionクラスを作成します。
    ダウンロード ListAction.java


JSPファイルの実装

JSPファイルを実装します。
ここでは、以下のファイルを実装します。

JSPファイル名 説明
/WEB-INF/jsp/login.jsp ログイン画面を記述します。
/WEB-INF/jsp/list.jsp 一覧画面を記述します。
/WEB-INF/jsp/error.jsp エラー画面を記述します。
  1. ログイン画面のJSPファイルを記述します。
    WEB-INF/jsp以下に以下のようなファイルを作成します。

    Struts2ではタグライブラリが用意されており、 開発者は直接Javaコードを記述しなくても簡単にJSPが記述できるようになっています。

    タグは以下のようなものが記述可能です。
    種別 タグ 用例 説明
    フォーム s:form
    <s:form action="login_action">
        (フォームの内容)
    </s:form>
    フォームの宣言。
    action属性で定義されたアクションへとフォームの内容を送信する。
    s:textfield
    <s:textfield name="user_id" value="" size="24" 
                label="ユーザID"/>
    テキスト入力フィールドの宣言。
    name,value属性はinputタグと同様の意味を持つ。
    また、label属性に指定された文字列がフィールドの左側に表示される。
    s:password
    <s:password name="password" value="" size="24" 
                label="パスワード"/>
    パスワード入力フィールドの宣言。
    name,value属性はinputタグと同様の意味を持つ。
    また、label属性に指定された文字列がフィールドの左側に表示される。
    s:submit
    <s:submit value="ログイン"/>
    送信ボタンの宣言。
    value属性はinputタグと同様の意味を持つ。
    s:hidden
    <s:hidden name="item_id" value="ID"/>
    hiddenフィールドの宣言。
    name,value属性はinputタグと同様の意味を持つ。
    value属性が省略された場合はnameに対応するActionクラスのプロパティが利用される。
    データ処理 s:property
    <s:property value="currentUser.name"/>
    値の埋め込み。
    value属性にはActionクラスのプロパティを指定可能。
    ${変数名}の形式でも埋め込み可能。
    s:if,
    s:elseif,
    s:else
    <s:if test="finishedDate != null">
        (testが成立した場合の記述)
    </s:if>
    <s:elseif test="user.id.equals(currentUser.id)">
        (testが成立した場合の記述)
    </s:elseif>
    <s:else>
        (いずれも成立しなった場合の記述)
    </s:else>
    条件分岐の宣言。
    test属性に指定された式を評価し、成立した場合の記述が出力対象となる。
    s:iterator
    <s:iterator value="items">
    繰り返しの宣言。
    value属性に指定されたオブジェクトに格納されたオブジェクトの個数だけ繰り返しをおこなう。
    iteratorタグ内では、繰り返し中のオブジェクトのプロパティを参照可能。
    s:set
    <s:set var="sample" value="1"/>
    変数の定義。
    var属性で指定された変数に値を設定する。

    ダウンロード login.jsp
    2行目:
      2: <%@ taglib prefix="s" uri="/struts-tags" %>

    Struts2のタグライブラリを使用することの宣言。
    15~19行目:
     15: <s:form action="login_action">
     16:     <s:textfield name="user_id" value="" size="24" id="user_id" label="ユーザID" onkeyup="fieldChanged();" onchange="fieldChanged();"/>
     17:     <s:password name="password" value="" size="24" id="password" label="パスワード" onkeyup="fieldChanged();" onchange="fieldChanged();"/>
     18:     <s:submit value="ログイン" id="login" align="center"/>
     19: </s:form>

    タグライブラリを使用したform定義。
    formを簡単に定義するためのs:formタグを使用することで、 table定義など面倒なHTML記述をすることなくシンプルにformを定義することができます。


  2. エラー画面のJSPファイルを記述します。

    ダウンロード error.jsp
    16~17行目:
     16: エラーが発生しました。<br>
     17: 内容: <s:property value="errorMessage"/>

    Actionの値をJSP中に出力。
    s:propertyタグを記述することで、転送元のActionのgetterを呼び出し、JSP中に埋め込んでいます。


  3. 一覧画面のJSPファイルを記述します。

    ダウンロード list.jsp
    36~40行目:
     36: <s:if test="items.length == 0">
     37:     <div align="center">
     38:         作業項目はありません。
     39:     </div>
     40: </s:if>

    転送元のActionの値による条件分岐。
    s:ifタグによって条件分岐をおこないます。条件文中の値は、s:propertyと同様に転送元のActionのgetterを呼び出すことで取得しています。
    60~63行目:
     60: <s:iterator value="items">
     61:     <s:if test="finishedDate != null">
     62:         <s:set var="tdStyle" value="'background-color: #cccccc;'"/>
     63:     </s:if>

    転送元のActionの値による繰り返しと変数の管理処理。
    s:iteratorタグによって繰り返しをおこないます。また、s:setタグにより変数に値を設定しています。


  4. 先に作ったCSS,JavaScriptファイルをstruts2todoプロジェクト直下にコピーします。
    CSSについてはStruts2のformタグにあわせて一部修正しています。

    ダウンロード todo.css login.js


設定ファイルの記述

  1. WEB-INF以下にweb.xmlを作成します。
    ここでは、Struts2が提供するクラスをパラメータに指定します。

    ダウンロード web.xml


  2. WEB-INF/src以下にstruts.xmlを作成します。
    ここでは、これから記述するActionとJSPの定義をパラメータに指定します。

    ダウンロード struts.xml
    12~15行目:
     12: <action name="login" class="test.LoginAction" method="show">
     13:     <result name="success">/WEB-INF/jsp/login.jsp</result>
     14:     <result name="error">/WEB-INF/jsp/error.jsp</result>
     15: </action>

    loginアクションの定義。
    アクションクラス名とメソッド名、結果文字列によってどのJSPファイルに転送するかを設定します。
    17行目:
     17: <result name="success" type="chain">list</result>

    別のアクションへの転送定義。
    result要素にtype="chain"と記述することで別のアクションに転送することも可能です。


ここまでのファイル

ここまででプロジェクトディレクトリの内容は以下のようになります。
正しく作成できているか、確認してください。

ダウンロード struts2todo_1.zip


デバッグ

ブラウザで以下のURLを開きます。
http://localhost:8080/struts2todo/login.action

Servletから実装する場合に比べて、アクションごとに分配する処理などを記述する必要がなくなり、 個々の機能の独立性が高くなっていることがわかると思います。
このようにWEBアプリケーションフレームワークを活用することで、モジュール化、再利用を促進することが できるようになります。