オレオレフレームワーク
昨日のエントリのコメントにも書いたが、SpringMVCはいまいち使いにくいところもあってオレオレフレームワークでちょうど1年前に作っていた。それは妄想その2に非常に近い。
そこでshot6さんのコードをもとに書いてみよう。
public class AddPage implements Controller{ @Inject HTTPServletRequest request; public View show() { return new View(View.REDIRECT ,"jsp/add.jsp"); } /** * addボタンがPOSTで押されたときだけ呼ばれる */ @WebEvent(name="add" , value="同一ページ") public View add() { //Validationはここらでお好きにどうぞ。 Integer arg1 = Integer.valueOf(request.getParameter("arg1")); Integer arg2 = Integer.valueOf(request.getParameter("arg2")); request.setAttribute("arg1", arg1); request.setAttribute("arg2", arg2); request.setAttribute("result", arg1 + arg2); return new View(View.FORWARD ,"jsp/add.jsp"); } /** * addAndMoveボタンがPOSTで押されたときだけ呼ばれる */ @WebEvent(name="addAndMove" , value="結果ページ") public View addAndMove() { //Validationはここらでお好きにどうぞ。 Request request = context.getRequest(); Integer arg1 = Integer.valueOf(request.getParameter("arg1")); Integer arg2 = Integer.valueOf(request.getParameter("arg2")); request.setAttribute("result", arg1 + arg2); return new View(View.FORWARD ,"jsp/addResult.jsp"); } }
InjectがあることからわかるようにGoogle Guiceを使っていた。まー見事に似ているね。ViewにはバイナリデータのダウンロードとかpdfとかExcelとかタイプがいろいろとある。byte[]をわたしてダウンロードとかよくやるね。
Controllerは最初はなくて、同じように@Defaultというアノテーションで最初はやっていた。実際のところデフォルトなGETを受け取るのを作ることを忘れるなどミスをすることもあるため、コンパイル前に縛るためにインターフェースをつけるようにした。また、URLもクラスにつけていたが、一箇所でどのクラスがどのURLになるのかをすぐ確認や管理できるほうがやはり便利だと思い知ったので、GuiceのModuleで定義した。
なんでもアノテーションにすればいいというわけではないというのをこのとき思い知る。インターフェースで必ず実装してもらうというのは非常にJavaらしく、やはり基本を大事にしようね、と。
requestの判断は最初はshot6さんと同じようにnameだけにしていたが、2度押し防止のために手軽に実装できるdisableをいれるscriptを実装すると判断できないこと、1つのhiddenなパラメータを利用して画面遷移をコントロールするのが一番柔軟性があること、ラジオボタン等の状態によって飛ぶ先をかえることが可能なこと、など柔軟性のためにnameとvalueを用意した。おかげでhtmlとコードを見てすぐわかるというメリットがあった。アノテーションを使う場合メソッド名で判断させないほうがコードを見ていてわかりやすいと思った。IDEで色づけしてくれるわけだし。
実際はRequestにパラメータをセットすることもなくて、このインスタンス自体がrequestにマップされるようにしていた。
public class AddPage implements Controller{ @Inject HTTPServletRequest request; public View show() { return new View(View.REDIRECT ,"jsp/add.jsp"); } /** * addボタンがPOSTで押されたときだけ呼ばれる */ @WebEvent(name="add" , value="同一ページ") public View add() { //Validationはここらでお好きにどうぞ。 arg1 = Integer.valueOf(request.getParameter("arg1")); arg2 = Integer.valueOf(request.getParameter("arg2")); result = arg1 + arg2; return new View(View.FORWARD ,"jsp/add.jsp"); } /** * addAndMoveボタンがPOSTで押されたときだけ呼ばれる */ @WebEvent(name="addAndMove" , value="結果ページ") public View addAndMove() { //Validationはここらでお好きにどうぞ。 arg1 = Integer.valueOf(request.getParameter("arg1")); arg2 = Integer.valueOf(request.getParameter("arg2")); result = arg1 + arg2; return new View(View.FORWARD ,"jsp/addResult.jsp"); } //-------------------------------------------------------------------------- //ここから下がrequestにマッピングされてEL等で取得可能になる private Integer arg1; public Integer getArg1(){ return arg1; } private Integer arg2; public Integer getArg2(){ return arg2; } private Integer result; public Integer getResult(){ return result; } }
おおむねこんな感じ。
小規模開発だとこれとJSTLだけでかなり安定した開発ができていたと思う。当時はGuiceの資料ゼロだったけど、コードによる定義ファイルというのはミスが少なく非常に楽だった。カスタムタグでhtmlを生成すると実行しないと結果がわからないことやDreamWeaverでデザインしやすいようにするため制御以外のタグは一切なしで。あくまでもループやテキスト等を表示するところにタグやELを書くだけに専念する。
いろんな現場でオレオレフレームワークはあるとは思うが、ほとんどはこんな感じだと思う。そしてStrutsの上にかぶせているものはそのほとんどがかなり使いにくいものだったと思う。位置から作ったやつのほうがカバー範囲は狭いものの、このフレームワークでどんな問題を解消しようと考えていたのかがよくわかって、結局使いやすいものが多いと思う。
JSFのようなイベントモデルをとらないで、こういうActionベースでの考え方の場合、あまり機能を増やさないほうが結果的に融通が利いてやりやすい。必要ならばその上にかぶせればいいだけだし。