@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

StrutsでActionFormをネストしたときに値が送信されない

1
投稿者投稿内容
pat
会議室デビュー日: 2006/08/03
投稿数: 7
投稿日時: 2006-08-03 21:04
初めて投稿させて頂きます。

Struts1.1にて伝票管理のソースを書いております。

DBでT_DENPYOU_MAINとT_DENPYOU_SUBを定義し、DENPYOU_NOカラムで紐付けています。
画面のヘッダ項目をT_DENPYOU_MAINで、明細項目をT_DENPYOU_SUBで管理しています。

T_DENPYOU_MAIN
DENPYOU_NO
AAA
(以下省略)

T_DENPYOU_SUB
DENPYOU_NO
ROW_NO
BBB
CCC
(以下省略)

ActionFormをネストしており、
明細項目を<logic:iterate>でテキストボックスに表示することは成功しているのですが、
テキストボックスの値を変更してsubmitするときに、
メインActionFormに、サブActionFormをaddしたListをsetすることができません。

ActionでサブActionFormのListを別にsession.setAttribute()する方法も考えたのですが、
生成されるhtmlではヘッダのformと明細行数分のformに分かれてしまうので、
一つのbotton押下で、
ヘッダと明細行全てのテキストボックスの値を送信する方法が分かりません。

どなたかこのような処理をご存じの方がおられましたら、よろしくお願いいたします。

/**
* メインActionForm
* (説明用のためgetter、setterはプロパティの直下に書いています)
*/
public class DenpyouMainForm extends ActionForm {

/** 伝票番号 */
private String denpyouNo = "";
public void setDenpyouNo(String denpyouNo) {
this.denpyouNo = denpyouNo;
}
public String getDenpyouNo() {
return this.denpyouNo;
}


/** 画面項目aaa */
private String aaa = "";
public void setAaa(String aaa) {
this.aaa = aaa;
}
public String getAaa() {
return this.aaa;
}

/** サブActionForm用List */
private List subFormList = new ArrayList();
public void setSubFormList(List subFormList) {
this.subFormList = subFormList;
}
public List getSubFormList() {
return this.subFormList;
}
}

/**
* サブActionForm
* (説明用のためgetter、setterはプロパティの直下に書いています)
*/
public class DenpyouSubForm extends ActionForm {

/** 画面項目bbb */
private String bbb = "";
public void setBbb(String bbb) {
this.bbb = bbb;
}
public String getBbb() {
return this.bbb;
}

/** 画面項目ccc */
private String ccc = "";
public void setCcc(String ccc) {
this.ccc = ccc;
}
public String getCcc() {
return this.ccc;
}
}

<%--
*****************************
* denpyou.jsp
*****************************
--%>
<%-- ヘッダ項目 --%>
<html:text neme="denpyouMainForm" property="denpyouNo" readonly="true" />
<html:text neme="denpyouMainForm" property="aaa" />
<%-- 明細項目 --%>
<table border="1">
<logic:iterate id="row"
name="denpyouMainForm"
property="subFormList"
indexId="index">
<tr>
<td>
<html:text name="row"
property="bbb"
indexed="true" />
</td>
<td>
<html:text name="row"
property="ccc"
indexed="true" />
</td>
</tr>
</logic:iterate>
</table>

<!--
*****************************
* 生成されたhtml
*****************************
-->
<input type="text" name="denpyouNo" value="XXX" readonly="readonly">
<input type="text" name="aaa" value="XXX">
<table border="1">
<tr>
<td>
<input type="text" name="row[0].bbb" value="XXX">
</td>
</tr>
<tr>
<td>
<input type="text" name="row[0].ccc" value="XXX">
</td>
<td>
<input type="text" name="row[1].bbb" value="XXX">
</td>
</tr>
<tr>
<td>
<input type="text" name="row[1].ccc" value="XXX">
</td>
</tr>
<!-- 以下row[2]、row[3]と続く -->
</table>
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2006-08-03 23:31
引用:
<input type="text" name="row[0].bbb" value="XXX">


このような場合、Strutsは自動的にform内のリストに値を設定してくれます。
この例では、
rowListというリストのindex=0にあるBeanに対してsetBbbメソッドで値XXXを設定します。
pat
会議室デビュー日: 2006/08/03
投稿数: 7
投稿日時: 2006-08-04 22:31
ご返事ありがとうございます!!

<bean:define>を使うか、
スクリプトレットに埋め込むかでやってみます。
(それ以外かもしれませんが...)

アドバイスありがとうございます!
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2006-08-05 00:11
patさんの記述しているソースから後一歩という感じを受けましたので端的に記述しましたが、逆に伝えたいことがはっきりしていませんでした。
コード:
<logic:iterate id="row" name="denpyouMainForm" property="subFormList" indexId="index">
	<tr>
		<td>
			<html:text name="row" property="bbb" indexed="true" />
			<html:text name="row" property="ccc" indexed="true" />
		</td>
	</tr>
</logic:iterate>


のように記述すると
コード:
<tr>
	<td>
		<input type="text" name="row[0].bbb" value="b0">
		<input type="text" name="row[0].ccc" value="c0">
	</td>
</tr>
<tr>
	<td>
		<input type="text" name="row[1].bbb" value="b1">
		<input type="text" name="row[1].ccc" value="c1">
	</td>
</tr>


と展開されるところまではOKと思います。
ここでこのフォームをsubmitすると、パラメタを「row[0].bbb」とした値b0などが渡ります。
Strutsはこのような値をインデックスを持ったプロパティ値と分類しアクションフォームに設定しようとします。
最終的にjakarta commonsプロジェクトの
org.apache.commons.beanutils.PropertyUtilsBean#setIndexedProperty
を用いて配列やリストとして設定しようとします。
この際、セッターとしてどのメソッドを使用するかを決定するために、先頭から[までの文字列を使用します。

先日私が挙げた例では「row[0].bbb」の値をリストとしてフォームにセットしてもらうためには
setRowListメソッドがsubmitフォームとなるアクションフォームには必要ということを言いたかったのです。

patさんの例ではリストsubFormListのセッターとしてsetSubFormListを持っているので、htmlに
「subForm[0].bbb」(「subFormList[0].bbb」だったかも。試してみてください。)と展開されるようにStrutsタグを修正すれば
Submit後のActionではフォームにリストがセットされるはずです。

また、PropertyUtilsBean#setIndexedPropertyはリストに対しsetメソッドで値を設定するので
通常のArrayListなどではIndexOutOfBoundsExceptionが発生してしまいます。回避のためにはjakarta commonsプロジェクトの
org.apache.commons.collections.list.LazyList
を代用してください。
これはsetやaddで最大インデックスをオーバーした値を指定した場合、リスト構築時に指定するオブジェクトでfillして自動拡張してくれるリストです。使用を最小限に抑えたいリストではありますが。

長々しつれいしました。
pat
会議室デビュー日: 2006/08/03
投稿数: 7
投稿日時: 2006-08-06 00:41
ご返事ありがとうございます!!
実はどのように記述したらよいのか分からずにいろいろとやっていまして、
また詰まったら再度質問させて頂こうと思っていたところです。

引用:
「subForm[0].bbb」(「subFormList[0].bbb」だったかも。試してみてください。)と展開されるようにStrutsタグを修正すれば
Submit後のActionではフォームにリストがセットされるはずです。


コード:
<logic:iterate id="row" 
               name="denpyouMainForm" 
               property="subFormList" 
               indexId="index"> 
              ↓
<logic:iterate id="subForm" (もしくはid="subFormList")
               name="denpyouMainForm" 
               property="subFormList" 
               indexId="index"> 


で一度試してみます。

引用:
また、PropertyUtilsBean#setIndexedPropertyはリストに対しsetメソッドで値を設定するので
通常のArrayListなどではIndexOutOfBoundsExceptionが発生してしまいます。回避のためにはjakarta commonsプロジェクトの
org.apache.commons.collections.list.LazyList
を代用してください。


ArrayListしか知りませんでした...。
詳しいご説明ありがとうございます!
やってみます!

大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2006-08-19 13:22
解決はされていると思いますが、誤ったレスを返していたので訂正します。
フォームのリスト"rowList"にセットさせたい場合はsetRowListが必要な上、htmlになった時点でrowList[〜となっている必要がありました。
html上でrow[〜となっている必要があると書きましたがこの点間違いでした。すみません

サンプルコード書いてみました。(長いですが…)
action、form、beanはサーブレット用フォルダに直置きです。宣言など省略してます。
jarはstruts用のほかcommons-collection用が必要です。

コード:
■struts-config.xml(抜粋)

<form-beans>
<form-bean
name="listForm"
type="ListSampleForm"/>
</form-beans>


<action-mappings>
<action
path="/sampleAction"
type="ListSampleAction"
name="listForm"
scope="request"
validate="false"
parameter="sampleForward">
<forward name="success" path="/pages/test.jsp"/>
</action>
</action-mappings>



コード:
■test.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="/WEB-INF/tld/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/tld/struts-logic.tld" prefix="logic" %>
<html:html>
<html:form action="sampleAction">
<body>
<logic:iterate id="dataList" name="listForm" property="dataList" indexId="index">
<html:checkbox name="dataList" property="use" indexed="true"
onclick='<%="alert(\\'isCheck[" + index + "]:\\' + this.checked)"%>'/>
<html:text name="dataList" property="bbb" indexed="true"/>
<br>
</logic:iterate>
<input type="hidden" name="act" value="">

<br>
<input type="submit" value="plus" onclick="form.act.value='plus'">
<input type="submit" value="minus" onclick="form.act.value='minus'">
</body>
</html:form>
</html:html>



コード:
■ListSampleAction.java

public class ListSampleAction extends MappingDispatchAction {

public ActionForward sampleForward(ActionMapping theMapping, ActionForm theForm,
HttpServletRequest theRequest, HttpServletResponse theResponse)
throws Exception {

ListSampleForm form = (ListSampleForm) theForm;
List dataList = form.getDataList();
if ("plus".equals(form.getAct())) {
dataList.add(new SubBean());
} else if ("minus".equals(form.getAct())) {
if (!dataList.isEmpty()) {
dataList.remove(dataList.size() - 1);
}
}
return theMapping.findForward("success");
}
}



コード:
■ListSampleForm.java

public class ListSampleForm extends ActionForm {
private String act;
private List dataList = LazyList.decorate(new LinkedList(), new Factory() {
public Object create() {
return new SubBean();
}
});

public String getAct() {
return act;
}
public void setAct(String theAct) {
act = theAct;
}
public List getDataList() {
return dataList;
}
public void setDataList(List theDataList) {
dataList = theDataList;
}
}



コード:
■SubBean.java

public class SubBean implements Serializable {
private boolean isUse;
private String bbb;
public boolean isUse() {
return isUse;
}
public void setUse(boolean theIsUse) {
isUse = theIsUse;
}
public String getBbb() {
return bbb;
}
public void setBbb(String theBbb) {
bbb = theBbb;
}
}


以上です。


[ メッセージ編集済み 編集者: 暁 編集日時 2006-08-19 13:24 ]

[ メッセージ編集済み 編集者: 暁 編集日時 2006-08-19 13:24 ]
pat
会議室デビュー日: 2006/08/03
投稿数: 7
投稿日時: 2006-08-25 20:49
暁さん、いつもお世話になります。

引用:
jarはstruts用のほかcommons-collection用が必要です。


あれから前回教えて頂いた、
org.apache.commons.collections.list.LazyListを、
Webで探し出してimportしたところまでは良かったのですが、
LazyList#decorate()の第2引数FactoryがInterfaceのため、
implementsしたクラスを指定しないといけないのかといろいろとやっていたところでした。

コード:
public class ListSampleForm extends ActionForm {
	private String act;
	private List dataList = LazyList.decorate(new LinkedList(), new Factory() {
		public Object create() {
			return new SubBean();
		}
	});
	(以下省略)
}


上記にならってMainFormでプロパティの定義を修正し、
続いてjspの<logic:iterate>を修正したところ、
ようやく成功しました!


たびたびのご回答ありがとうございました!!
1

スキルアップ/キャリアアップ(JOB@IT)