Wicket AjaxButton onSubmit()でエラーが発生した際の振る舞いを制御する


AjaxButton#onSubmit()にて、Exception 発生時に、
AjaxButton#onError(AjaxRequestTarget target, Form<?> form) 処理の制御が移らず、
うまくハンドリングができておりません。
ハンドリングできていない理由を調べてみました。


参考

そもそも、onSubmit()でエラーが発生したら、onError() は実行されない。

onError()は実行されない動作をするものでした。1
[1] 私が勝手に勘違いをしていただけとなります。

そのため、以下のように Exception 発生時にハンドリングを行う必要があります。2
[2] 引数同じなので、Exception が発生したら、onError を呼び出すでもいいかもしれません。

    AjaxButton sendMessage = new AjaxButton("sendMessage", Model.of(getString("messageButtonLabelText"))) {
        private static final long serialVersionUID = -8204140666393922700L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form) {

            try {
                // メール送信要求を登録
                ContactMailTaskManage contactMailTaskManage = (ContactMailTaskManage) form.getModelObject();
                // 内部でJPA呼び出し、ここで、PersistenceExceptionが発生する可能性がある。
                mailTaskService.execute(contactMailTaskManage);
            } catch (PersistenceException e) {
                log.error("Mail transmission failed.", e);
                // エラーメッセージを表示して処理を終了
                error(getString("messageMailSendError"));
                target.add(form);
                return;
            }
            // Formに対してのオペレーション
            token.regenerateToken();
            success(getString("messageMailSendSucceed"));
            target.add(form);
        }

        @Override
        protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
            super.updateAjaxAttributes(attributes);
            // AjaxButton は (というかButtonは) setOutputMarkupId(true) なので、特に呼び出さなくてOK
            final AjaxCallListener ajaxCallListener = new AjaxCallListener();
            ajaxCallListener.onPrecondition("return confirm('" + getString("messageMailSendConfirm") + "');");
            ajaxCallListener.onBeforeSend("$('#" + getMarkupId() + "').prop('disabled',true);");
            ajaxCallListener.onComplete("$('#" + getMarkupId() + "').prop('disabled',false);$('#" + getMarkupId() + "').focus();");
            attributes.getAjaxCallListeners().add(ajaxCallListener);
        }

        @Override
        protected void onError(AjaxRequestTarget target, Form<?> form) {
            error(getString("messageMailSendError"));
            target.add(form);
        }
    };

ExceptionSettings#setAjaxErrorHandlingStrategy() でAjax Error時の振る舞いを変更する。

Application クラスで、

getExceptionSettings().setAjaxErrorHandlingStrategy(ExceptionSettings.AjaxErrorStrategy.INVOKE_FAILURE_HANDLER);
を設定することで、Ajax Error発生時の振る舞いを変更することができます。3
[3] デフォルトの振る舞いは、AjaxErrorStrategy.REDIRECT_TO_ERROR_PAGE で通常リクエストと同じ、ErrorPageに遷移します。

AjaxButton で updateAjaxAttribute 内で、AjaxRequestAttributes#onFailre() で、
失敗時のjavascriptを定義すると、Exception発生時に、そのjavascriptが呼び出されます。

    @Override
    protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
        super.updateAjaxAttributes(attributes);
        // AjaxButton は (というかButtonは) setOutputMarkupId(true) なので、特に呼び出さなくてOK
        final AjaxCallListener ajaxCallListener = new AjaxCallListener();
        ajaxCallListener.onPrecondition("return confirm('" + getString("messageMailSendConfirm") + "');");
        ajaxCallListener.onBeforeSend("$('#" + getMarkupId() + "').prop('disabled',true);");
        // 失敗時のjavascriptの定義
        ajaxCallListener.onFailure("alert('onFailure');");
        ajaxCallListener.onComplete("$('#" + getMarkupId() + "').prop('disabled',false);$('#" + getMarkupId() + "').focus();");
        attributes.getAjaxCallListeners().add(ajaxCallListener);
    }

どちらで実装を進めるか.

個人的には、デフォルトAjaxErrorStrategy.REDIRECT_TO_ERROR_PAGE でよいかと思いました。
個別でコントロールできたらよさそうに思いましたが、何か設定があったりするのかもしれません。 以上です。

コメント