HandlerMappingを自動でやりたい
リクエストのパスに対応するControllerを見つけるためのクラスがHandlerMapping。
こういうのは、命名規約といったルール付けをしておくことで、実装者が
設定ファイルを書かなくても自動でできるようにしたい。
イメージとしては、/top/top.formにアクセスするとtop.TopControllerが
自動で呼ばれるようにしたい。
今考えている前提として、
という条件。
で、ControllerClassNameHandlerMappingを使うとTopControllerは
以下のURLにマッピングされると認識される。
- top/top
- top/top/*
つまりは、top/top.formには反応しないわけで、困った困った・・・
というのをどうにかしたいというのが今回のお話。
とりあえず思いつきで2つを試してみた。
- ControllerClassNameHandlerMappingを拡張する
- 独自にHandlerMappingを作る
ControllerClassNameHandlerMappingを拡張してしまう
ControllerClassNameHandlerMappingで、top.TopControllerが
/top/top*に対して登録するようにしてしまう。
コードを追う限り、ControllerClassNameHandlerMapping#generatePathMappings
でTopControllerがMultiActionControllerTypeと認識されるから悪いわけで、
そうでないと認識されれば/top/top*に対するマッピングが登録されるはず。
やるとすると以下の方法となる。
- ControllerClassNameHandlerMappingを継承したクラスを作成し、isMultiActionControllerTypeメソッドをオーバーライドしちゃう。
- isMultiActionControllerTypeで使っているControllerTypePredicateを置き換える。
- →ただしこいつパッケージプライベートだったりする。
ただ、@Controllerを付けたクラスがMultiActionControllerTypeでなくなる
ことの弊害は不明・・・。
独自にHandlerMappingを作る
単にパス名とControllerをマッピングするHandlerMappingを自作してみる。
Spring全体の動作を把握しているわけじゃないので、あんまりやりたくないけど、
なんかちょっとやってみたかったというだけ。
top/top.formにアクセスした場合、top.formの部分からTopControllerが
マッピングされるようにする。テスト的に作ったのがこんな感じ。
# 時間がないのでガリガリ書いてるのはヒミツ
# 上半分はどっかのコードのパクりだしw
public class PathNameHandlerMapping extends AbstractUrlHandlerMapping { @Override protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { Object handler = getHandlerMap().get(urlPath); if (handler != null) { if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } int index = urlPath.lastIndexOf('/'); if (index == -1) { return null; } String path = urlPath.substring(index + 1); int extIndex = path.indexOf('.'); if (extIndex != -1) { path = path.substring(0, extIndex); } String handlerName = path + "Controller"; if (!getApplicationContext().containsBean(handlerName)) { return null; } handler = getApplicationContext().getBean(handlerName); validateHandler(handler, request); registerHandler(urlPath, handlerName); return buildPathExposingHandler(handler, path, path, null); } }
なんとなく動いているようだけど、不正なパスに対してもControllerが動くわけで、
セキュリティ的に大問題な気がする。/aaa/xxx.formにアクセスできないユーザーが、
/xxx.formでアクセスできちゃったりしそーなので。
あと、これやるとパス名は必ず一意としなければならない(/aaa/xxx.formと
/bbb/xxx.formというのは作れない)わけで、それもよろしくない。
色々と悩んだけど、こんな解決策しか思いつかないんで、
もうちっとソースをあさってみるかぁ。
そもそも、1リクエスト=1Controllerとしてるのが悪な気がするけど。