機能リファレンス
SAStrutsで使われている機能の説明をします。
プロジェクト構成
SAStrutsでは、ルートパッケージの配下にactionなどのパッケージを作って、 そこに必要なファイルを格納します。 ルートパッケージ名は、任意の名前を指定することができます。 例えば、sa-struts-tutorialプロジェクトでは、ルートパッケージ名は、tutorialになっています。
ルートパッケージ名は、convention.diconで指定します。 sa-struts-tutorialプロジェクトでは、src/main/resourcesで次のように指定されています。
convention.dicon
<components> <component class="org.seasar.framework.convention.impl.NamingConventionImpl"> <initMethod name="addRootPackageName"> <arg>"tutorial"</arg> </initMethod> </component> <component class="org.seasar.framework.convention.impl.PersistenceConventionImpl"/> </components>
アクションは、ルートパッケージ.actionに格納します。 例えば、http://ホスト名/プロジェクト名/xxx/のURLに対応するアクションクラスは、 ルートパッケージ.action.XxxActionという名前にします。
アクションフォームは、ルートパッケージ.dtoに格納します。 例えば、XxxActionで利用するアクションフォームは、XxxDtoという名前にします。 通常は、アクションフォームを定義する必要はありません。 アクションで状態も一緒に管理したほうが、 関連する定義が近くにあるので、わかりやすいためです。
エンティティは、 ルートパッケージ.entityに格納します。 エンティティとは、データベースに永続化されるデータです。 エンティティの名前は任意の名前にすることができますが、 通常は、テーブルの名前にあわせます。
サービスは、ルートパッケージ.serviceに格納します。クラス名の最後は、Serviceで終わるようにします。 複数のアクションから共通に使われるような機能は、 サービスクラスで実装すると良いでしょう。 サービスは、インターフェースと実装に分ける必要はなく、実装のみで良いでしょう。 テストのときにモックが必要なら、実装クラスを継承したモッククラスでメソッドを モック用に上書きすればよいからです。
ユーティリティは、ルートパッケージ.utilに格納します。 クラス名は自由につけてかまいません。 ユーティリティクラスは、通常staticメソッドで構成されています。
JSPは、アクションに対応するディレクトリに格納します。 例えば、XxxActionで使うJSPは、/xxx/に格納すると良いでしょう。
アプリケーションアーキテクチャ
SAStrutsは、MVC(Model View Controller)のアーキテクチャに基づいていて、 Modelはエンティティ、 ViewはJSP、Controllerはアクションになります。
アクションは、複数の実行メソッド を持つことができ、通常は、1ユースケースを1アクションにマッピングします。 複数の画面で構成される意味のある単位をユースケースだと、とらえればよいでしょう。
ビジネスロジックは、エンティティに 定義します。ビジネスロジックと間違えやすいのが、データアクセスのロジックと、 エンティティの関連をたどる(部署のエンティティから関連先の従業員のエンティティをみにいくこと) ような複数種類(部署と従業員)のエンティティにまたがるようなロジックです。
データアクセスのロジックは、アクションに記述します。 データアクセスのロジックをDaoクラスに抽出する方法もありますが、 S2JDBCを使うと、 ほとんどのデータアクセスロジックは、一度JdbcManagerを呼び出して終わりというような スカスカなメソッドになってしまいます。 データアクセスのロジックは、アクションに直接記述したほうが、 わかりやすいでしょう。
エンティティの関連をたどる ような複数種類のエンティティにまたがるようなロジックは、 アクションに記述します。 複数種類のエンティティにまたがるようなロジックは、 どのエンティティ所属するのかあいまいなので、 制御ロジックととらえ、アクションに記述するほうがわかりやすいでしょう。
アクション
リクエストに応じて起動されるクラスをアクションといいます。 Strutsでは、URLとアクションの関係をstruts-config.xmlに記述しますが、 SAStrutsでは、次のルールに従って自動的に決まるので、 設定ファイルを書く必要がありません。
http://localhost:8080/sa-struts-tutorial/login/にアクセスしたとします。 sa-struts-tutorialはWebアプリケーション名です。 SAStrutsは、次のような手順でURLをActionクラスに変換します。
- Webアプリケーション名の後ろのパス(/login/)の最後のスラッシュをActionに変換(/loginAction)します。 スラッシュがない場合は後ろにActionを付け加えます。
- 最後のスラッシュの直後を大文字(/LoginAction)にします。
- スラッシュをドットに変換(.LoginAction)します。
- ルートパッケージ名.actionを先頭につけます(ルートパッケージ名.action.LoginAction)。 ルートパッケージ名の詳細は、こちらを参照してください。
- 最終的に、/login/に対応するアクションクラスはtutorial.action.LoginActionになります。
アクション用のパスがない場合、ルートパッケージ.action.IndexActionがあれば、 そのアクションが呼び出されます。 例えば、http://localhost:8080/sa-struts-tutorial/にアクセスすると、 tutorial.action.IndexActionが呼び出されます。
IndexActionを呼び出したいときは、Webのルートにindex.jspをおかないようにしてください。 index.jspの方が優先されて呼び出されるためです。
大規模なアプリケーションでは、パスを分割することもできます。 例えば、/aaa/bbb/のパスに対応するアクションクラスは、 ルートパッケージ.action.aaa.BbbActionになります。
アクションはPOJO(普通のJavaのクラス)にします。StrutsのようにActionを継承する必要はありません。 HttpServletRequestやHttpServletResponseなどのServlet API関連のオブジェクトは、 次のようにプロパティを定義しておけば、Seasar2が自動的に設定します。
public class MyAction { public HttpServletRequest request; public HttpServletResponse response; public HttpSession session; public ServletContext application; ... }
Seasar2は、publicフィールドをプロパティとみなすので、 setter,getterメソッドをいちいち定義する必要はありません。 setter,getterメソッドを定義してもかまいませんが、 何かと面倒なので、publicフィールドにすることをお勧めします。
Strutsでは、リクエストのパラメータの内容は、アクションフォームで受け取りますが、 SAStrutsでは、アクションにリクエストのパラメータ名と同じ名前のプロパティを 定義しておけば、アクションで受け取ることができます。 入力値を受け取るためのプロパティは、バリデーションエラーになっても値を格納できるように プロパティの型をStringあるいはbooleanで定義してください。 アクションフォームをアクションとは別に定義することもできます。 詳しくはアクションフォームの説明を参照してください。
アクションは、リクエストスコープで管理されています。 セッションスコープにすることはできません。 セッションスコープを使いたい場合は、アクションフォームを セッションスコープで管理してください。
ログインしたユーザに関する情報など、 アクションフォーム以外をセッションで管理したい場合、 ルートパッケージ.dtoにXxxDto作成し、@Componentでセッションで管理されるように定義します。
@Component(instance = InstanceType.SESSION) public class UserDto implements Serializable { private static final long serialVersionUID = 1L; public String userName; ... }
作成したUserDtoをアクションで利用するには、次のようにプロパティを定義しておけば、 Seasar2が自動的に設定します。フィールド名は、クラス名の先頭を小文字にしたものにします。
public UserDto userDto;
Dtoをセッションに保存する場合、DtoのHOT deployが効かない場合があります。 Tomcatを使っているなら、デフォルトでセッションをアプリケーションの終了時に 保存する設定になっているので、Seasar2の関与しないところでクラスローダに読み込まれてしまい HOT deployがうまく動作しません。
セッションに保存しないようにするには、TOMCAT_HOME/conf/context.xmlの Managerタグのコメントをはずしてください。
他のアプリケーションサーバでも、セッションをアプリケーションの終了時に 保存する設定になっていると同様のことが起こると思われます。 HOT deployがうまくいかないときは、セッションをアプリケーションの終了時に 保存しないように設定してください。
複数のアクションから共通に使われるようなロジックをサービスで定義する場合、 ルートパッケージ.serviceにXxxServiceを作成します。
public class XxxService { ... }
作成したXxxServiceをアクションで利用するには、次のようにプロパティを定義しておけば、 Seasar2が自動的に設定します。フィールド名は、クラス名の先頭を小文字にしたものにします。
public XxxService xxxService;
リクエストに対する処理を記述したい場合は、 実行メソッドを定義します。
入力値の検証は、検証用のアノテーションを定義します。
入力値に対する検証をロジックで記述したい場合は、 検証メソッドを定義します。
実行メソッド
リクエストに対する処理は、実行メソッドに記述します。 実行メソッドは、@Executeがつけられている任意の名前のメソッドで、 戻り値はString、引数は無しにする必要があります。
@Execute public String execute() { ... return ...; }
実行メソッドの戻り値は、遷移先のパスです。 パスが/ではじまっていない場合、アクションのパスからみた相対パスとみなされます。
例えば、http://localhost:8080/sa-struts-tutorial/login/のアクションで
戻り値をlogin.jspとした場合
http://localhost:8080/sa-struts-tutorial/login/login.jspに遷移します。
パスが/ではじまっている場合、Webアプリケーションのルートからの相対パスと みなされます。例えば、戻り値を/selectとした場合、 http://localhost:8080/sa-struts-tutorial/select/に遷移します。
デフォルトではフォワードで遷移しますが、リダイレクトで遷移したい場合は、 パスの最後にredirect=trueを追加します。 =の前後に余分な空白は含めないでください。 redirect=trueの部分は、実際に実行されるときには、消去されます。
... return "xxx.jsp?redirect=true";
... return "xxx.jsp?key=value&redirect=true";
別のサイトに遷移したい場合は、パスをhttpやhttpsではじめ、 リダイレクトするように指定します。
... return "https://ホスト名/アプリケーション名/パス?redirect=true";
ファイルのダウンロードのように既にレスポンスに出力済みの場合は、 遷移先(戻り値)はnullにしてください。
1つのアクションに複数の実行メソッドを定義することができます。 どの実行メソッドが選択されるのかは、URLで指定するか、 リクエストのパラメータのキーにメソッド名が含まれている(値が1文字以上あること)かどうかで決まります。
次の例では、LoginAction#index()が呼び出されます。
http://localhost:8080/sa-struts-tutorial/login/index/
メソッドが定義されていない場合、index()が呼び出されるので、 上記の呼び出しは、下記の呼び出しと一緒です。
http://localhost:8080/sa-struts-tutorial/login/
@ExecuteでURLのパターン(urlPattern)を指定することで、 URLの一部をパラメータの値として受け取ることができます。 例えば、EmployeeAction#edit()が次のように定義されているとします。
@Execute(urlPattern = "edit/{id}") public String edit() { ... }
urlPatternの{}で囲まれている部分をパラメータとして受け取ることができます。 /employee/list.jspに次のようなアンカータグが定義されている場合、 アンカータグをクリックするとidプロパティが1に設定されて、 EmployeeAction#edit()が呼び出されます。
<a href="edit/1">編集画面へ</a>
フォームをサブミットする場合は、ボタン系のname属性に実行メソッド名を指定します。 次の例では、アクションクラスのsubmit()が呼び出されます。
<input type="submit" name="submit" value="サブミット"/>
実行メソッドを呼び出す前に、commons validatorを使った 検証を行なうには、@Executeのvalidator属性をtrueにします。デフォルトはtrueです。
validator=trueの場合は、検証結果がNGのときの遷移先のパスをinput属性で指定します。 パスの書き方は、実行メソッドの戻り値の場合と一緒です。 バリデータの詳細は、こちらを参照してください。
@Execute(validator = true, input = "edit.jsp")
実行メソッドを呼び出す前に、アクションクラスのメソッドで検証を行なうには、 @Executeのvalidate属性で検証用のメソッド名を指定します。
validate属性を指定した場合は、検証結果がNGのときの遷移先のパスをinput属性で指定します。 パスの書き方は、実行メソッドの戻り値の場合と一緒です。 validator属性とvalidate属性を両方指定した場合には、 バリデータのほうが先に実行されます。 検証メソッドの詳細は、こちらを参照してください。
@Execute(validate = "validate", input = "login.jsp")
バリデータ
commons validatorを使った検証を行なうには、 アクションやアクションフォームのフィールドに検証用のアノテーションを指定します。 検証用のアノテーションの詳細は、こちらを参照してください。
@Required public String userName;
検証結果がNGの場合に出力されるメッセージは、メッセージリソースに 記述します。検証用のアノテーションとメッセージのキーは次のようになっています。
アノテーション | メッセージのキー |
---|---|
Required | errors.required |
Validwhen | 開発者が指定 |
Minlength | errors.minlength |
Maxlength | errors.maxlength |
Minbytelength | errors.minbytelength |
Maxbytelength | errors.maxbytelength |
Mask | errors.invalid |
IntRange | errors.range |
LongRange | errors.range |
FloatRange | errors.range |
DoubleRange | errors.range |
ByteType | errors.byte |
ShortType | errors.short |
IntegerType | errors.integer |
LongType | errors.long |
FloatType | errors.float |
DoubleType | errors.double |
DateType | errors.date |
CreditCardType | errors.creditcard |
EmailType | errors.email |
UrlType | errors.url |
メッセージをカスタマイズしたい場合は、キーに対応する値を書き換えてください。
特定のプロパティのみ、メッセージをカスタマイズしたい場合は、 メッセージリソースに、 メッセージを追加し、検証用のアノテーションのmsg属性で指定します。
errors.required2={0}は必須だぜ。
@Required(msg = @Msg(key = "errors.required2"))
メッセージには、{位置}で引数を渡すことができます。 位置は0からはじまります。 検証用のアノテーションで、引数を指定するには、arg0, arg1, ..., args属性で指定します。
@Required(arg0 = @Arg(key = "ほげ", resource = false))
@Validwhen(test = "((validwhen1Text == null) or (*this* != null))", msg = @Msg(key = "errors.required.other"), args = @Arg(key = "validwhen1Text", resource = false, position = 1))
最初の引数は、プロパティ名が自動的に設定されます。
プロパティの表示をカスタマイズしたい場合は、
メッセージリソースに
labels.プロパティ名=...のエントリを追加してください。
labels.userName=ユーザ名
target属性を指定することで、特定のメソッドの場合だけ、検証を行なうようにすることもできます。 複数のメソッドを指定する場合は、カンマで区切ります。 target属性が指定されていない場合、@Executeでvalidator=trueのすべての実行メソッドが対象になります。 次の例では、secondプロパティは、goThirdメソッドが呼び出されるときだけ、 入力必須になります。
@Required(target = "goThird") public String second;
JSPでエラーメッセージを出力するには、次のようにhtml:errorsタグを使います。
<%@taglib prefix="html" uri="http://struts.apache.org/tags-html"%> ... <html:errors />
独自の検証用アノテーションを追加したい場合は、 org.seasar.struts.validator.S2FieldChecksを参考にして、 検証ロジックを実装し、そのメソッドをvalidator-rules.xmlで指定します。
そして、validator-rules.xmlで指定したvalidatorの名前を Validatorアノテーションで 指定してください。
検証メソッド
バリデータでは検証できないような複雑なものは、 アクションの検証メソッドを使います。
検証メソッドには、任意の名前をつけることができ、戻り値はActionMessages、 引数は無しにする必要があります。 戻り値のActionMessagesが空でない場合、検証結果はNGだとみなされます。
public ActionMessages validate() { ActionMessages errors = new ActionMessages(); ... return errors; }
実行メソッドで、どの検証メソッドを使うのかは、validate属性で指定します。 validate属性を指定した場合は、 input属性に検証結果がNGのときの遷移先も指定する必要があります。
@Execute(validate = "validate", input = "login.jsp")
ログインをするときの実行メソッドと検証メソッドは次のようになります。
@Execute(validate = "validate", input = "login.jsp") public String login() { return "welcome.jsp"; } public ActionMessages validate() { ActionMessages errors = new ActionMessages(); if (!userName.equals(password)) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.invalid.login")); } return errors; }
アクション以外で、検証を行ないたい場合は、 検証結果がNGの場合、ActionMessagesExceptionをスローします。
public void validateLogin(String userName, String password) { if (!userName.equals(password)) { throw new ActionMessagesException("errors.invalid.login"); } }
ActionMessagesExceptionの処理は、app.diconに
org.seasar.struts.interceptor.ActionMessagesThrowsInterceptorを登録し、
customizer.diconで登録したインターセプタを使うように記述しておけば、
個別のアクションでは何もする必要はありません。
app.diconとcustomizer.diconは、sa-struts-tutorialプロジェクトの場合、
src/main/resourcesにおかれています。
app.dicon
<component name="actionMessagesThrowsInterceptor" class="org.seasar.struts.interceptor.ActionMessagesThrowsInterceptor"/>
customizer.dicon
<component name="actionCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain"> ... <initMethod name="addAspectCustomizer"> <arg>"actionMessagesThrowsInterceptor"</arg> </initMethod> ... </component>
データアクセス
データアクセス用のフレームワークは、任意のものを使うことができますが、 SAStrutsと一緒に使うことを想定して作成されている S2JDBCを 使うことをお勧めします。
S2JDBCを 使う場合、データベースへ接続するための設定は、jdbc.diconに記述します。 jdbc.diconの設定は、こちらを参照してください。 sa-struts-tutorialプロジェクトの場合、jdbc.diconは、src/main/resourcesにおかれています。
S2JDBC自体の設定は、 s2jdbc.diconに記述します。 s2jdbc.diconの設定は、こちらを参照してください。 sa-struts-tutorialプロジェクトの場合、jdbc.diconは、src/main/resourcesにおかれています。
S2JDBCは、 JdbcManager経由で利用します。 JdbcManagerをアクションで利用するには、 次のようにプロパティを定義しておけば、Seasar2が自動的に設定します。
public JdbcManager jdbcManager;
トランザクション
SAStrutsでは、トランザクション処理は、JTAの実装に任せていて、 SAStruts自体がトランザクション処理に関与することはありません。 JTAの設定は、s2container.diconで行ないます。 詳細は、こちらを参照してください。 sa-struts-tutorialプロジェクトの場合、s2container.diconは、src/main/resourcesにおかれています。
アクションやサービスのメソッドが呼び出されたときに、 自動的にトランザクションを開始するには、customizer.diconにトランザクション用の設定を記述します。 sa-struts-tutorialプロジェクトの場合、customizer.diconは、src/main/resourcesにおかれています。
cutomizer.dicon
<component name="actionCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain"> <initMethod name="addCustomizer"> <arg> <component class="org.seasar.framework.container.customizer.TxAttributeCustomizer"/> </arg> </initMethod> ... </component> <component name="serviceCustomizer" class="org.seasar.framework.container.customizer.CustomizerChain"> <initMethod name="addCustomizer"> <arg> <component class="org.seasar.framework.container.customizer.TxAttributeCustomizer"/> </arg> </initMethod> ... </component>
TxAttributeCustomizerを使うと、Objectクラス以外のpublicなメソッドが呼び出されると、 自動的にトランザクション処理が行なわれます。 デフォルトのトランザクション属性は、Requiredです。
Requiredは、トランザクションが開始されていなければ、 自動的にトランザクションを開始し、 既にトランザクションが開始されていれば、 そのトランザクションを引き継ぎます。 例外が起こった場合は、自動的にロールバックします。
特定のクラスのトランザクション属性を変えたい場合は、 クラスに@TransactionAttributeを指定します。
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public class XxxAction { ... }特定のメソッドのトランザクション属性を変えたい場合は、 メソッドに@TransactionAttributeを指定します。 次の例では、someMethod()はTransactionAttributeType.NEVERで、 someMethod2()はTransactionAttributeType.REQUIRES_NEWになります。
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public class XxxAction { @TransactionAttribute(TransactionAttributeType.NEVER) public void someMethod() { ... } public void someMethod2() { ... } ... }
データ変換
アクションとエンティティ間でデータを変換するには、 Beansの機能を使うのが良いでしょう。 単純に値をコピーするだけでなく、文字列と数値などの変換も行なってくれます。 Commons BeanUtilsはpublicフィールドに対応していないので、 publicフィールドを使いたい場合は、Beans を使ってください。
S2JDBCを組み合わせて、 プライマリーキーで取得したデータをアクションにコピーするには次のようにします。 thisはアクションです。
Employee emp = jdbcManager .from(Employee.class) .id(id) .getSingleResult(); Beans.copy(emp, this).execute();
アクションのデータでテーブルを更新するには次のようにします。 thisはアクションです。
Employee emp = Beans.createAndCopy(Employee.class, this).execute(); jdbcManager.update(emp).execute();
JSP
JSPは、アクションに対応するディレクトリに格納します。 例えば、XxxActionで使うJSPは、/xxx/に格納すると良いでしょう。
アクションやアクションフォームのプロパティの値は、 リクエストの属性にプロパティと同じ名前でセットされています。 そのため、ELやJSTLで次のように参照することができます。
${プロパティ名} ${f:h(プロパティ名)} <a href="${f:u(プロパティ名)}">...</a>
HTMLエスケープ(クロスサイトスクリプティング対策で"<"を"<"などに変換すること)が必要なケースは、f:h()を使ってください。
URLエンコーディング(クロスサイトスクリプティング対策でURLの部分をjavascript:alert('hoge') のような感じでJavaScriptが実行されないように変換すること)が必要なケースは、f:u()を使ってください。
タグのボディでは、HTMLエスケースしてください。 URL用の属性は、URLエンコーディングしてください。
ネストしたプロパティにはドット(.)でアクセスできます。
${プロパティ名.ネストしたプロパティ名}
どのJSPでも共通で使うような宣言は、1つのJSPにまとめ、web.xmlでそのJSPを指定します。 sa-strtus-tutorialプロジェクトでは、webapp/common/common.jspに共通で使う宣言が 定義されています。
commons.jsp
<%@page pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> <%@taglib prefix="html" uri="http://struts.apache.org/tags-html"%> <%@taglib prefix="bean" uri="http://struts.apache.org/tags-bean"%> <%@taglib prefix="tiles" uri="http://jakarta.apache.org/struts/tags-tiles"%> <%@taglib prefix="s" uri="http://sastruts.seasar.org"%> <%@taglib prefix="f" uri="http://sastruts.seasar.org/functions"%>
web.xml
<web-app> ... <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>false</el-ignored> <page-encoding>UTF-8</page-encoding> <scripting-invalid>false</scripting-invalid> <include-prelude>/common/common.jsp</include-prelude> </jsp-property-group> </jsp-config> </web-app>
SAStrutsには、Strutsのhtml:formを継承したs:formが用意されています。 s:formタグは、action属性の値に拡張子(.do)が付かないこと以外は、 html:formと同じです。
アクションフォーム
SAStrutsでは、アクションフォームもPOJOで記述することができます。 リクエストのパラメータと同じ名前のプロパティをアクションフォームに定義します。 入力値を受け取るためのプロパティは、バリデーションエラーになっても値を格納できるように プロパティの型をStringあるいはbooleanで定義してください。
アクションフォームクラスは、ルートパッケージ.dtoにおき、クラス名の最後は、Dtoで終わるようにします。
SAStrutsのアクションフォームは、デフォルトだとリクエストスコープで管理されますが、 次のようにアノテーションを指定することで、 セッションスコープで管理することもできます。 セッションスコープで管理するコンポーネントは、 java.io.Serializableをimplementsする必要があります。
@Component(instance = InstanceType.SESSION) public class FormDto implements Serializable { private static final long serialVersionUID = 1L; ... }
アクションフォームを利用するには、アクションのプロパティに@ActionFormを指定します。 @ActionFormを複数指定しても意味がないので、 複数指定しないようにしてください。 次のようにプロパティを定義しておけば、 Seasar2が自動的に設定します。 フィールド名は、クラス名の先頭を小文字にしたものにします。
public class FormAction { @ActionForm public FormDto formDto; ... }
検証メソッドはアクションフォームではなく、アクションに定義します。 複数のアクションでアクションフォームを共用した場合、 検証の内容は、アクションごとに異なることがほとんどだからです。
リセットメソッドはこちらを参照してください。
Tomcatを使う場合、セッションをアプリケーションの終了時に保存する設定になっていると、 Seasar2の関与しないところでクラスローダに読み込まれてしまうので、 HOT deployがうまく動作しません。 セッションに保存しないようにするには、TOMCAT_HOME/conf/context.xmlの Managerタグのコメントをはずしてください。
他のアプリケーションサーバでも、セッションをアプリケーションの終了時に 保存する設定になっていると同様のことが起こると思われます。 HOT deployがうまくいかないときは、セッションをアプリケーションの終了時に 保存しないように設定してください。
リセットメソッド
チェックボックス(<input type="checkbox" .../>)や 複数選択リスト(<select multiple="multiple" ...></select>) では、選択された値のみをブラウザはリクエストで送信します。 何も選択しなかった場合は、ブラウザは何も送信してくれません。 そのため、アクションフォームをセッションで管理している場合、 チェックボックスや複数選択リストで選択状態をすべて解除しても 何もリクエストで送信されないため、元の状態のまま残ってしまいます。
この問題に対応するために用意されているのが、 アクションフォームのreset()です。 reset()は、リクエストパラメータをアクションフォームにセットする直前に呼び出されるため、 reset()で、チェックボックスや複数選択リストのプロパティを選択されていない状態に更新することで、 リクエストで何も送られてこなかった場合でも、選択状態を解除することができます。
@Component(instance = InstanceType.SESSION) public class XxxDto implements Serializable { private static final long serialVersionUID = 1L; public boolean foo; public String[] bar; ... public void reset() { foo = false; bar = new String[0]; } }