2025/03/04, 2025/03/12
Struts 1.3でAction「/Action1」で、Form Beanクラス EditFormのインスタンスを作成し、
request.setAttribute("EditForm", instance);
でrequestスコープに保存して edit.jsp にフォワードしました。
edit.jsp では EditForm をhtml:form として表示し、そのSubmit時のAction「/Action2」を
とstruts-config.xmlに定義しているとき、requestスコープでAction2からEditFormのインスタンスを参照できますか?
------
はい。できるけども、以下の点に注意。
リクエストスコープの持続性
リクエストスコープは、ブラウザのリクエストがサーバーに送信されるたびに新しいリクエストオブジェクトが作成されます。
そのため、もし edit.jsp からの submit が新しいリクエストとして送信されている場合、
もともと /Action1 でセットした EditForm インスタンスは新しいリクエストには引き継がれません。
フォームBeanの再作成
タグで name="EditForm" を指定しているので、Strutsはフォームのデータをリクエストパラメータから読み取り、
新しい EditForm インスタンスを作成します。
そのため、/Action2 に来たときの EditForm は /Action1 でセットしたものではなく、
フォーム送信時のデータを反映した新しいインスタンスになります。
------
requestスコープにしたとき、Action2で以下の例外が発生する原因は何でしょうか?
org.apache.struts.util.RequestUtils.populate(RequestUtils.java:453)
org.apache.struts.chain.commands.servlet.PopulateActionForm.populate(PopulateActionForm.java:45)
------
Apache Commons BeanUtilsの同じバージョンでコンパイルしたJava Classに対して、
実行しているJavaVMのバージョンが7か8か17かで、BeanUtils.populate()の動作が変わることがありますか?
特にJava Classの中に、配列やListなどコレクション型のインスタンス変数(プロパティ)
が含まれている場合の動作に差異があるかを教えてください。
------
コレクション型を扱う例で、
JavaVMが古いバージョンでは正常に動くが、新しいバージョン(8や17以降)では、
ArrayIndexOutOfBoundsExceptionが発生するサンプルコードを記述してもらえますか。
------
import org.apache.commons.beanutils.BeanUtils;
import java.util.*;
public class BeanTest {
public static void main(String[] args) throws Exception {
Person person = new Person();
Map properties = new HashMap<>();
// インデックス指定で List の要素をセットしようとする
properties.put("hobbies[0]", "Reading");
properties.put("hobbies[1]", "Running");
// BeanUtils でマッピング
BeanUtils.populate(person, properties);
System.out.println("Hobbies: " + person.getHobbies());
}
}
class Person {
private List hobbies;
public List getHobbies() {
return hobbies;
}
public void setHobbies(List hobbies) {
this.hobbies = hobbies;
}
}
------
--------------------------------------------------------------------------------
2025/03/12
Java言語のStrutsを使用した次のようなWeb画面の構築パターンに決まった名称はありますか?
・Form Beanにデータベースレコード1行ずつに対応するArrayList型のプロパティrecordListを持つ
・Form Beanはrequestスコープ
・getRecord(int index)メソッドがあるが、単にリストを返すとStruts内部処理の
BeanUtils.populate()がIndexOutOfBoundsExceptionを発生させる問題があるため、これを防ぐために
getRecord(int index)メソッドの内部でrecordListの要素数を動的に膨らませている。
・レコード数(リストのサイズ)を事前にForm Beanに知らせる必要があるためhtml:hiddenで持たせている
・getRecord(int index)と別に、getRecordList()、setRecordList()メソッドもあり、
データベース検索結果をForm Beanに格納するためにsetRecordList()を使い、
JSPでlogic:iterateで反復するプロパティとして getRecordList() を参照する。
--------------------------------------------------------------------------------
決まった名称があるわけではないですが、設計思想としては以下のキーワードがフィットします:
Dynamic List Expansion Pattern(動的リスト拡張パターン)
Tabular Input Pattern(表形式入力パターン)
Index-Safe List Access Pattern(インデックスセーフリストアクセスパターン)
--------------------------------------------------------------------------------
struts indexed properties list request scope hidden
https://myjavaexamples.wordpress.com/2012/01/25/struts-simple-example-of-indexed-properties/
https://javabreaks.blogspot.com/2016/01/indexoutofboundsexception-when-using.html
--------------------------------------------------------------------------------
Form Beanのスコープをsessionにすれば、html:hidden要素で配列データを保持させる必要もなく、
動的リスト拡張処理も不要になると思います。
動的リスト拡張パターンが生まれた当時、requestスコープでForm Beanを保持することに、
何か利点があったのでしょうか?
--------------------------------------------------------------------------------
当時、requestスコープ を選ぶ理由は、メモリ効率・データ整合性・ステートレス性 の3つが大きかった
--------------------------------------------------------------------------------
Strutsアプリケーションに今から大きく手を入れる予定はありませんが、Java21+Tomcat 9.0に移行して延命したいです。
その際、動的リスト拡張パターンではBeanUtils.populateが例外を出して動作しないため、
コード変更をできるだけ少なくしてsessionスコープに移行するにはどう変更すればよいですか?
--------------------------------------------------------------------------------
struts-config.xmlを直す。
getRecord(int index)で膨らませない。
不要なhiddenタグを削除
--------------------------------------------------------------------------------