このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
日本語の問題が解決したので、次のステップに移る。
今日は、キャンセル処理について。
/WEB-INF/pages/filter/edit-info.jsp では、
タグライブラリの <html:cancel> を使って、
キャンセル用のボタンを配置しているが、
これを押すと、InvalidCancelException 例外が発生する。
まず、これを直さなければならない。
何故 <html:cancel> を配置するだけで例外が発生するのか。
<html:cancel> には「キャンセル」という特別な役割がある。
つまり、このボタンで送信した場合、
何も処理を行わないずに終了するという目的がある。
そのため、Struts はこのボタンを特別扱いしており、
これが押された場合は「フォームの検証を行わない」。
キャンセルするということは、編集内容を放棄する訳だから、
送信される内容を検証する必要がないというのが理由である。
しかし、<html:cancel> が押された場合でも、
「通常と同じように、Action が呼び出される。」
そのため、Action でキャンセルが押されたことを検出し、
if 等で分岐して適切な処理を行う必要がある。
もしこれを忘れると、<html:cancel> が押されても
通常の送信と同じように Action で処理されてしまうため、
検証を回避できてしまうというセキュリティ上の問題がある。
そのため、<html:cancel> は既定では許されておらず、
使うと InvalidCancelException 例外が発生するのだ。
さて、<html:cancel> を有効にする場合は、
キャンセルを行う事を Struts の設定ファイルに明示し、
Action でキャンセルかどうかを判別するコードを追加する。
最初に、/WEB-INF/struts-config.xml の、
/filter/update-info に対応する <action> を書き換える。
<!-- 情報更新 -->
<action path="/filter/update-info"
name="filterInfoForm" scope="request"
type="jp.loafer.test.actions.UpdateFilterInfoAction"
cancellable="true">
<!-- 成功時は一覧画面へ戻る -->
<forward name="success"
path="/filter/list.do" />
<!-- キャンセル時も一覧画面へ戻る -->
<forward name="cancel"
path="/filter/list.do" />
</action>
ポイントは、「cancellable」属性だ。
この属性値を true と明示することで、
安全装置である InvalidCancelException の発生を抑制する。
name="cancel" の <forward> は必須ではないが、
キャンセルを押した際の遷移先を指定するために追加した。
もし、cancellable="true" と指定した場合は、
必ず Action のコードを書き換えて、
キャンセルに対する処理を追加する必要がある。
========== UpdateFilterInfoAction.java ==========
package jp.loafer.test.actions;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jp.loafer.test.beans.Filter;
import jp.loafer.test.forms.FilterInfoForm;
import jp.loafer.test.util.FilterManager;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class UpdateFilterInfoAction extends
Action {
public UpdateFilterInfoAction() {
super();
}
@Override
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// キャンセルを押した場合は更新しない
if (isCancelled(request)) {
return mapping
.findForward(Forwards.CANCEL_KEY);
}
// フォームを取得
FilterInfoForm infoForm = (FilterInfoForm)form;
// 現在のフィルタ設定を読み込み
Filter filter = FilterManager.load();
// フィルタ情報のみ更新し
filter.setInfo(infoForm.getInfo());
// 保存する
FilterManager.save(filter);
// OK
return mapping
.findForward(Forwards.SUCCESS_KEY);
}
}
========== end of UpdateFilterInfoAction#execute ==========
<html:cancel> が押されたことは、
Action#isCancelled() によって検出することができる。
今回は、特にキャンセルに対応して行うことはないため、
「cancel」で登録した ActionForward へと転送するだけで、
もちろん、通常ならば行う更新処理は実行しない。
なお、Forwards.CANCEL_KEY は以下のような定義で、
Forwards クラスに追加してある。
static public final String CANCEL_KEY = "cancel";
・Forwards クラスはこちら
http://mixi.jp/view_diary.pl?id=374835977&owner_id=2300658
キャンセル時でも Action は呼ばれるため、
isCancelled() を呼び出して分岐させることで、
適切な後処理やリソースの解放等を行う機会が得られるのだ。
このように、キャンセルは特別な機能として扱われている。