menu
書いてる野郎
orebike@gmail.com
大体の更新系の定番画面というのは
という流れになるはずなのでこれを順番に実装していく
今回は更新の一連の流れを担当するActionをHogeActionとして実装する。
まずHogeActionを作る。最初に表示される画面を担当するメソッドとしてindexを作成する。そして普通にindex.jspにルーティングするように記述する。
public class HogeAction { @Execute(validator = false) public String index() { return "index.jsp"; } }
それと対になるjspの /hoge/index.jspを作る。
<html> <head> <title>hoge index</title> </head> <body> <h1>This is index</h1> </body> </html>
そしてブラウザでアクセスしてみる。表示されたことを確認。これでベースが完成した
次に画面から値を受け取るところを作る。
SAStrutsでは画面から受け取る値はすべてformと呼ばれるクラスにいったん格納してactionにわたってくることになっている。なのでまず値を格納するための入れ物としてのクラスHogeFormを作る
画面とformクラスは密接な関係があるので名前をわかりやすく統一しておいたほうがいいだろう。
今回はHogeActionで使うformをHogeFormにした。ケツにFormをつけるのはそういうルールだから。
formパッケージにHogeFormという名前でクラスを作ってそのpublicメンバにidという名前のStringの入れ物を一個作ってみた。 SAStrutsではこのようなpublicなメンバ変数をpropertyと呼んだりする。
public class HogeForm { public String id; }
今度はHogeActionのほうにこのHogeFormを格納する入れ物を作る。 メンバを宣言してアノテーションでこのメンバがこのActionでのActionFormであることと、DIを要求していることを伝える
こういう風に記述しておくと、このActionがらみの動きがあった場合画面からのリクエストパラメータのキーで ActionFormと一致するものがあったら自動的にそのActionFormにセットされてそのセットされたActionForm、今で言うHogeFormのインスタンスが自動的にthis.hogeFormに格納される仕掛け。
public class HogeAction { @ActionForm @Resource protected HogeForm hogeForm; @Execute(validator = false) public String index() { return "index.jsp"; } }
注意として制限がある。1つのActionには1つのActionFormしか持てないようになっている。 このことから、Actionの分割単位はFormの分けということになる。
つまり画面をシンプルな機能で分割し設計せよということだな。なんでも間でも1個の画面に詰め込んでグチャグチャにするなよということ
ここまでできたので次は入力フォームを作る。
先ほどのJSPに書き足して
<html> <head> <title>hoge index</title> </head> <body> <h1>This is index</h1> <s:form method="POST"> id:<html:text property="id" /> <s:submit property="inputConfirm" /> </s:form> </body> </html>
こうする。s:formタグを使ってフォームを宣言する。
このタグは↓のようなHTMLを生成する。
<form name="hogeActionForm" method="POST" action="/sample01/hoge/"> <input type="text" name="name" value=""> <input type="submit" value="Submit" name="inputConfirm"> </form>
s:form
というのはコンテキストを意識した送信先(action)が自動セットされる仕掛けのタグということ。このままでは送信先は HogeAction の index メソッドを指しているように見える。しかしここはフレームワークのコントローラーが Action クラス中のメソッド名と一致する key をもつパラメータをブラウザが送るとそのメソッドが呼び出される仕掛けになっている。
これはブラウザが押したボタンのパラメータしか送出しないことを利用し、一個のフォームに対して複数の送信先が存在した場合ボタンで挙動を変化させられるようにするためだ。 なので今回は submit ボタンの name に指定されている inputConfirm メソッドに処理がジャンプするようになるということ。
送信を受けるinputConfirmメソッドをHogeActionに追記する。
public class HogeAction { @ActionForm @Resource protected HogeForm hogeForm; @Execute(validator = false) public String index() { return "index.jsp"; } @Execute(validator = false) public String inputConfirm() { return "confirm.jsp"; } }
データを受けて遷移する、/hoge/confirm.jspも作る
<html> <head> <title>hoge confirm</title> </head> <body> <h1>This is confirm</h1> </body> </html>
動かしてみる /hoge/ でアクセスしてテキストボックスに何か入れて送信する。 画面に
This is confirm
が出て完了
入力画面からActionに値を渡すのがFormの役割だった。なので値を取り出そうと思えば、もうすでにthis.hogeFormに入っているのでこいつをただ単に取り出すだけでよい。
逆にActionから画面へ値を持っていくにはDTOというクラスを使った仕組みで持っていく。このDTOというオブジェクト経由で画面にもっていくことにする。
画面に表示したい項目は決まっているわけだからこの塊を DTO というインスタンスに入れることにする。dto パッケージがもうすでにできているのでここに HogeDto クラスを実装する。実際の実装では entity をそのままスライドして持っていくことも多いだろう。
今回はFormと同じidだけを表示するのでidのpropertyを1個だけ持ったDTOを作成する。これだけ・・・恐ろしく単純
public class HogeDto{ public String id; }
そしてこの DTO を Action のメンバとして保持するように記述する。このように public なメンバとして保持する。public なメンバは自動的にインジェクションの対象になるので、newの必要もなく使えるようになる
public class HogeAction { @ActionForm @Resource protected HogeForm hogeForm; public HogeDto hogeDto; @Execute(validator = false) public String index() { return "index.jsp"; } @Execute(validator = false) public String inputConfirm() { return "confirm.jsp"; } }
Action に来ている時点で form と dto 共にインジェクションされて存在しているので、Form からの値を普通に dto に受け渡す
@Execute(validator = false) public String inputConfirm() { hogeDto.id = hogeForm.id; return "confirm.jsp"; }
Action中でpublicなメンバはJSP中でEL式で呼び出すことができる。EL式の中でメンバ名そのものでズバリ取り出すことができる。
<html> <head> <title>hoge confirm</title> </head> <body> <h1>This is confirm</h1> id:${hogeDto.id} </body> </html>
これはなぜ出来るかというと、DI コンテナ側が JSP へ渡す時点で id メンバの getter を自動的に実装してくれるからである。
では別のActionのメソッドを呼び出すにはどうすればよいだろうか?
大体の更新系の定番画面というのは フォームの表示 クライアントサイドでのvalidate サーバサイドでのvalidate →だめならフォームに押し返す(値の復元+エラーメッセージ) 確認画面の表示 更新処理 確認画面の表示
という流れになるはずなのでこれを順番に実装していく
今回は更新の一連の流れを担当するActionをHogeActionとして実装する
まずHogeActionを作る
public class HogeAction { @Execute(validator = false) public String index() { return "index.jsp"; } }
それと対になるjspの /hoge/index.jspを作る
<html> <head> <title>hoge1</title> </head> <body> <h1>This is hoge1.</h1> </body> </html>
そしてブラウザでアクセスしてみる 表示されたことを確認
次に画面から値を受け取るところを作る SAStrutsでは画面から受け取る値はすべてformと呼ばれるクラスにいったん格納してactionにわたってくることになっている なのでまず値を格納するための入れ物としてのクラスHogeFormを作る
このことからわかるように画面の形態とformクラスは密接な関係があるので名前をわかりやすく統一しておいたほうがいいだろう だから今回はHogeActionで使うformをHogeFormにした。ケツにFormをつけるのはそういうルールだから。
このルールを守ることでHogeFormはActionFormクラスの継承をしなくてもいいことになっている。 つまりPOJOになるのでテストが容易になるという仕掛け
formパッケージに HogeFormという名前でクラスを作ってそのpublicメンバにnameという名前のStringの入れ物を一個作ってみた。 SAStrutsではこのようなpublicなメンバ変数をpropertyと呼んだりする。
public class HogeForm { public String name; }
これでOK
今度はHogeActionのほうにこのHogeFormを格納する入れ物を作る メンバを宣言してアノテーションでこのメンバがActionFormであることと、DIを要求していることを伝える
こういう風に記述しておくと、このActionがらみの動きがあった場合画面からのリクエストパラメータのキーで ActionFormと一致するものがあったら自動的にそのActionFormにセットされてそのセットされたActionForm、今で言うならHogeFormのインスタンスが自動的にthis.hogeFormに格納される仕掛け。
public class HogeAction { @ActionForm @Resource protected HogeForm hogeForm; @Execute(validator = false) public String index() { return "index.jsp"; } }
制限もあり、1つのActionには1つのActionFormしか持てないというルールがある。 この流れから、Actionの分割単位はFormの分けということになる。
つまり画面を単機能で分割し設計し、Actionのシンプルさを保てということ
なんでも間でも1個の画面に詰め込んでグチャグチャにするなよということ
ここまでできたので次は入力フォームを作る
先ほどのJSPに書き足して
<html> <head> <title>hoge1</title> </head> <body> <h1>This is hoge1.</h1> <s:form method="POST" action="input"> what is your name?<html:text property="name" /> <s:submit value="okuru" /> </body> </html>
こうする。s:formタグを使ってフォームを宣言する。
このタグは↓のようなHTMLを生成する。
<form name="hogeActionForm" method="POST" action="/sample01/hoge/input"> <input type="text" name="name" value=""> <input type="submit" value="okuru"> </form> </html>
つまりコンテキストを意識した送信先が自動セットされる仕掛けのタグということ OK そして受けを作る。この辺はstrutsっぽくて受けのメソッド、今回ならばinputが作ってないとエラーで落ちる
受けのinputメソッドをHogeActionに追記する
public class HogeAction { @ActionForm @Resource protected HogeForm hogeForm; @Execute(validator = false) public String index() { return "index.jsp"; } @Execute(validator = false) public String input() { return "input.jsp"; } }
それに対を成す/hoge/input.jspも作る
<html> <head> <title>hoge2</title> </head> <body> <h1>This is input</h1> </body> </html>
動かしてみる /hoge/ でアクセスしてテキストボックスに何か入れて送信する。 画面に This is input が出て完了
さらにもうひとつ仕掛けがあって、index.jspをこのように書き換えてみる
<html> <head> <title>hoge1</title> </head> <body> <h1>This is hoge1.</h1> <s:form method="POST"> what is your name?<html:text property="name" /> <s:submit property="input" value="okuru" /> </body> </html>
formのaction属性のinput記述をsubmitのproperty属性に移したバージョンを作ってみる。
これで動かしても実はちゃんと動くのだ。
生成されたHTMLソースを見てみると、
<input type="submit" name="input" value="okuru" />
ということになっている。
初心者がよく知らないinput submitの性質として、押したボタンのみ値が送られるという挙動がある。 つまりここではボタンを押すことで input=okuru というパラメータが送出されていることになる。
SAStrutsのコントローラがパラメータ中のkeyに注目しFormクラスのpropertyには存在しないが、ActionFormクラスのメソッドに 合致するkeyがあった場合、そちらにルーティングしてくれるという機能なのだ。
なのでsubmitボタンを二つ配置してnameを変えておけば押したボタンのkey=valueしか送出されないのだから押すボタンによって formのactionを変えずに動的に呼び出すメソッドを切り替えられるということ
おまけだが、HTTPのリクエストパラメータというのは文字列でしかないということ。 つまりActionFormに合致しないキーのパラメータをどういう形であれ送りつければ別にsubmitに実装しなくてもメソッド指定はできるのだ だからformタグ内に
<input type="hidden" name="input" value="okuru" />
と記述しておいてsubmitからpropertyを除去してもinputメソッドにルーティングされる。
では別のActionのメソッドを呼び出すにはどうすればよいだろうか? 答えは簡単だった・・・w 別Actionということは機能的にもぜんぜん別モノなのでパラメータなんか使いまわさない つまり単にリンクで飛べ