CodeZine(コードジン)

特集ページ一覧

Struts 2にトランザクション管理を提供する「Spring Frameworkプラグイン」

続・Struts 2入門(7)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2010/09/14 14:00
目次

今回のサンプルについて

 単純な依頼リストの登録・閲覧・編集・削除を行えるアプリケーションを作成しました。データベースのテーブルも非常にシンプルなもので、画面からは依頼内容とステータスを入れる2つのフィールドを持つだけです。それ以外にキー項目となるシーケンシャルなIDが1つあります。

 アプリケーションとしては、本来入力チェックや排他制御を設けるところですが、今回は単純にデータベースとのアクセスにのみ注力したアプリケーションなので割愛いたしました。

 なお、本サンプルの画面遷移図は以下のようになります。

図1 画面遷移図
図1 画面遷移図

 今回作成するアプリケーションの機能をざっと上げるとこの5つとなります。併せてそれぞれの機能のAction名を決定しました。

  • 一覧検索 - list(登録されている全件を表示する)
  • 詳細表示 - browse(一覧から選んだ1件の情報を表示し、更新-削除を選べる)
  • 新規登録 - insert
  • 更新 - update
  • 削除 - delete

 画面は簡単に一覧画面と詳細画面のみとしています。詳細画面で依頼内容以外のデータ(今回はステータスしかありませんが)を表示し、そこで編集、削除、追加をできるものとしています。また、このAction名をそのままリクエストするURLとします。例えば、新規登録のURLは/コンテキストルート/insertとなります(.actionは省略できます)。

 では実装部分を見てみましょう。次に示すのは、今回の5機能を網羅したActionクラスとなります。非常に単純な実装なこともありますが、従来のStruts 1やサーブレットに比べてコード量は激減します。

リスト6 IssueAction.java(抜粋)
public class IssueAction extends ActionSupport implements ModelDriven<IssueModel> {
    …(中略)…
    @Action("list")
    public String list() throws Exception {
        // 依頼一覧を検索する。
        resultList = (List<IssueModel>)dao.getObjectList("searchIssue", null );
        addActionMessage("検索が完了しました");    // メッセージ
        return "list";
    }
    
    @Action("browse")
    public String browse() throws Exception {
        // 渡されたidで検索を行う。存在していれば1件になる。
        resultList = (List<IssueModel>)dao.getObjectList("searchIssue", model);
        
        // 検索結果を調べ、1件存在したならばその1件を表示用オブジェクトへバインド
        if ( resultList != null && resultList.size() == 1 ) {
            result = resultList.get(0);
        }
        addActionMessage("詳細を表示しました");    // メッセージ
        return "browse";
    }

    @Action("insert")
    public String insert() throws Exception {
        dao.insert("insertIssue", model);        // 新規登録
        addActionMessage("1件追加しました");    // メッセージ
        return browse();
    }

    @Action("update")
    public String update() throws Exception {
        int count = dao.update("updateIssue", model);    // 更新
        addActionMessage(count + "件を更新しました");    // メッセージ
        return browse();
    }

    @Action("delete")
    public String delete() throws Exception {
        int count = dao.delete("deleteIssue", model);    // 削除
        addActionMessage(count + "件を削除しました");    // メッセージ
        return browse();
    }

    /**
     * ModelDrivenインターセプタ必須メソッド。
     * リクエストパラメータをバインドする実体クラスを取得する。
     * ※Struts 2により中身は自動的にバインドされる。
     */
    public IssueModel getModel() {
        model = new IssueModel();
        return model;
    }
    /** 画面からのパラメータが格納される */
    private IssueModel model;

    private DAO dao;
    public DAO getDAO() {
        return dao;
    }
    public void setDAO(DAO dao) {
        this.dao = dao;
    }
    /** 詳細画面の検索結果を格納する */
    private IssueModel result;
    public IssueModel getResult() {
        return result;
    }
    public void setResult(IssueModel result) {
        this.result = result;
    }
    /** 検索結果を格納する */
    private List<IssueModel> resultList;
    public List<IssueModel> getResultList() {
        return resultList;
    }
    public void setResultList(List<IssueModel> resultList) {
        this.resultList = resultList;
    }
}

 Springによるトランザクションの監視はDAOクラスに対して行われていますので、先ほどの設定ではinsert,update,deleteのメソッドに対して行われます。

 では次に、このActionクラスからDAO経由で呼び出されるSQL定義になります。冒頭でも挙げましたが、今回はiBATISと、SpringのiBATIS管理クラスを利用しますので、iBATIS用の設定ならびにSQL定義ファイルを配置します。

リスト7 sql-map-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
                                 "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <sqlMap resource="../ibatis/sqldefs.xml"/>
</sqlMapConfig>

 <sqlMapConfig>要素で、複数の設定ファイルを読み込めるよう、別ファイルにSQL定義XMLを読みこめるようになっています。今回は1ファイルのみですが、分割してsqldefs.xmlにSQLを記述しています。

リスト8 sqldefs.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap
    PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="lumi2">
    …(省略)…
    <select id="searchIssue" resultClass="seren.lumi2.model.IssueModel" parameterClass="seren.lumi2.model.IssueModel">
        SELECT
            id , issue , checked
        FROM
            issueInfo
        <dynamic>
          <isNotEmpty prepend="WHERE" property="id">
            id = #id#
          </isNotEmpty>
        </dynamic>
    </select>

    <insert id="insertIssue" parameterClass="seren.lumi2.model.IssueModel">
        INSERT INTO issueInfo
            (issue , checked )
        VALUES
            (#issue# , #checked#)
    </insert>

    <update id="updateIssue" parameterClass="seren.lumi2.model.IssueModel">
        UPDATE
            issueInfo
        SET
            issue = #issue# ,
            checked = #checked#
        WHERE
            id = #id#
    </update>

    <delete id="deleteIssue" parameterClass="seren.lumi2.model.IssueModel">
        DELETE FROM
            issueInfo
        WHERE
            id = #id#
    </delete>
</sqlMap>

 <sqlMap>の子要素にあたる<select>や<insert>で、実際に使われるSQLのIDを定義し、parameterClass属性で入力オブジェクトを定義します。また、SELECT文についてはレコード1行の結果をresultClassで受け取れるようになっています。今回のサンプルでは、入力も出力も単純にテーブルのレコード1行そのままを扱っていますので、そのまま扱うクラスであるIssueModelクラスを単純に使います。

 なお、iBATISの詳細については、末尾の参考資料で取り上げた『iBATIS.NETでO/Rマッピングを行う(SQL Maps編)』『iBATISを使ったO/RマッピングによるDBアクセスの実例』、双方の記事を参照してください。

 以上で一通りの検索~登録~更新~削除の流れまでを説明しました。実際のアプリケーションでは、さらに入力チェックや排他制御の実装、複雑なビジネスロジックを組み立てると予想されますが、それらの機能を追加するために行うActionクラスへの変更作業は、今まで取り上げたインターセプタやSpringの機能を使って役割を分担しておけば、きっちりと実装範囲を区分けすることができます。

 制御も含めた実装面をきれいにすることで、単体試験の実施が簡単になり、設計も単純化しやすいという側面もあります。またSpringで作成した従来のアプリケーションのロジック部分のみを再利用できるのも多少なりとも良い点ではないでしょうか。

まとめ

 今回は簡単なデータベースアクセスを扱うアプリケーションを通して、Springプラグインを紹介をしました。次回は、Struts 2でAjaxアプリケーションを作成するためにできたもう一つのStruts 2用プラグインである、JQueryプラグインを紹介します。

参考資料




  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:続 Struts 2入門

もっと読む

著者プロフィール

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

  • WINGSプロジェクト 東 浩二(アズマ コウジ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5