Tiempo de espera de la sesión y manejo de ViewExpiredException en la solicitud JSF / PrimeFaces ajax

Encuentro que este artículo es útil para solicitudes sin ajax. ¿Cómo puedo manejar la caducidad de la sesión y ViewExpiredException en JSF 2? pero no puedo hacer uso de esto cuando estoy enviando una llamada AJAX.

Supongamos que en un cuadro de diálogo de Primefaces, estoy haciendo una solicitud posterior usando AJAX y la sesión ya ha expirado. Veo que mi página se atasca.

¿Cómo arreglar este tipo de escenario de modo que cuando publico usando AJAX, podría redirigirlo a mi página expirada y luego reenviarlo a la página de inicio de sesión similar a la solución en el enlace de arriba?

JSF2 / Primefaces / Glassfish

Las excepciones que se lanzan durante las solicitudes ajax no tienen, por defecto, ninguna retroalimentación en el lado del cliente. Solo cuando ejecute Mojarra con la etapa del proyecto establecida en Development y use , obtendrá una alerta de JavaScript con el tipo y mensaje de excepción. Pero aparte de eso, y en PrimeFaces, por defecto no hay retroalimentación. Sin embargo, puede ver la excepción en el registro del servidor y en la respuesta ajax (en la sección “Red” del conjunto de herramientas del desarrollador del webbrowser).

ViewExpiredException implementar un ExceptionHandler personalizado que básicamente hace el siguiente trabajo cuando hay una ViewExpiredException en la cola:

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

Alternativamente, puede usar la biblioteca de utilidades JSF OmniFaces . Tiene un FullAjaxExceptionHandler para exactamente este propósito (código fuente aquí , demostración de demostración aquí ).

Ver también:

  • ¿Por qué usar una herramienta JSF ExceptionHandlerFactory en lugar de una redirección de ?
  • ¿Cuál es la forma correcta de lidiar con las excepciones JSF 2.0 para componentes AJAXified?

Una fusión entre la respuesta de @BalusC y esta publicación , ¡resolví mi problema!

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

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

Mi faces-config.xml

     your.package.here.CustomExceptionHandlerFactory    

Estoy usando Mojarra 2.1.7 en modo de producción con JBoss 7. Después de que la sesión caduque, las llamadas AJAX devuelven un documento XML de error. Puede detectar fácilmente este error utilizando el controlador usual onerror de f: ajax.

     

He incluido esto en mi clase ViewExpiredExceptionHandler y funcionó bien para mí en 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 esto ayude

Me enfrenté a este problema, el requisito debe mostrar una ventana emergente de confirmación cuando el usuario realiza cualquier acción después de que la sesión se agote, mi solución propuesta fue:

            

MyRedirectEntryPoint debe extender AuthenticationProcessingFilterEntryPoint y anular el método de inicio

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

Ahora puede vincular simplemente una función javascript de callback para detectar el error 403 arrojado y hacer lo que quiera:

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