SyntaxHighlighter

2011年6月7日火曜日

Slim3でのURLマッピング

再度確認しました
 結論としては、@higayasuo さんがお話されていた通り「当たり前の挙動」を示しているだけなのかなーと。
 サーブレットに詳しくない自分としてはちょっとツラい感じです

※6/9修正しました。ソース部分をasXxxを使った形に書き換え&こちらを参考にrequestなどの取得について修正

確認しました。
POSTが噛んだときの、マッピングの判断条件の考え方が間違っていました。

RequestMapのgetは、内部でHttpRequestServletのgetAttribute()を呼び出します。
で。
  • Formのenctypeが「multipart/form-data」の場合
    POSTがない場合はこれでGETの引数としてのマッピング先(?key={key})が取得できるのですが、POSTデータがある場合はこの値がPOSTの内容になるようです。
    GETの値はどこかというと、「request.getParameter("key")」で取得できる模様

  • Formのenctypeが「text/plain」の場合
    RequestMapのgetは、GETの値、つまりURLマッピングの「?key={key}」が入っています。
    POSTの値は・・・getParameterでも取れませんでした。

とりあえずURLマッピングを絡めてPOSTを扱う場合は、「multipart/form-data」にしておくことをオススメします。
以下修正しました。
ひと通り動く版。POSTは「multipart/form-data」で。

参照リンク
http://sites.google.com/site/slim3documentja/documents/slim3-controller/url-mapping

Slim3は通常、
リクエストURLパス コントローラ
/ slim3.rootpackage.controller.IndexController
/xxx slim3.rootpackage.controller.XxxController
/xxx/ slim3.rootpackage.controller.xxx.IndexController
/xxx/yyy slim3.rootpackage.controller.xxx.YyyController
/xxx/yyy/zzz slim3.rootpackage.controller.xxx.yyy.ZzzController
※slim3.rootpackage は web.xml で定義されています。
というようにマッピングルールに基づいて、実行するコントローラが決まります。

リンク先に書いてあるのをちゃんと読んでいなかったのですが、このURLマッピングはある程度制御することができます

コントローラを取得する前にリクエストURLパスの書き換えをすることもできます。
URLリライティングを使うには slim3.rootpackage.controller.AppRouter クラスを先に定義する必要があります。

とのこと。実際にやってみましょう

slim3.rootpackageが「jp.tyato.test」だとすると、「jp.tyato.test.controller.AppRouter」クラスを生成します
  • 「jp.tyato.test.controller」のパッケージを用意する
  • 「jp.tyato.test.controller」配下に「AppRouter」クラスを生成。内容は次のような感じ

6/8修正
package jp.tyato.test.controller;

import org.slim3.controller.router.RouterImpl;

public class AppRouter extends RouterImpl
{
    Public AppRouter()
    {
        addRouting("/xxx/{key}", "/xxx?key={key}");
    }
}

次にIndexControllerクラスを生成します
  • 「build.xml」を開き、アウトラインから「gen-controller-without-view」を選択、実行から「1 Ant ビルド」を実行する
  • 名前の入力を求められるので、「/xxx/Index」と入力
  • 「jp.tyato.test.controller.xxx」配下に「IndexController.java」が作成される
  • メソッド「run」の中を書き換える

final String KEY_NAME = "key";

@Override
public Navigation run() throws Exception
{
    Navigation result = null;

    try
    {
        String keyword = asString(KEY_NAME);

        if(keyword == null)
        {
            //getParameterで再度試行
            keyword = request.getParameter(KEY_NAME);
        }

        if( keyword != null )
        {
            keyword = keyword.toLowerCase();
        }

        //Factoryパターン用コントローラ親クラスの定義
        Controller con = this.GetFromFactory(keyword);

        result = con.runBare();
    }
    catch (Throwable e)
    {
        e.printStackTrace();
    }

    return result;
}

public Controller GetFromFactory(String keyword)
{
    Controller con = null;

    try
    {
        if (keyword == null || keyword.isEmpty() || keyword.startsWith("index") )
        {
            //keywordがnull、空文字、indexで始まる文字のいずれかである場合、Index表示処理
            con = new ForDefaultController();
        }
        else if (keyword.equals("yyy"))
        {
            //keyが「yyy」である場合、yyy用の処理へ
            con = new YyyController();
        }
        else if (keyword.equals("zzz"))
        {
            //keyが「zzz」である場合、zzz用の処理へ
            con = new ZzzController();
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    return con;
}
後は実際に処理を行うControllerクラスを実装します。
この場合は「ForDefaultController」「YyyController」「ZzzController」について
  • 「build.xml」を開き、アウトラインから「gen-controller-without-view」を選択、実行から「1 Ant ビルド」を実行する
  • 名前の入力を求められるので、「/xxx/???」と入力
  • 「jp.tyato.test.controller.xxx」配下に「???Controller.java」が作成される
???の部分をそれぞれ「ForDefault」「Yyy」「Zzz」に置き換えて読んでください。

しかしこのままですと、各Controllerを呼び出してもそれぞれの変数である
「protected ServletContext servletContext」
「protected HttpServletRequest request」
「protected HttpServletResponse response」
がnullのままです。

ですので、利用する前に各Locaterのgetを使って、値を取得してやります。

YyyControllerであれば、こんな感じです
package jp.tyato.test.controller.xxx;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.util.RequestLocator;
import org.slim3.util.ResponseLocator;
import org.slim3.util.ServletContextLocator;

public class YyyController extends Controller
{
    @Override
    public Navigation run() throws Exception
    {
        this.CheckParentMember();

        //以降、実処理
    }

    protected void CheckParentMember()
    {
        if( request == null )
        {
            request = RequestLocator.get();
        }

        if( response == null )
        {
            response = ResponseLocator.get();
        }

        if( servletContext == null )
        {
            servletContext = ServletContextLocator.get();
        }
    }
}
「ForDefaultController」「ZzzController」についても同様に定義してやります。
※まぁ実際に使うときに〜Locator.get()を呼び出してやればいいんですが。

こうすることで、
  • Indexに一旦集約
  • その都度の値により狙った処理を行うように制御
といったことが可能になります。

0 件のコメント:

コメントを投稿