web-dev-qa-db-fra.com

JSF 2 Gestion globale des exceptions, absence de navigation vers la page d'erreur

Je développe une application Web basée sur JSF 2.0. J'essaie d'implémenter un gestionnaire d'exception global qui redirige l'utilisateur vers une page d'erreur générique chaque fois qu'une exception se produit (par exemple, NullPointerException, ServletException, ViewExpiredException, etc.).

Lorsqu'un point NPE survient dans mon application, mon point d'arrêt customnavhandler est touché et le code NavigationHandler est exécuté, mais la redirection vers la page d'erreur ne se produit pas, la page demandée reste partiellement rendue. Une idée de ce qui pourrait être faux ici? Une information est que je jette délibérément un NPE sur la page demandée (qui a été rendue partiellement après NPE)

Mon entrée faces-config.xml

<factory>
  <exception-handler-factory>
    com.common.exceptions.CustomExceptionHandlerFactory
  </exception-handler-factory>
</factory>

Mon CustomNavHandler

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

private static final Logger logger = Logger.getLogger("com.gbdreports.common.exception.CustomExceptionHandler");
private final ExceptionHandler wrapped;

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

@Override
public ExceptionHandler getWrapped() {
    return this.wrapped;

}
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 ExternalContext externalContext = fc.getExternalContext();
        final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();            
        final ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) fc.getApplication().getNavigationHandler();               
        //here you do what ever you want with exception             
        try {                   
            //log error ?      
            logger.error("Severe Exception Occured");
            //log.log(Level.SEVERE, "Critical Exception!", t);                   
            //redirect error page                 
            requestMap.put("exceptionMessage", t.getMessage());                 
            nav.performNavigation("/TestPRoject/error.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(); 
        }

}

Mon usine customNavhandler

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {


 private ExceptionHandlerFactory parent;

  public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
    this.parent = parent;
  }

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

  }

}
7
user1722908

C'est probablement parce que la demande en cours est une demande ajax (asynchrone). Le gestionnaire d'exceptions que vous avez créé est conçu pour les requêtes régulières (synchrones).

La bonne façon de changer de vue dans le cas d'une exception ajax est la suivante:

String viewId = "/error.xhtml";
ViewHandler viewHandler = context.getApplication().getViewHandler();
context.setViewRoot(viewHandler.createView(context, viewId));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();

C'est cependant un peu naïf. Cela ne fonctionnera pas si l'exception ajax est lancée au cours du rendu d'une réponse ajax.

Je suggère de ne pas réinventer la roue. La bibliothèque d’utilitaires JSF - OmniFaces dispose d’une solution de travail complète à l’aide de FullAjaxExceptionHandler . Vous pouvez trouver le code source complet ici et l'exemple de démonstration ici . Il utilise les déclarations <error-page> de l'API de servlet standard dans web.xml. De cette manière, les pages d'erreur sont également réutilisables pour les requêtes synchrones, avec l'aide de FacesExceptionFilter, également fournie par OmniFaces.

Voir également:

14
BalusC

Une manière unifiée de gérer à la fois l'exception des requêtes ajax et non ajax pourrait être utilisée pour simplifier votre code. Au lieu de

requestMap.put("exceptionMessage", t.getMessage());                 
nav.performNavigation("/TestPRoject/error.xhtml");                 
fc.renderResponse();

est suffisant pour utiliser:

fc.getExternalContext().redirect("/TestPRoject/error.xhtml");
0
Alex Tsurika