Tempo limite da session e manipulação de ViewExpiredException no pedido ajax JSF / PrimeFaces

Eu acho este artigo para ser útil para pedido não-ajax Como lidar com a expiração da session e ViewExpiredException no JSF 2? mas eu não posso fazer uso disso quando estou enviando usando uma chamada AJAX.

Suponha que em uma checkbox de diálogo primefaces, eu esteja fazendo uma solicitação de post usando AJAX e a session já tenha expirado. Eu vejo minha página ficando presa.

Como corrigir esse tipo de cenário de tal forma que quando eu postar usando AJAX, eu poderia redirecioná-lo para a minha visão da página expirada e, em seguida, encaminhá-lo para a página de login semelhante à solução no link acima?

JSF2 / Primefaces / Glassfish

    Exceções que são lançadas durante as solicitações do ajax têm, por padrão, nenhum feedback no lado do cliente. Somente quando você executar o Mojarra com o estágio do projeto configurado como Development e usar , você receberá um alerta JavaScript com o tipo e a mensagem de exceção. Mas além disso, e no PrimeFaces, não há nenhum feedback por padrão. No entanto, você pode ver a exceção no log do servidor e na resposta do ajax (na seção “Rede” do conjunto de ferramentas do desenvolvedor do navegador).

    Você precisa implementar um ExceptionHandler personalizado que faça basicamente o seguinte trabalho quando houver uma ViewExpiredException na fila:

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

    Como alternativa, você poderia usar a biblioteca de utilitários JSF OmniFaces . Ele tem um FullAjaxExceptionHandler exatamente para esse propósito (código-fonte aqui , demonstração aqui ).

    Veja também:

    • Por que usar um JSF ExceptionHandlerFactory em vez de redirecionamento de

      ?

    • Qual é a maneira correta de lidar com as exceções do JSF 2.0 para componentes AJAXified?

    Uma mescla entre a resposta do @BalusC e esse post , resolvi meu problema!

    Minha exceçãoHandlerWrapper:

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

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

    Meu faces-config.xml

     < ?xml version='1.0' encoding='UTF-8'?>    your.package.here.CustomExceptionHandlerFactory    

    Eu estou usando o Mojarra 2.1.7 no modo de produção com o JBoss 7. Após a session expirar, as chamadas AJAX retornam um documento XML de erro. Você pode facilmente pegar esse erro usando o manipulador onerror usual de f: ajax.

         

    Eu incluí isso na minha class ViewExpiredExceptionHandler e funcionou bem para mim no WAS

      public void handle() throws FacesException { FacesContext facesContext = FacesContext.getCurrentInstance(); for (Iterator 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(); } 

    Espero que isto ajude

    Eu enfrentei este problema, Requisito precisa exibir um pop-up de confirmação quando o usuário fizer qualquer ação após a session ser expirada, minha solução proposta foi:

                

    O MyRedirectEntryPoint deve estender AuthenticationProcessingFilterEntryPoint e replace o método de início

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

    Agora você pode simplesmente ligar uma function javascript de callback para capturar o erro 403 e fazer o que você quiser:

     $(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}/'; } });