【Struts2】s:actionタグでJSP内でAction実行し値だけを取り込む

- Java/Struts2 -
2019.10.23
struts2

Struts2では、ひとつのActionを実行すると、以下のようにひとつのJSPが返ってきます。

Struts2 s:action

しかしこれだと、実行されたActionからしか値を受け取れないことになります。

struts2 s:action

そこで、Struts2でものを作っていた時に「他のActionも同時に実行して値だけを取り出せないかなぁ・・・」と思うことがありました。

s:action

調べてみると、これはJSPに<s:action>タグを埋め込むことで可能になることが判明。

手順❶

値を取り込みたいJSPに以下を書く ※xxx, yyyは適宜置き換えること

<s:action name="xxx"/>

手順❷

struts.xmlに以下を書く

<action name="xxx" class="{パッケージ名}.yyyAction"></action>

ここでyyyAction.javaではgetterメソッドを置いてValueStack経由かsession.putして値をJSPで取れるようにする。

普段何気なく書いている<result name="success">は不要。Action実行結果の値だけを吸い取るのでJSPは使われません。

手順❸

手順①のJSP上で以下のように書く ※userNameを取得したい場合の例

・ValueStackから取る場合

<s:property value="#yyyAction.userName"/>

・sessionから取る場合

<s:property value="#session.userName"/>

sessionから取る場合は普通の記法と変わりません。

また、この例ではs:propertyタグで書いてますが他のs:タグでも同じ記法で取り出せます。

これ、毎Actionでわざわざ実行すんの?という処理に置き換えられそう

本来はどんな目的でどんな使い方をされるのか、文献が少なくてよく分かりません。。ですが、自分がコード書いてて「こういう時使えばいいんじゃね?」というのが一つ。

例えば、以下のプルダウンリスト。

これをJSPでは、以下のように書いているとします。

Struts2 <s:action>

このプルダウンリストのひと癖あるところは、JSPに「CD」「DVD」「ゲーム」と決め打ちしていない点です。

#session.とあるように、ActionでDBのカテゴリーテーブルからDAOで検索したカテゴリー一覧をsession.putしたListを参照して動的に生成されたプルダウンメニューになってます。

カテゴリ名をわざわざDAOで引っ張ってきている理由は、カテゴリが後々追加されることになってもコードを変更することなく追加したカテゴリを勝手に表示してくれるようにするため。

この商品カテゴリのプルダウンメニューはどのページに遷移しても常に表示されている必要があり、sessionタイムアウトによって表示されなくなってしまうなんてことが起きてはいけません。

なので、「もしsessionにcategoryListがcontainsKeyされてなかったら(=セッション切れが起きたら)DAOを実行してカテゴリーListをsession.putしろ」という処理を全Actionにif文で書いていました

Struts2 <s:action>

こうしないと、もしセッションが切れてしまったとしたらJSPでカテゴリのプルダウンが表示されなくなってしまうからです。

・・・って全Actionに繰り返し書くとか完全にDRY原則に違反してるじゃん!!!

今はまだActionクラスの数が10〜20個の範囲なので全Actionに書いてもまぁいけるのですが、これがガチシステムでActionの数が何百何千となるとコピペもきつくなるしミスも起きそうです。

というわけで、JSPに繰り返し値を送るだけの処理は別Actionクラスとして切り出してJSP上に<s:action〜>と書いてしまえば各Actionからその処理を全消しすることが可能になります。

今回の例でいうと、PullCategoryActionとかいうActionクラスを別に作ってしまい、JSPに

<s:action name="PullCategoryAction"/>

と書いてしまえば他の全ActionにこのカテゴリーListを送りこむために書いていたif文は不要になるということですね。

<s:action>を書く位置

<s:action name="xxx"/>ってJSPのどこに書けば良いんだろう?と疑問に思って試してみました。

結果、<s:action/>は取り出したい行よりも上に書く必要があるようです。

これだとOK

<s:action name="yyyAction"/>
<s:property value="#yyyAction.userName"/>

これでもOK

<s:action name="yyyAction"/>
・・・他の記述・・・
・・・他の記述・・・
・・・他の記述・・・
<s:property value="#yyyAction.userName"/>

これだとNG!

<s:property value="#yyyAction.userName"/>
<s:action name="yyyAction"/>