garbagetown

個人の日記です

ルーティング

Cubby のルーティング規則が気になるのです。

疑問

アクションクラスの作成 によると、リクエスト URL と Action クラスおよびメソッドは、以下のように割り当てられるらしい。

メソッド URL 説明
HelloAction#index /hello メソッド名 index だけは特別で URL なし
HelloAction#message /hello/message "/" + "hello" + "/" + "message"

なるほど、よく分かる。が、例えば以下のような URL はどういう風に割り当てられるんだろう?

  • /sk8/howto/shuvit

予想

なんとなく予想を立ててみる。

  1. action パッケージの下にサブパッケージが付く(action.sk8.HowtoAction#shuvit)
  2. Action クラス名を大文字で区切る(action.Sk8HowtoAction#shuvit)
  3. Sk8Action#howto() に引数として "shuvit" が渡る

自分で書いておいて何だが、2 と 3 は無いな、と思う。とくに 3 は階層がさらに深くなったら対応できないし。ってことで、1 が本命。

調査結果

ソースコードを読んでみたら、考え方がまるっきり逆だったことが判明。
リクエスト URL を解析して Action クラスやメソッドを特定するのではなくて、Action クラス名と宣言されているメソッド名から URL を作って Map に保持していた。この Map からリクエスト URL をキーにして Action クラスとメソッドを取っている。
ソースコード読む前に起動時のログを見て気付けと言いたい。

アクションメソッドを登録します [regex=^/hello/message$,
method=public org.seasar.cubby.action.ActionResult 
cubby.test.action.HelloAction.message(),
uriParameterNames=[],
requestMethods=[GET, POST]]

Action クラス名の "Action" を取り除いて先頭を小文字にした文字列をディレクトリパス、ActionResult を返すメソッド名を URL として設定しているので、"/xxx/" または "/xxx/yyy" という URL しかあり得ない。

対応方法

というわけで、"/sk8/howto/shuvit" のような深い URL を使いたいときは下記いずれかの方法で対応する必要がある。

  1. @Path アノテーションを使って URL マッピングをカスタマイズ する。
  2. org.seasar.cubby.routing.impl.PathResolverImpl#add() を使ってルーティング情報を登録する

どちらの方法を取っても野放図にマッピングしまくると収集が付かなくなるので、予想 1 のマッピングルールを @Path アノテーションで補ってやると良さそう。

package cubby.test.action.sk8; // action 配下にサブパッケージを切る

import org.seasar.cubby.action.Action;
import org.seasar.cubby.action.ActionResult;
import org.seasar.cubby.action.Path;
import org.seasar.cubby.action.Redirect;

@Path("sk8/howto") // @Path アノテーションでマッピング
public class HowtoAction extends Action {
    public ActionResult shuvit() {
        ...
    }
}

予想は全部はずれたけど、気は済んだので寝るとします。