46

この記事は、ajax 以外のリクエストに役立つと思います JSF 2 でセッションの有効期限と ViewExpiredException を処理する方法は? しかし、AJAX 呼び出しを使用して送信しているときは、これを利用できません。

primefaces ダイアログで、AJAX を使用して投稿リクエストを作成していて、セッションがすでにタイムアウトになっているとします。ページが動かなくなっています。

この種のシナリオを修正して、AJAX を使用して投稿したときに、期限切れのビュー ページにリダイレクトしてから、上記のリンクのソリューションと同様のログイン ページに転送できるようにするにはどうすればよいですか?

JSF2/Primefaces/グラスフィッシュ

4

6 に答える 6

52

ajax リクエスト中にスローされる例外は、デフォルトではクライアント側でまったくフィードバックされません。Developmentプロジェクト ステージを に設定してMojarra を実行した場合にのみ<f:ajax>、例外タイプとメッセージを含む生の JavaScript アラートが表示されます。しかし、それ以外の場合、PrimeFaces では、デフォルトでフィードバックはまったくありません。ただし、サーバー ログと ajax 応答 (Web ブラウザーの開発者ツールセットの [ネットワーク] セクション) で例外を確認できます。

キューExceptionHandlerに がある場合、基本的に次のジョブを実行するカスタムを実装する必要があります。ViewExpiredException

String errorPageLocation = "/WEB-INF/errorpages/expired.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();

または、JSF ユーティリティ ライブラリOmniFacesを使用することもできます。FullAjaxExceptionHandlerまさにこの目的のためのものです(ソースコードはこちら、ショーケースデモはこちら)。

以下も参照してください。

于 2012-06-26T11:14:11.623 に答える
18

@BalusC の回答とこの投稿をマージして、問題を解決しました。

私のExceptionHandlerWrapper:

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    CustomExceptionHandler(ExceptionHandler exception) {
        this.wrapped = exception;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

    @Override
    public void handle() throws FacesException {
        final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
        while (i.hasNext()) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context
                    = (ExceptionQueuedEventContext) event.getSource();

            // get the exception from context
            Throwable t = context.getException();

            final FacesContext fc = FacesContext.getCurrentInstance();
            final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
            final NavigationHandler nav = fc.getApplication().getNavigationHandler();

            //here you do what ever you want with exception
            try {

                //log error ?
                //log.log(Level.SEVERE, "Critical Exception!", t);
                if (t instanceof ViewExpiredException) {
                    requestMap.put("javax.servlet.error.message", "Session expired, try again!");
                    String errorPageLocation = "/erro.xhtml";
                    fc.setViewRoot(fc.getApplication().getViewHandler().createView(fc, errorPageLocation));
                    fc.getPartialViewContext().setRenderAll(true);
                    fc.renderResponse();
                } else {
                    //redirect error page
                    requestMap.put("javax.servlet.error.message", t.getMessage());
                    nav.handleNavigation(fc, null, "/erro.xhtml");
                }

                fc.renderResponse();
                // remove the comment below if you want to report the error in a jsf error message
                //JsfUtil.addErrorMessage(t.getMessage());
            } finally {
                //remove it from queue
                i.remove();
            }
        }
        //parent hanle
        getWrapped().handle();
    }
}

私のExceptionHandlerFactory:

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory parent;

    // this injection handles jsf
    public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        ExceptionHandler handler = new CustomExceptionHandler(parent.getExceptionHandler());
        return handler;
    }

}

私の顔-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">

    <factory>
        <exception-handler-factory>
            your.package.here.CustomExceptionHandlerFactory
        </exception-handler-factory>
    </factory>
</faces-config>
于 2015-02-19T18:23:52.047 に答える
3

JBoss 7 で本番モードで Mojarra 2.1.7 を使用しています。セッションの有効期限が切れた後、AJAX 呼び出しはエラー XML ドキュメントを返します。f:ajax の通常の onerror ハンドラを使用して、このエラーを簡単にキャッチできます。

<script type="text/javascript">
    function showError(data) {
        alert("An error happened");
        console.log(data);
    }
</script>

<h:commandLink action="...">
    <f:ajax execute="..." render="..." onerror="showError"/>
</h:commandLink>
于 2012-10-06T00:55:46.853 に答える
1

私はこの問題に直面しました。セッションがタイムアウトした後にユーザーが何らかのアクションを実行したときに確認ポップアップを表示する必要があるという要件でした。提案された解決策は次のとおりです。

<security:http use-expressions="true" auto-config="true" entry-point-ref="authenticationEntryPoint">
            <security:intercept-url pattern="/common/auth/**" access="permitAll" />
            <security:intercept-url pattern="/javax.faces.resource/**" access="permitAll" />
            <security:intercept-url pattern="/**/   *.*" access="hasRole('ROLE_ADMIN')" />
            <security:form-login login-page="/common/auth/login.jsf" />
            <!-- <security:remember-me key="secret" services-ref="rememberMeServices" /> -->
            <security:logout invalidate-session="true" logout-success-url="/common/auth/login.jsf" />
        </security:http>
        <bean id="authenticationEntryPoint" class="com.x.y.MyRedirectEntryPoint" >
           <property name="loginFormUrl" value="/common/auth/login.jsf"/>
        </bean>

MyRedirectEntryPoint は AuthenticationProcessingFilterEntryPoint を拡張し、開始メソッドをオーバーライドする必要があります

public void commence(HttpServletRequest request, HttpServletResponse response,   AuthenticationException authException)
        throws IOException, ServletException {
    boolean ajaxRedirect = request.getHeader("faces-request") != null
            && request.getHeader("faces-request").toLowerCase().indexOf("ajax") > -1;
    if (ajaxRedirect) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            response.sendError(403);

        }
    } else {

        super.commence(request, response, authException);
    }
}

これで、コールバック JavaScript 関数をバインドして、スローされた 403 エラーをキャッチし、必要なことを実行できます。

$(document).bind('ajaxError',
                    function(event, request, settings, exception){
                          if (request.status==403){
                             //do whatever you wanted may be show a popup or just redirect
                             window.location = '#{request.contextPath}/';
                             }
                             });
于 2013-09-10T09:28:41.010 に答える