2007 年 3 月 15 日 23 時 55 分

ActionMapping: Model と遷移の分離


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


昨日は、ActionForward クラスを使って転送を行ったが、
ActionForward インスタンスをその場で作成しているため、
アクションのコード中に URL がハードコーディングされる。

確かに Model と View のコードは切り離されたが、
両者の依存性(結合性)は未だに高く、
この Model を実行するとこの View に移動するという、
遷移が固定されていることには変わりない。

「Model の部品化」という点で考えてみると、
Model は動作だけに専念すべきである。
処理を行って処理結果を格納し、成否を返すだけで良く、
Model が自身の遷移先を決める必要はないはずだ。

そこで、今日は Model から状態遷移を切り離してみよう。

LoginAction を例として考えてみると、
このアクションは「ログイン処理」という動作なのだから、
認証が必要な色々な場所で使えるはずだが、
昨日のコードでは、必ずメニュー画面に飛んでしまう。

これを防ぐためにはどうすればよいか。

実は、設定ファイルの <action> 要素には、自分の子として、
<forward> 要素を記述することができる。
<forward> 要素は、ActionForward を XML 化したもので、
これを使うと、事前に転送先を用意しておくことができる。

    <action path="/login"
                type="jp.loafer.test.actions.LoginAction">

        <forward name="success" path="/WEB-INF/pages/menu.jsp" />
        <forward name="failure" path="/WEB-INF/pages/login.jsp" />

    </action>

<forward> 要素の path 属性には転送先のパスを、
name 属性には自由な名前をつけることができる。
上記の例では、success(成功)は menu.jsp への、
failure(失敗)は login.jsp への転送を意味している。

では、この情報をどのように使うか。
例によって、Action の execute メソッドを見てみよう。

    public ActionForward execute(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response) throws Exception;

今回使うのは、ActionMapping クラスである。

ActionMapping クラスは、struts-config.xml に記述した、
<action> 要素の設定内容を Bean 化したものだ。
そのため、アクションクラスの execute メソッドでは、
mapping 引数を使って設定内容を読み取る事ができる。

ActionMapping の FindForward メソッドを使うと、
<action> 要素の子として定義した <forward> 要素を、
その name 属性を元にして検索することができる。

戻り値は、ActionForward インスタンスとして返るため、
そのまま execute メソッドの戻り値とすることができる。

では、これを利用して、昨日のコードを改造してみよう。

========== LoginAction#execute ==========

    public ActionForward execute(ActionMapping mapping,
            ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        // パラメータを取得
        String user = request.getParameter("user");
        String password = request.getParameter("password");

        // ユーザ名は guest 限定とする
        if (!"guest".equals(user)) {
            return mapping.findForward(Forwards.FAILURE_KEY);
        }

        // パスワードは hogehoge 限定とする
        if (!"hogehoge".equals(password)) {
            return mapping.findForward(Forwards.FAILURE_KEY);
        }

        // ログイン成功!

        // ログイン情報をセッションに保存
        request.getSession().setAttribute("user",
                request.getParameter("user"));

        return mapping.findForward(Forwards.SUCCESS_KEY);

    }

========== end of LoginAction#execute ==========

今日は少しだけロジックも仕込んでみた。

入力パラメータを調べ、ユーザ名とパスワードが、
「guest」かつ「hogehoge」の場合のみログイン成功、
それ以外なら失敗とみなす。

アクションは、ActionMapping を使って成否を返す。

成功時には "success"、失敗時には "failure" というキーで
ActionMapping を検索してそれを返すのだ。

ソースコード上に、"failure" 等の文字列リテラルを、
大量に書かないようにするため、
<forward> の名前は定数化しておいた。

========== Forwards.java ==========

package jp.loafer.test.actions;

public class Forwards {
    static public final String FAILURE_KEY = "failure";
    static public final String SUCCESS_KEY = "success";
    private Forwards() {}
}

========== end of Forwards.java ==========

では、/index.do をブラウザで開き、
ログインフォームに入力して送信してみよう。

guest/hogehoge の組み合わせの場合のみ、
「ログイン成功!」の画面に転送され、
それ以外の場合は、ログイン画面に戻されるはずだ。

これでアクションから URL を消すことができた。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.