2

問題は次のとおりです。EJB が次の例外をスローします (glassfish ログから):

SEVERE: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
    at com.extremelatitudesoftware.security.auth.CredentialsController.checkForPreviousConfirmation(CredentialsController.java:244)

そして、例外スタックのクライアント側 (一番下) には、次のように表示されます。

WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
    at com.extremelatitudesoftware.accesscontrol.registration.RegistrationConfirmationBean.setChallengeQuestion(RegistrationConfirmationBean.java:61)
    at com.extremelatitudesoftware.accesscontrol.registration.RegistrationConfirmationBean.fetchChallengeResponse(RegistrationConfirmationBean.java:51)

もちろん、ブラウザーでは、null ポインター例外があったことを示す一般的な 500 例外エラーが発生します。

「com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException」を検出し、「おっと、これは既に確認済みです!」のようなカスタム エラー ページが必要です。

これが行われるように、クライアント/JSFレイヤーが例外を正しく「見る」ようにするために、誰かが私を正しい方向に向けることができますか?

これが問題の使用例です
。EJB 層に、ユーザーが以前にログイン アカウントを確認したかどうかを確認するメソッドがあります。そうでない場合は、リクエストを処理して新しいアカウントを確認します。彼らが古い電子メールに戻って「うーん、それをもう一度クリックしましょう」と言った場合、バックエンドはそれを検出し、JSF/クライアント層によって取得されることを意図して例外をスローし、ユーザーに通知しますアカウントがすでに確認されていること。


サンプルコードの追加:

条件をチェックし、必要に応じて例外をスローするメソッド。ほとんどの場合、これは発生しないため、誰かがアカウントを確認するたびに不必要な呼び出しを行う代わりに、このメカニズムを使用したいと考えています.

...
private void checkForPreviousConfirmation(Credentials cr) 
                                    throws LoginPreviouslyConfirmedException {

    if (!(CredentialsStatusType.PENDING.equals(cr.getStatus()))
         || !(CredentialsDispositionType.WAITING.equals(cr.getDisposition()))) {
      String msg = "Attempting to confirm previously confirmed login using "
              + "confirmation UUID: " + cr.getConfirmationUuid();
      Logger.getLogger(CredentialsController.class.getName()).log(Level.INFO,
              msg);
      throw new LoginPreviouslyConfirmedException(msg);
    }
  }

カスタム例外:

public class LoginPreviouslyConfirmedException extends RuntimeException {

    public LoginPreviouslyConfirmedException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public LoginPreviouslyConfirmedException(String msg) {
        super(msg);
    }
}

これは、JSF 層の ManagedBean にあります。次の方法で呼び出されます: preRenderView

        ...
public void fetchChallengeResponse() {
    try {
         crespList = regFacade.fetchChallengeResponse(confirmUuid);
    } catch (LoginPreviouslyConfirmedException ex) {
         String msg = "Attempting to confirm previously confirmed login using " + "confirmation UUID: " + getConfirmUuid();
         Logger.getLogger(RegistrationConfirmationBean.class.getName()).log(Level.SEVERE, msg, ex);
          FacesContext facesContext = FacesContext.getCurrentInstance();
          Application application = facesContext.getApplication();
          NavigationHandler navigationHandler = application.getNavigationHandler();
          navigationHandler.handleNavigation(facesContext, null, "faces/errorpages/already_confirmed.xhtml");
          facesContext.renderResponse();
        }catch (Exception ex){
          String msg = "Including this to see if the previously confirmed exception was skipped over";
              Logger.getLogger(RegistrationConfirmationBean.class.getName()).log(Level.SEVERE, msg, ex);
        }

        this.setChallengeQuestion();
      }

ログには次のように表示されます。

INFO: Attempting to confirm previously confirmed login using confirmation UUID: b90b33ca-dc69-41c1-9c60-99152810c89b
WARNING: EJB5184:A system exception occurred during an invocation on EJB CredentialsController, method: public java.util.ArrayList com.extremelatitudesoftware.security.auth.CredentialsController.fetchChallengeResponseByCredentialUuid(java.lang.String) throws com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException
WARNING: javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean

次に、いくつかトレースします。

SEVERE: Including this to see if the previously confirmed exception was skipped over
javax.ejb.EJBTransactionRolledbackException



BalusC の提案に従って、ManagedBean のコードを次のように変更しました。

public void fetchChallengeResponse() throws LoginPreviouslyConfirmedException{
     crespList = regFacade.fetchChallengeResponse(confirmUuid);
     this.setChallengeQuestion();
  }

これは web.xml にあります

<error-page>
    <exception-type>com.extremelatitudesoftware.els_commons.exceptions.LoginPreviouslyConfirmedException</exception-type>
    <location>/errorpages/already_confirmed.xhtml</location>
</error-page>

しかし、私はまだこれを取得します(これは表示されるエラーページの画像です)。

4

2 に答える 2

3

今日の調査で見つけた最も簡単で最良の答えは次のとおりです。@ApplicationException(rollback = true)アノテーションを使用してカスタム例外を装飾します。

例えば

@ApplicationException(rollback=true)
public class LoginPreviouslyConfirmedException extends Exception {...

基本的な問題は、例外をクライアントに渡す前に、EJBコンテナが少なくともいくつかの例外を「EJBTransactionRolledBackException」ラッパーでラップすることでした。よくわかりませんが、JSFがそこで発生したすべての例外を「ServletException」でラップする方法と似ているようです。実際のアプリケーションエラーが何であるかを隠すことを考えると、かなり欠陥があるように思えます。いずれの場合も、操作全体を中止せずに修正できるものであるという理由で、クライアントがスローする可能性のある特殊なケースの例外を「見る」ことを防ぎます。つまり、表示されるのは、多数の例外をラップするために使用されるEJBTransactionRolledBackExceptionだけです。これを行うと、例外を簡単にデバッグまたは処理することができなくなります。幸い、JEEの最新号には、この動作に対抗するための@ApplicationExceptionアノテーションが含まれていました。なぜ彼らが例外のラッピングを完全に止めないのかはわかりませんが。

いずれの場合も、@ ApplicationException(rollback = true)は、例外をEJBTransactionRolledBackExceptionでラップせず、そのままクライアントに返すようにサーバーに指示します。これにより、クライアントは実際の例外が何であるかを確認できるため、適切に処理できるようになります。「rollback=true」を指定すると、サーバーに現在のトランザクションをロールバックするように指示されます。そうしないと、デフォルトでfalseになり、すべてがそこにドロップされます。どんな状態であれ、すべてを終わらせる。

カスタム例外がExceptionを継承し、EJBセッションBeanのメソッドがそれをスローする場合、JSFManagedBeanで呼び出しを行うメソッドもそれをスローする必要があります。RuntimeExceptionから継承する場合、継承しません。

いずれの場合も、例外はEJBTransactionRolledBackExceptionによってラップされないため、JSFレイヤーに戻ると、カスタム例外のweb.xmlで定義された例外ページが呼び出されます。管理対象Beanで例外をキャッチする必要はありません。フィルタリングは必要ありません。特別なナビゲーションルールは必要ありません。ただし、キャッチしたい場合はキャッチできます。@ApplicationExceptionがないと、(ラップされているため)なりません。

ここにある情報(他の場所の中でも):
http ://docs.oracle.com/javaee/5/api/javax/ejb/ApplicationException.htmlhttp:
//openejb.apache.org/examples-trunk/applicationexception/
方法セッションBeanでカスタム例外を使用しますか?

とにかくこれは動作します。グーグルで正しい検索用語をもっと早く見つけられたらいいのにと思いました。

于 2012-06-08T03:09:48.073 に答える
1

例外をスローする EJB メソッドで、 を宣言しthrows LoginPreviouslyConfirmedExceptionます。次に、マネージド Bean で EJB 呼び出しをその例外の try-catch で囲みます。キャッチブロックで; ユーザーをエラーページにリダイレクトできます。または、単にメッセージをビューに送信します (h:messages、p:growl などでレンダリングされます)。

于 2012-06-06T12:00:14.290 に答える