0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Struts2のValueStackの構造

Last updated at Posted at 2022-12-23

概要

Struts2ではView-Model間のデータ受け渡しやOGNL式の適用対象としてValueStackを利用している。ValueStackはインターフェースでありStruts2におけるデフォルトの実装はOgnlValueStackである。
ここではOgnlValueStackの構造と利用方法について説明する。

ValueStackの構造

ValueStackはrootとcontextの2つの領域で構成される。

名称 説明
root CompoundRoot OGNL式に指定したプロパティやメソッド呼び出しの対象となるオブジェクトが格納されるスタック。Actionクラスのインスタンスなどが格納される。スタックなので後から格納された項目から取り出される。
context OgnlContext HTTPリクエストやセッションなどが格納されるMap。OGNL式からそれらにアクセスする際に使用される。

image.png

ValueStackに格納される値

Action実行時にはValueStackは以下の状態になっている。
image.png

格納される値の詳細
名称 説明
root
Action 実行されるActionのインスタンス。ActionInvocationによってスタックの先頭に格納される
TextProvider プロパティファイルからi18nに対応したメッセージの取得を行う。ValueStack作成時に最初に格納される。
context
VALUE_STACK 正式なキーはcom.opensymphony.xwork2.util.ValueStack.ValueStack。ValueStack自身
CONTAINER 正式なキーはcom.opensymphony.xwork2.ActionContext.container。StrutsPrepareAndExecuteFilterまたはStrutsExecuteFilterが保持するDIコンテナ
PARAMETERS 正式なキーはcom.opensymphony.xwork2.ActionContext.parameters。HttpServletRequestのgetParameterMap()をラップしてMapインターフェースでアクセスできるようにしたもの
SESSION 正式なキーはcom.opensymphony.xwork2.ActionContext.session。HttpSessionをMapとしてアクセスできるようにラップしたSessionMap
APPLICATION 正式なキーはcom.opensymphony.xwork2.ActionContext.application。ServletContextをMapとしてアクセスできるようにラップしたApplicationMap
LOCALE 正式なキーはcom.opensymphony.xwork2.ActionContext.locale。リクエストから取得したロケール
HTTP_REQUEST 正式なキーはcom.opensymphony.xwork2.dispatcher.HttpServletRequest。HttpServletRequest
HTTP_RESPONSE 正式なキーはcom.opensymphony.xwork2.dispatcher.HttpServletResponse。HttpServletResponse
SERVLET_CONTEXT 正式なキーはcom.opensymphony.xwork2.dispatcher.ServletContext。ServletContext
request HttpServletRequestをラップしたRequestMap
session SESSIONと同じ値。OGNL式で#sessionとして参照する。
application APPLICATIONと同じ値。OGNL式で#applicationとして参照する。
parameters PARAMETERSと同じ値。OGNL式で#parametersとして参照する。
attr OGNL式で#attrとして参照する。contextにPAGE_CONTEXTがあればそこから値を取得し、なければ上記のrequest、session、applicationの順に最初に値が見つかったものを返す。
struts.actionMapping リクエストに紐づくActionMapping

Actionやインターセプターで例外が発生した場合、発生した例外を保持したExceptionHolderがpushされて以下の状態になっている。
image.png
例えばエラーページのJSP内で以下を記述するとExceptionHolderクラスのgetExceptionメソッドが呼び出されて画面に例外クラス名とメッセージが表示される。他にもexceptionStackでスタックトレースを表示できる。

JSP
<h1>Error</h1>
<s:property value="exception"/>

image.png
Struts2のいくつかのタグはタグの開始時に属性で指定されたオブジェクトをpushすることでタグ内でその効果を使用できるものがある。

  • <s:iterator>
JSP
<s:bean name="org.apache.struts2.example.IteratorExample" var="it">
  <s:param name="day" value="'foo'"/>
  <s:param name="day" value="'bar'"/>
</s:bean>

<table border="0" cellspacing="0" cellpadding="1">
<tr>
  <th>Days of the week</th>
</tr>

<s:iterator value="#it.days" status="rowstatus">
  <tr>
    <s:if test="#rowstatus.odd == true">
      <td style="background: grey"><s:property/></td>
    </s:if>
    <s:else>
      <td><s:property/></td>
    </s:else>
  </tr>
</s:iterator>
</table>

上記の<s:iterator>の内部では以下のように#it.daysの要素1つが順にpushされる。また、status属性の値をKeyとしてIteratorStatusがcontextに格納される。
image.png
そのため<s:property/>と記載するだけで'foo'や'bar'が画面に出力され、#rowstatusでIteratorStatusにアクセスしてループ処理のステータスが取得できる。<s:property/>のvalue属性を省略した場合、value="top"が指定されたとみなされrootの先頭の値が表示される。
image.png

  • <s:generator>
JSP
<s:generator val="%{'aaa,bbb,ccc,ddd,eee'}" separator=",">
  <s:iterator>
    <s:property /><br/>
  </s:iterator>
</s:generator>

上記の<s:generator>の内部では以下のようにIteratorGeneratorがpushされる。IteratorGenerator自体はイテレータであり、<s:iterator>で要素に対して繰り返し処理を行うことができる。
image.png
先ほどと同じように<s:iteretor>の中では<s:property/>と記載するだけで'aaa'や'bbb'が画面に出力される。
image.png
<s:sort>、<s:subset>も同様の原理になっており並び替え、部分集合の作成を行うイテレータを生成してrootにpushする。

  • <s:i18n>
JSP
<s:i18n name="myCustomBundle">
  The i18n value for key aaa.bbb.ccc in myCustomBundle is <s:property value="getText('aaa.bbb.ccc')" />
</s:i18n>
myCustomBundle.properties
aaa.bbb.ccc=Hello!!

上記の<s:i18n>の内部ではname属性に指定したプロパティファイルから値を取得するResourceBundleTextProviderがpushされる。
image.png
そのためタグ内でgetTextメソッドを使用するとmyCustomBundle.propertiesから値が取得される。
image.png

  • <s:push>
JSP
<s:push value="struts.actionMapping">
  namespace:<s:property value="namespace" /><br/>
  name:<s:property value="name" /><br/>
  method:<s:property value="method" />
</s:push>

value属性に指定した値をrootにpushする。
image.png
value属性に指定した値はOGNL式として評価されるのでcontextに格納されている値を取得するのに利用できる。contextの値は通常#...で取得するが、ピリオドを含むKeyは取得できないのでPushタグでrootにpushしてやることでアクセスすることができる。
image.png

  • <s:bean>
JSP
<s:bean name="org.apache.struts2.example.IteratorExample" var="it">
  <s:param name="day" value="'foo'"/>
  <s:param name="day" value="'bar'"/>
</s:bean>

<s:iterator>のところでも記載した<s:bean>タグも、自身をrootにpushすることでタグ内に記載した<s:param>の設定対象が自身になるようにしている。pushした自身は</s:bean>でrootから削除されてしまうのでvar属性を指定することでcontext側に格納し後続で使用できるようにしている。
image.png

ValueStackへのアクセス

OGNL式でValueStackのrootにアクセスする方法を以下に示す。
※<s:property value="簡単に言うとここに指定する値"/>

説明
フィールド名/メソッド名 rootに格納されているインスタンスのフィールド名/メソッド名を指定すればそのフィールド/メソッドを持つインスタンスをrootの先頭から順に検索し最初に見つかったものを取得/実行する。ただしStruts2ではtoStringなどObjectクラスのメソッドについてはオーバーライドしなければ呼び出せないように制限されている。
root root自身を返す。次のような配列になる[org.demo.actions.HelloAction@728fc979, com.opensymphony.xwork2.DefaultTextProvider@77783003]
#root rootと同じ
top rootの先頭の要素を返す。<s:property>タグでvalue属性を指定しなかった場合はtopを指定したとみなされ同じ結果になる。
[0].top rootの先頭の要素。[0]は先頭の要素以降を返却しそのtopを取得するので先頭の要素になる。
[1].top rootの2番目の要素。[1]は2番目の要素以降を返却しそのtopを取得するので2番目の要素になる。

contextにアクセスする方法は以下のとおり。

説明
#application JSPのアプリケーションオブジェクト
#session セッション
#request リクエスト情報
#parameters リクエストパラメータ
#attr JSPのページコンテキスト。ページコンテキストがなければ上記のrequest、session、applicationの順に最初に値が見つかったものを返す。

contextには上記以外に"struts.actionMapping"のようにピリオドを含むキーで値が格納されているものがあり、それについては<s:push>で説明した方法でアクセスすることができる。

ValueStackのライフサイクル

ValueStackはリクエストの度に生成される。詳細にはStrutsPrepareAndExecuteFilterまたはStrutsPrepareFilterで生成されるPrepareOperationsクラスによりValueStackFactoryを使って生成される。
struts.xmlでChain Result(<result type="chain">)を使って複数のActionを繋げてページを表示させてもリクエストは1回なのでValueStackは最初に生成されたものが引き継がれていく。Chain Resultの場合、以下のように実行したActionがrootに積まれていく。そのためJSPではすべてのActionのプロパティを利用することができ、chainの組み方によって表示が変わるページを作ることもできる。rootに積まれるActionのプロパティは同じ名称のものがあれば下のActionから上のActionに引き継がれる。
image.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?