Gestion du temps d'arrêt de la Session et de la réception ViewExpiredException sur la demande ajax de JSF / PrimeFaces

je trouve que cet article est utile pour la requête non-ajax comment gérer l'expiration de session et ViewExpiredException dans JSF 2? mais je ne peux pas l'utiliser quand je soumets en utilisant un appel AJAX.

supposons que dans une boîte de dialogue primefaces, je fais une requête post en utilisant AJAX et que la session est déjà chronométrée. Je vois ma page se coincer.

comment corriger ce genre de scénario de sorte que lorsque je poste en utilisant AJAX, je pourrais redirigez - le vers ma page de vue expirée et alors avant lui à la page de connexion similaire à la solution dans le lien ci-dessus?

JSF2/Primefaces /Glassfish

42
demandé sur Community 2012-06-26 12:10:29

5 réponses

les Exceptions qui sont lancées pendant les requêtes ajax n'ont par défaut aucun retour d'information du côté du client. Ce n'est que lorsque vous exécutez Mojarra avec project stage réglé à Development et utilisez <f:ajax> que vous recevrez une alerte JavaScript avec le type d'exception et le message. Mais à part ça, et dans PrimeFaces, il n'y a par défaut aucun retour d'information. Vous pouvez cependant voir l'exception dans le journal du serveur et dans la réponse ajax (dans la boîte à outils du développeur webbrowser "Network")." section.)

vous devez mettre en œuvre une coutume ExceptionHandler qui fait essentiellement le travail suivant quand il ya un ViewExpiredException dans la file d'attente:

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

alternativement, vous pouvez utiliser la bibliothèque utilitaire JSF OmniFaces . Il a un FullAjaxExceptionHandler pour exactement ce but (code source ici , vitrine Démo ici ).

voir aussi:

44
répondu BalusC 2017-05-23 12:02:37

une fusion entre la réponse de @BalusC et ce post , j'ai résolu mon problème!

My 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();
    }
}

My 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;
    }

}

Mon faces-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>
17
répondu Douglas Nassif Roma Junior 2015-02-19 18:23:52

J'utilise Mojarra 2.1.7 en mode Production avec JBoss 7. Après l'expiration de la session, les appels AJAX renvoient un document XML d'erreur. Vous pouvez facilement attraper cette erreur en utilisant le handler onerror habituel de f:ajax.

<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>
3
répondu RajV 2012-10-06 00:55:46

j'ai inclus ceci dans ma classe ViewExpiredExceptionHandler et il a fonctionné très bien pour moi Dans était

    public void handle() throws FacesException {
    FacesContext facesContext = FacesContext.getCurrentInstance();
                 for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents()
            .iterator(); iter.hasNext();) {
        Throwable exception = iter.next().getContext().getException();

        if (exception instanceof ViewExpiredException) {


            final ExternalContext externalContext = facesContext
                    .getExternalContext();

            try {


                facesContext.setViewRoot(facesContext.getApplication()
                        .getViewHandler()
                        .createView(facesContext, "/Login.xhtml"));     //Login.xhtml is the page to to be viewed. Better not to give /WEB-INF/Login.xhtml
                externalContext.redirect("ibm_security_logout?logoutExitPage=/Login.xhtml");    //  when browser back button is pressed after session timeout, I used this.         
                facesContext.getPartialViewContext().setRenderAll(true);
                facesContext.renderResponse();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                iter.remove();
            }
        }

    }

    getWrapped().handle();
}

Espérons que cette aide

1
répondu Ramya 2013-03-12 13:19:06

j'ai fait face à ce problème, exigence besoin d'afficher un popup de confirmation lorsque l'Utilisateur faire une action après la session est chronométré, ma solution proposée était:

<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>

la méthode MyRedirectEntryPoint doit étendre la méthode AuthenticationProcessingFilterEntrypoint et outrepasser la méthode commence

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);
    }
}

Maintenant, vous pouvez simplement lier une fonction javascript de rappel pour attraper l'erreur 403 lancée et faire ce que vous voulez:

$(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}/';
                             }
                             });
1
répondu Rami 2015-12-24 07:52:42