Struts開発パターン3

今回は今までのパターン1,2と比べてガラリと実装方法を変えています。
今までのパターン1,2は、アクションの実装単位がイベントごと、文字通りアクション単位で作成していたわけです。具体的には、リンクのクリックや、サブミットボタン押下時のイベントで、1つのアクションを作っていました。
これはこれで1つの完成系なのですが、違う実装方法として、画面単位でアクションを作成している例を紹介します。

パターン3は、1 JSP-1 Action-1 ActionFormです。
クラス構成を考えるときには、全部が1対1で対応するので、頭を悩ませずに定型的になります。その代わり1 Actionで全てのイベント処理を実装するので、1Actionあたりの記述量は増えてしまいます。

前提条件の資料は以下のとおりです。

今回は、さらに2つのサブミットボタンによるイベント切り替えを実装するために、削除機能を編集画面に用意してみます。
パターン3 ロバストネス図

アクションとJSPの関係

BaseActionは、DispatchActionを継承しています。Dispatchアクションは1つのアクションクラスで複数のイベントを処理できます。
Dispatchアクションは、複数のメソッドをパラメータによって振り分けて実行してくれます。

通常のAction
  • アクションパス/action-foo   → ActionFooのexecuteメソッド
  • アクションパス/action-bar   → ActionBarのexecuteメソッド
  • DispatchAction
  • アクションパス/action-foo パラメータ=select   → ActionFooのselectメソッド
  • アクションパス/action-foo パラメータ=update   → ActionFooのupdateメソッド
  • 1つのActionクラスで、2つのイベント(select,update)を処理できます。
    パラメータは、任意の名称をつけることができ、struts-configのaction-mappingのparamterで指定できます。
    作成したサンプルでは、cmd(コマンド)という名前を使うようにしています。

    1 JSP – 1 Actionなので、アクションはいくつ作ればよいだろうかという悩みはなくなりました。
    ActionFormはActionがJSP単位で作成されるので、必然的にJSP単位で作成することになります。

    1 JSP – 1 Actionのルールをより明確にするため、JSPから呼び出されるActionは必ず対応しているActionとしています。
    例えば、一覧画面における「編集リンク」は、そのまま編集画面の表示アクションを呼べばよいわけですが、あえて一覧画面のアクションを呼び出し、一覧画面アクションから編集画面アクションへaction-chainしています。

    1 JSPから呼び出されるActionは、常にその画面用Actionになっています。つまりJSP側にはどの画面に遷移するかわ分からないのです。どの画面に遷移するかは、struts-configのaciton-mappingに記述されることになります。
    一覧画面の「編集リンク」に編集画面へのアクションパスを記述してしまうと、JSPに画面遷移を記述したことになり、JSPを見ないことにはどの画面に遷移するのかが分かりません。

    意味としては、一覧画面の「編集」リンクは、「編集リンクをクリックした」ということだけ、サーバーに通知しそれがどこに遷移するかをサーバサイドで決定してしまうわけです。
    したがって画面遷移はすべてaction-chainで実装されることになります。

    このようなルールで記述したaction-mappingはこのようになります。

    
    <action path="/03/ProductList" scope="request"
      type="struts.kenkyu03.action.ProductListAction"
      parameter="cmd">
      <forward name="list" path="/WEB-INF/jsp/03/ProductList.jsp"/>
      <forward name="edit" path="/03/ProductEdit.do?cmd=edit"/>
      <forward name="editnew" path="/03/ProductEdit.do?cmd=editnew"/>
    </action>
    
    <action path="/03/ProductEdit" scope="request"  name="ProductEditForm3"
     type="struts.kenkyu03.action.ProductEditAction"
      parameter="cmd">
      <forward name="edit" path="/WEB-INF/jsp/03/ProductEdit.jsp"/>
      <forward name="success" path="/03/ProductList.do?cmd=list"/>
    </action>
    

    一覧画面から呼び出されるイベント(=コマンド)は、forwardのところに集約されており、「一覧表示」、「編集」、「新規作成」となります。それぞれ、「一覧画面のJSP」、「編集画面のeditイベント」、「編集画面のeditnewイベント」が呼び出されることが分かります。
    もしもJSPに編集画面へ遷移する記述があると、ここは、<forward name="list" ...>だけになってしまいます。

    コマンドパラメータの切り替え

    JSPの方は、今までアクションパスを変えることが、呼び出すイベントを切り替えることになっていたのですが、今度は意味が変わります。
    アクションパスは画面用Action固定になり、代わりにパラメータ(cmd)の値を切り替えることになります。
    リンクの場合は、GETでクエリ文字列で?cmd=editとか、?cmd=editnewと渡しています。
    編集画面のsubmitボタンでは、hiddenのフォーム部品(cmd)を用意し、JavaScriptで実行時に切り替えています。
    2つのsubmitボタンのイベント

    JavaScriptで切り替えなくても、submitボタンにvalue値が設定できるので、そこでcmd用の設定値をセットすればよいのですが、HTMLの仕様上、submitボタンのvalue値はボタンのキャプションになってしまうので、そう簡単には変えられません。
    LookupDispatchActionというのは、それ考慮して、リソース文字列を逆検索する仕様になっているのですが、それも面倒くさいしキャプション文字列を使うことがイマイチだと思います。それならJavaScriptで切り替えたほうがマシだと思います。

    検索してみたら、上手い実装をしている例がありました。

    ずんWIki – Java Tips 「EasyDispatchAction」
    使い方は <input type="submit" name="_edit_" value="編集" /> って感じの submit ボタンを置くだけ。

    • このボタンが押された場合は edit メソッドが起動される。
    • もちろん同じフォーム内に name=”_delete_” な submit があってそれを押せば delete メソッドが起動できる。
    • _XXX_ という形のパラメータが無ければ DispatchAction に習って unspecified メソッドが呼ばれる。
    • name=”_edit_” が押された場合に edit というメソッドが無ければ mapping.findForward(“edit”) をしてくれるので、単に他のActionにフォワードするだけのディスパッチメソッドの場合は forward を設定するだけで良く、メソッドの実装すら要らない楽チン仕様。

    なるほど、value属性とボタンのキャプションが一緒だから、nameを使ってしまうわけです。しかもname属性は見た目に影響しないし、サーバーへの送信にも使えるので便利ですね。これを使えば、JavaScriptを使わず、複数のsubmitボタンで呼び出すイベントを切り替えられます。(あとで補足サンプルとして作ってみます)
    追記:開発パターン3の補足として作成してみました

    今回もDAOやDTOは作成していません。
    しかしながら、Actionクラスに複数のイベントが記述されるので処理が長くなってきています。そろそろDAOくらいは作ったほうがよいように思います。パターン4ではDAOを導入してみようと思います。

    開発パターン3

    • DTO使用せずに汎用的なコレクションを使用
    • DispatchActionクラスを継承して作成
    • DAOを作成せずに、Actionクラスでビジネスロジックを作成
    • 1 JSP-1 Action-1 ActionFormのルールで作成(ActionFormのないActionも可)
    • 画面内のイベントを、1 Actionで全て記述する

    ソースコードはこちらです。(kenkyu03パッケージが今回の対象です)
    kenkyu03.zip


    Struts開発パターン3」への7件のフィードバック

    1. はじめまして。
      大変貴重な内容で参考にさせていただいております。
      実際にEasyDispatchActionを使用してsubmitを使い分けようと考えているのですが、submitボタンを押したときにnameで指定した _edit_ が飛びません。
      アドレスの最後に直接 ?_edit_ を加えてやれば仕様どおりに動くのですが、JSPからsubmitしてやるとアドレスが .jsp で終わってしまいます。

    2. お忙しい中、ご返答誠にありがとうございます。
      大変申し訳ございません、書き間違えてしまいました。jsp→actionに飛ばしているのでアドレスの最後は.doで終わっております。jspでsubmitした時、.doの後ろに?_edit_がついていきません。
      サンプルをダウンロードさせて頂き同じように書いてみたのですがうまくいかない状態です。
      受け取るaction側は問題がないようなので(手動で?_edit_をつければ動くので)jsp側のどこかがおかしいのだとは思うのですが、何かjsp側でやっておかなければならない設定というのはあるのでしょうか?造りとしては名前、住所などを入力してsubmitで飛ばしております。
      何かお心あたりが御座いましたらお聞かせ頂ければ幸いです。

    3. 勘違いしていることがあると思うのですが、submitさせたときにURLの後ろに_edit_はつきません。
      POSTしたリクエストデータにnameが_???_という形式が含まれていれば、それを判断してexecuteするメソッドを決定します。それがEasyDispatchActionの役割です。
      さて、nameで_edit_と指定したsubmitボタンでPOSTしたときに、acitonのメソッドeditが動作しますか?であれば、それで問題はありません。
      >受け取るaction側は問題がないようなので(手動で?_edit_をつければ動くので)
      とあるので、submitボタンのname属性に、ちゃんと_edit_が設定されているかぐらいしか思いつきません。

    4. 度々ありがとうございます。
      nameで_edit_と指定したsubmitボタンでPOSTした時、acitonのメソッドeditが動作せずに真っ白の画面が出てしまいます。現在actionの中にメソッドはeditのみを置いております。
      submitボタンもname=”_edit_”がしっかり入っているのですが・・・。
      最終的にはLookupの方に切り替えるという手もありますし色々試行錯誤してみようと思います。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)