Strutsは1.2系で終了しているid:paulowniaです。
今更Strutsネタも無いだろうという気がするが、あっちこっちで使われているフレームワークなので保守案件も少なくない。それにStrutsに代わる本命フレームワークが無いのも事実。
というわけでStrutsアプリにCRUD処理の追加のお仕事。だまってMappingDispatchAction使えば実装30分で終了だが、
public class HogeAction extends MappingDispatchAction { public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) { HogeForm hForm = (HogeForm)form; this.hogeDao.deleteById( hForm.getId() ); } public ActionForward list(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) { HogeForm hForm = (HogeForm)form; hForm.setHoges( this.hogeDao.findAll() ); } // 以下略 }
毎度のことながらActionFormのキャストが嫌な感じ。メソッド内に同じインスタンスを参照するローカル変数が二つある時点でウンコのようなコード略してウンコード。何とかしたい。
こーいう嫌な処理を肩代わりする地味なActionクラスを書いてみた。まずURLベースのメソッドディスパッチを実装。MappingDispatchAction のように executeでないメソッドが呼べるが、URLを見てディスパッチするのでstruts-configにparamaterを指定しなくていい。たとえば /hoge/create.do に対しては createメソッドが呼ばれる。リフレクションは空気のように使おう。ビジネスロジック的な処理で使うべきではないがこーいう場面では活用しよう。
このときコントローラメソッドの ActionForm には型パラメータを使えるようにする。どうせ定義するであろうCRUDメソッドはabstractメソッドとして記述しておくと継承クラス作成時にコード補完で楽できる。
public abstract class CrudAction<E extends ActionForm> extends Action { private static Log log = LogFactory.getLog(CrudAction.class); @SuppressWarnings("unchecked") public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse res) throws Exception { // SuppressWarnings below E eform = (E)form; String path = mapping.getPath(); String methodName = path.substring(path.lastIndexOf('/') + 1); try { Method method = this.getClass().getMethod(methodName, ActionMapping.class, eform.getClass(), HttpServletRequest.class, HttpServletResponse.class); if (Modifier.isPublic(method.getModifiers())) { ActionForward forward = (ActionForward)method.invoke(this, mapping, eform, req, res); if (forward != null) { return forward; } } } catch (NoSuchMethodException e) { String message = "Method " + methodName + " is not defined." ; log.error(message); throw new ServletException(message); } return this.unspecified(mapping, form, req, res); } public abstract ActionForward delete(ActionMapping mapping, E form, HttpServletRequest req, HttpServletResponse res) throws Exception; public abstract ActionForward create(ActionMapping mapping, E form, HttpServletRequest req, HttpServletResponse res) throws Exception; public abstract ActionForward update(ActionMapping mapping, E form, HttpServletRequest req, HttpServletResponse res) throws Exception; public abstract ActionForward edit(ActionMapping mapping, E form, HttpServletRequest req, HttpServletResponse res) throws Exception; public abstract ActionForward list(ActionMapping mapping, E form, HttpServletRequest req, HttpServletResponse res) throws Exception; protected ActionForward unspecified( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { response.sendError(404, "Forwarding Action Not found."); return null; } }
これを継承したCrudActionの実装は
public class HogeAction extends CrudAction<HogeForm> { @Override public ActionForward delete(ActionMapping mapping, HogeForm form, HttpServletRequest req, HttpServletResponse res) { this.hogeDao.deleteById( form.getId() ); } @Override public ActionForward list(ActionMapping mapping, HogeForm form, HttpServletRequest req, HttpServletResponse res) { form.setHoges( this.hogeDao.findAll() ); } // 以下略 }
キャスト不要で便秘が解消したようにすっきりした。Strutsの良いところは拡張が簡単なこと。最近のStruts開発は色々なツール使って楽してるのだろうけど、そういうのが準備できない場合でも小細工して奇麗にコード書けるよ、という辺りでよろしく。
個人的にはS2Struts使うのが幸せになれると思いますよ〜