以前の記事(Struts開発での考察)から継続してStrutsの開発パターンを1つ作成してみました。
とても作成するものが少ないパターンだと思います。
まず前提として、データベースの構造なんですが、商品データベースの一覧画面を想定しています。
画面のイメージはこんな感じを想定しています。
一覧画面のイメージ、編集画面のイメージ
特に難しいことはないと思います。
このテーブルに対する一覧画面と、編集画面を作成することを考えて、ロバストネス図を書きました。
初めに動作するのは、検索アクションです。DBからProductsテーブルを全件検索し、一覧画面に検索結果を渡します。
一覧画面の「編集」リンクをクリックすると、その商品の編集画面を表示します。これが編集アクションです。編集アクションは、編集画面を表示するだけの処理で、更新処理は行いません。
編集画面から「更新」ボタンを押すと、更新アクションが動作します。更新アクションはデータベースの更新処理を行い、更新アクション自体は画面を表示せず、検索アクションに連鎖します。
<
は、ブラウザからのサーバへのHTTPリクエストの流れになります。
<
は、ActionからJSPへのフォワードになります。
<
は、ActionからActionへのフォワードのことですが、
Action-Action間の連鎖を区別してaction-chainと呼んでいます。
ここでは、更新処理が終わった後に、検索処理に連結して、再び一覧画面を表示するために使っています。更新アクション中に、検索のための処理を記述する必要はなくなります。
ソース
このソースファイルはkenkyu01.zipになります。
Struts関係のライブラリは、サイズが大きくなるので削除してあります。(WEB-INF/lib配下)
DB周りの操作にDBUtilsを使っています。Strutsのカスタムタグはstruts-htmlのみ使用し、あとはJSTLを使用しています。
注目すべきところ
編集アクションでは、2つのActionFormを使っています。
1つは、一覧画面から送信されたものです。Strutsにより生成されたProductEditFormをキャストして使用します。
もう1つは、編集アクションでnewして生成したものです。編集画面には、formタグが配置されています。このアクションで使用するActionFormがProductUpdateFormであるため、これをnewしてsetAttributeしています。
編集アクションはDBからデータを取得して返却するわけですが、その返却の方法としてActionFormを使用しています。返却のためにActionFormを使用するのは、返却後にテキストボックスなどのform部品として使用する場合のみです。
それ以外のケースでは、リクエストスコープの変数を使って画面にデータを転送します。一覧画面では検索結果のListをリクエストスコープのデータとして返却しています。
Strutsの設計パターンというよりも,Webアプリの設計パターンになるのですが、データベースへの接続処理は、ServletFilterで行っています。
ServletFilterのinit処理で、DataSourceを取得し、あとは1つのHTTPリクエストごとに、DB接続を生成し、リクエストの終了時に切断しています。ActionServletを継承し、executeメソッドを呼び出す前にDB接続する方法もありますが、アクション連鎖の際に再び接続してしまうので、HTTPリクエストの単位でDB接続を継続するようにしました。
トランザクションは、例外が発生しなければ常にコミットし、例外発生時にロールバックするようにしました。このため、各アプリケーションではコミットやロールバックする必要はなく、例外を投げるか正常に終了するかで決定します。正常処理でロールバックするというケースは少ないので、このような実装にしました。
DTOについて
今回の設計パターンでは、DTO(Data Transfer Object)を使用していません。MapやListなどの汎用的なコレクションクラスで代用しています。
こうすることで、新たなクラスを作成する必要がなくなりますが、反面静的な型チェックが行われなくなります。
JSPで、${product.pname}
と記述できるのは、Mapに対して”pname”という文字列をキーに、商品名を格納してあるからです。
データベースから、検索した結果を、getString(フィールド名)で取得、DTOのプロパティに格納、JSPでデータ取得という作業が、DBUtils, BeanUtils, JSP-ELで非常に簡単に記述できています。
DAOについて
今回の設計パターンは、シンプルなパターンで、DAO(Data Access Object)は用意していません。
SQLがシンプルな場合などは、DAOを作成しなくてもActionクラスで処理してしまっていいのではないか?と思うのが私の考え方です。
DAOを作成する場合には、画面とは切り離して、Entityとしての役割を果たす形で考えるべきだと思います。
私の会社で開発している人を見ていると、DAOを作成するのはいいんですが、画面ごとにDAOを作成しているのを見かけます。そのため、同じようなSQLがあちこちのDAOに存在し、単にActionのソースファイルから、抜き出してDAOを作っているだけになっています。
そうなるくらいならば、Actionに記述したほうが、ロジックが分散しなくて見やすいです。どのみちDAO単独で再利用したりなんてしたことないし。(それどころか、DAOにActionFormを引き渡したりしているのを見かけたりもします←再利用できなくなる)
DAOの作成単位は、オブジェクト指向のモデリングによって決定すると思います。「画面1つにつきDAO1つ」とルール化したい気も分からないでもないですが、ルール化したければ、「テーブル1つにつきDAO1つ」の方が良いと思います。
ビジネスロジックの実装箇所について
Actionクラスから利用されるビジネスロジック用のクラスも作成していません。Actionに記述します。
ビジネスロジックは、別途作成した方がよいかも知れません。ですが本当にそのビジネスロジックを再利用できるように作成するつもりでビジネスロジックを別に分けるべきだと思います。分けたはいいが、結局、再利用できなくて別ファイルにロジックがジャンプしているだけにならないようにすべきです。
まとめると、今回の開発パターンはこのような感じです。
開発パターン1
- DTO使用せずに汎用的なコレクションを使用
- Actionクラスを継承して作成
- DAOを作成せずに、Actionクラスでビジネスロジックを作成
- 1Action-1ActionFormのルールで作成(ActionFormのないActionも可)
これをベースとして、他のパターンも応用して作成してみたいと思います。
DOONといいます。
はじめまして。
今回Strutsのプログラミングを始めてやることになって、
参考にしたくて読んでます。
できるだけソースを書きたくないので参考になります。
いままでVBで組んでたのですが、急にJavaをやれと・・・・。
私が今回やる画面では、html:linkに当たるところをみため的にボタンに
して欲しいといわれています。
(編集ボタン、新規作成ボタン)となります。
Action内での、振り分けは出来るのですが
Table内に貼ってある、複数のinput type=”submit”と
Table内のデータが、ひもづかないです。
真似をしながら作成していたのですが、そこで躓いています。
編集
のようなparamNameがinput typeにはなくて困っています。
Action-Chainはぜひ、実践したいのですが・・・。
Tableの列のユニークキーとinput Type=”submit”を関連付けるのが難しいです。
何行目のボタンがクリックされたかとかも、paramNameがないと判定しにくいです。
その場合、どのようにやられますか?
迷惑でなければ考え方を教えてください。
こんなのはどうでしょう?
input type=”hidden”で、選択された行を識別するコードを保持するようにします。(表示した時は空です)
submitボタンを押した時にonclickのJavaScriptでhiddenに選択行の情報をセット。
→これを使う場合にはonclick属性のJavaScriptコードを動的にセットする必要があります。
<td><html:submit onclick=”selectedPcode.value=’${product.pcode}'”>編集</html:submit>
…
<input type=”hidden” name=”selectedPcode”/>
DOONです。
早速の返事ありがとうございます。
JavaScriptですか。
Strutsではないということは、板違いの質問ですね。
申し訳ないです。
なんかhtml:linkを継承したbutton見たいなものが
作れるのかなーとか考えていました。
早速教えていただいたのをやってみようかと思います。
これは、ボタンクリックのアクション時に、
selectedPcodeをActionの中で取れるということなんですよね。
それすら、まだ理解できていません。
早速実践します。
明日までには報告できると思います。
すぐですいません。
DOONです。
ここで教えてもらったEasyDispatchActionを元に作成しています。
なので、をつかうと
タグ submit の属性 name は無効です’ とでてしまいます。
_edit_とかしています。
なんか、初歩的な質問で申し訳ないですね。
もう少し自分で考えます。
一つを優先すると、一つがおかしくなっての繰り返しで・・・。
今、 Input Type=”submit”でやっていまして、ボタンにも色をつけたいので
id=MYCOLORとかもやってまして・・。
それも、引っかかりそうです。
ごちゃごちゃです。
やはり、webはlinkでやるのが、基本なんでしょうかね?
もう一度、客先にレイアウト変更をだしてみようかなーと思っています。
いやいや、linkでなくてもできますよ。EasyDispatchActionを使う場合は、html:submitではなく、HTMLのinput type=”submit”でやらないといけません。
少し整理して落ち着いて考えてみてください。
DOONです。
やっと出来ました。
ありがとうございます。
昨日から今までかかりました。
上記でできました。linkではなくて、ボタンでやっていこうと思います。!!
を、テーブルのループ内に書いていまして、Actionで全然取れなくて・・・。
hiddenとかいて、nameをかくと、ActionFormで取れることに
びっくり。それすら分かっていませんでした。
input textとか、目に見えるものしかActionFormに渡らないと思っていました。
小さな会社なので、一人で、最初からやっていまして。
Strutsを実践するのは、難しいですね。本を読んでも、いざやるとなると。
JavaScriptも必要とは・・・。
ただonClickで、その押下されたボタンにある、行の値を取得するのが
${list.batchid}だけで、できるのは、楽です。
行指定が要らないんですもんね。GUIの考え方では、考えられないです。
超初心者ですいません。
今、Struts解発パターン4までを読ましてもらって、
納品プログラムに反映しています。Action-Chainがしたくて・・・。
他の所も随時、読ませてもらいます。
ありがとうございました。
はじめまして。Strutsを使用することになりました。
こちらの考察を読ませていただき、一連のStruts学習も読ませていただきたいと思っています。
2006年の記事は図やサンプルのリンクが切れているようなのですが、
再度ダウンロード出来るようにしていただくことは出来ないでしょうか?
いきなりでとてもあつかましいお願いですみません。
もし可能であれば宜しくお願い致します。
返答、遅くなってしまってスミマセン。。。
一応復元できるところは復元できました。
突然のお願いに対応していただき本当にありがとうございます!
嬉しいです。勉強させていただきます。