minimize

Top

自分用のメモ書きです。
ある程度まとまったら別ファイルで公開するかもしれません。

Struts

resetを実装する

フォームのある画面に遷移する時、そこから別の画面に遷移する時、
そのどちらからも Form.reset メソッドが呼ばれます。

フォームのある画面に遷移する時。
ただし、actionタグにname属性が存在した場合のみ。
resetが呼ばれた後、クエリー文字列として与えられた変数のsetXXXメソッドが呼ばれる。

フォームのある画面から遷移する時。
resetが呼ばれた後、画面の存在する全beanに対応するsetXXXメソッドが呼ばれる。

resetを設定していないと、
フォームのある画面に遷移する時は一部のsetXXXメソッドしか呼ばれないので
それ以外の変数が前回使用時のまま残った状況になってしまう。
その変数をexecute内で参照してたりすると、間違ったデータを参照してしまうことになるので
必要な変数は必ずresetメソッド内で初期化する事。

actionタグ解析

以下の例を考えてみる。

<form-beans>
  <form-bean name="makeDBTableForm" type="org.limy.struts.form.MakeDBTableForm"/>
</form-beans>
<action-mappings>
  <action path="/automake/editDBTable" type="org.limy.struts.action.EditDBTableAction"
    name="makeDBTableForm"  validate="false">
    <forward name="success" path="/automake/editDBTable.jsp" />
  </action>
  <action path="/automake/makeDBTable" type="org.limy.struts.action.MakeDBTableAction"
    name="makeDBTableForm" validate="false">
    <forward name="success2" path="/index.jsp" />
  </action>
</action-mappings>

フォームの無いページから、このアクションを利用してフォームのあるページ(editDBTable.jsp)に遷移する。

<html:link page="/automake/editDBTable.do">...</html:link>

まずは MakeDBTableForm.reset() が呼び出される。
そして、遷移時にクエリー文字列が付いていればそれに対応する setXXX() が呼ばれる。
その後で EditTableAction.execute() に処理が移る。
よって、このとき execute のパラメータである form には先程作成されたフォームが入っていることになる。

name属性が無い場合

もしactionタグのname属性が無い場合、executeに渡されるformはnullになる。

遷移先のeditDBTable.jspには<html:form>タグがある為、この画面を表示するにはformオブジェクトが必要になる。
具体的には、この<html:form>タグのaction属性が"/automake/makeDBTable"なので
actionタグの中でpath属性が"/automake/makeDBTable"のものを検索して
そのname属性に対応するformクラスのインスタンスということになる。
ここがちょっとややこしい。

話を戻して、仮にactionタグのname属性が無い場合は
Strutsは暗黙の内にMakeDBTableFormクラスのインスタンスを作成する。
このときreset,setXXXメソッドは呼ばれない。さらに、既にインスタンスが作成されていた場合これを「流用」する。
Catalinaを再起動しても内容を保持しているらしい。
この特性を利用できる場面があるのかは解らないが、紛らわしいので止めた方がいい。

formを明示的に作成

これを阻止する為に、formがnullの場合には
executeメソッド内部でformを明示的に作成する方法がある。
作成したら、request(もしくはsession)のsetAttribute(name,form)メソッドを呼び出す。
このときのnameを、<html:form>タグのname属性に指定することで
この作成したフォームをjspが利用することになる。

もしくは、actionタグのattribute属性を記述する。
こうすることによって、<html:form>タグのname属性はこの名前を自動的に利用する。
この場合、setAttributeのnameにはmapping.getAttribute()を渡す。
もちろんこれはactionタグのattribute属性を返すので
bean名を設定ファイルのみで記述することが可能になる。

遷移解析

フォームの無い遷移

まずはメインページ。静的なhtmlファイルとする。

<a href="diary/show_user.do">...</a>

リンクをクリックしたら、ブラウザは通常通り diary/show_user.do へジャンプする。
ここでAPP/WEB-INF/web.xmlを見ると、

<servlet-mapping>
  <servlet-name>action</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

という記述がある。つまりこのURLはactionというサーブレットに処理を委ねるという事である。
さらに同ファイルを見ると、

<servlet>
  <servlet-name>action</servlet-name>
  <description>original ActionServlet</description>
  <servlet-class>org.limy.struts.LimyActionServlet</servlet-class>
  <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml</param-value>
  </init-param>
  <init-param>
    <param-name>debug</param-name>
    <param-value>0</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

という記述がある。これにより、actionというサーブレットに対応するServletクラスは
LimyActionServlet だということになる。
このクラスのスーパークラスであるActionServletではdoGet, doPostが定義されていて、
その中でprocessメソッドを呼ぶ仕組みになっている。
よって、LimyActionServletではprocessメソッドをオーバーライドし独自のロジックを実行した後で
super.processメソッドを呼んでいる。

さて、ActionServlet.processメソッドでは与えられたURL(ここではdiary/show_user.do)を元に
対象となるactionタグを設定ファイルから探すことになる。
設定ファイルの場所は上で紹介したweb.xml内に記述されている。
通常はWEB-INF/struts-config.xmlである。

次にこのファイルを見てみる。

<action path="/diary/show_user" type="org.limy.struts.diary.action.MainAction" validate="false">
  <forward name="success" path="/diary/show_user.jsp" />
</action>

という要素がある。これが与えられたURLに対応するactionタグだということになる。
type属性を見ると、MainActionという記述があるので
これによってprocessはMainAction.executeに処理を移す。

executeに与えられるパラメータは
mapping, form, request, responseの4つ。後の2つは通常のServletと同じなので割愛する。
mappingには、上に記述したactionタグの各情報が入っている。
formには、このactionに対応するFormオブジェクトが入るが今回はnullである。

後はMainAction.execute内でロジックをこなせば無事処理が終了する。
executeの戻り値はActionForwardとなっている。
これは mapping.findForward("success") のようにして得ることができる。
例えば上の例だと、この値を返すことによって /diary/show_user.jsp に処理が移ることになる。

フォームの無い画面からフォームのある画面への遷移

まずは遷移元の画面。

<a href="diary/res.do">...</a>

ここでリンクをクリックすると、先程と同様にActionServletに処理が移ることになる。
では、actionタグを見てみましょう。

<action path="/diary/res" type="org.limy.struts.diary.action.MainAction"
  name="diary_resForm" validate="false">
  <forward name="success" path="/diary/res.jsp" />
</action>

先程と違う点があります。今回はname属性が付いています。
struts-config.xmlファイルを見ると、

<form-beans>
  <form-bean name="diary_resForm" type="org.limy.struts.diary.form.DiaryResForm"/>
</form-beans>

という記述があります。これにより、この遷移に必要なFormはDiaryResFormであることがわかりました。
executeに処理が移る前に、ActionServletではまずこのDiaryResFormのインスタンスを生成(new)します。
そしてform.resetメソッドを呼び出した後でexecuteをコールします。
そう、このときのパラメータformに、今作成したformオブジェクトを渡しているのです。

次に、遷移先の画面(diary/res.jsp)を見てみましょう。

<html:form action="/diary/resWrite">
  <html:text property="name" maxlength="32" />
</html:form>

ここで注意すべき点があります。
フォームが有るページにフォワードする時、
Strutsはフォワード後に再び設定ファイルを読みにいきます。
具体的には、遷移先のページ内に<html:form>タグが見つかると
それに対応するactionタグを設定ファイルから探すのです。
今回の例だと、対応するactionタグは以下のようになります。

<action path="/diary/resWrite" type="org.limy.struts.diary.action.MainAction"
  name="diary_resForm" validate="false">
  <forward name="success" path="/diary/main.jsp" />
</action>

「JSP内の<html:form>で指定されたアクション名」に対応するpath属性を持ったものを
設定ファイルから探すのです。
actionタグが特定できたら、そのタグのname属性を確認します。
遷移時に利用したtype属性etc.はここでは無視されます。
そして、そのname属性に対応するFormを<form-beans>タグから探します。
今回の例では、先程と同じくDiaryResFormです。

ちょっとややこしいと思うので、ここでもう一度整理します。
設定ファイル内にある2つのactionタグを並べて書いてみます。

<action path="/diary/res" type="org.limy.struts.diary.action.MainAction"
  name="diary_resForm" validate="false">
  <forward name="success" path="/diary/res.jsp" />
</action>
<action path="/diary/resWrite" type="org.limy.struts.diary.action.MainAction"
  name="diary_resForm" validate="false">
  <forward name="success" path="/diary/main.jsp" />
</action>

上のactionタグは、遷移元からAction.executeに移るまでに利用されるものです。
そして、Action.executeで処理が終わった後にどこかの画面にフォワードされる訳ですが
そのJSP(から生成されたサーブレットJava)を実行する際に利用されるのが下のactionタグになります。
流れを追ってみます。

フォームの初期値は、executeメソッドに渡されたformオブジェクトを参照することで決定されます。
具体的には、(DiaryResForm)form.getName()を呼び出してこれを初期値として表示します。
つまり、executeの処理中にformオブジェクトを更新すればその内容が画面に反映されることになります。
ちょっと(かなり?)ややこしいですが、解って頂けたでしょうか…

フォームの有る画面から他の画面への遷移

さて、これで最後です。
遷移元(フォームの有る画面)は、先程の例での遷移先と同じにします。
もう一度、遷移元の画面から一部を抜粋して書きます。

<html:form action="/diary/resWrite">
  <html:text property="name" maxlength="32" />
  <html:submit value="レスを送る" />
</html:form>

この画面上で「レスを送る」ボタンをクリックすると、

Top

[コメント(1) 2007/09/10(月) 17:32:26]
[PR] b nEXN[jOb f[^b FXb SEOb ANZXb nEX[J[b ^ItBXb SEO΍b ҋZb sYSۃ[b vb b nCb nCb AXNb ]Eb یb ev[gb ꗷsb b FXb Ƌhb b zb ҋZb ŗmb Stb wb [VbNb }bT[Wb ݂Xb FXb Mb 365b AtBGCgb эb FXb z[y[Wb fCg[hb FXb zm}\b xXg nC ze [cb ob nCEGfBOb Hawaii hotelsb Hawaii Activitiesb bhhrb Bb nC@Rh~jAb o@zeb
y^cЁup_CVtgvT[rXz nCnIvVicA[ibN}.j - rWlXNXq - iq(1) - iq(2) - COze - ؍s
z[y[W쐬 - ^T[o[ - gуz[y[W - uO - ze \ - iq - ؍ - ^CVFA
[PR] e`OȂIԂȂ炱炩B܂͔rĂ݂܂傤