【问题标题】:Error pages for exceptions during page rendering页面呈现期间异常的错误页面
【发布时间】:2013-02-07 11:42:07
【问题描述】:

在我的 JSF 应用程序的支持 bean 中,可能随时抛出某些异常,我想通过重定向到错误页面来对此做出反应。我已经包含了omnifaces FullAjaxExceptionHandler,我的web.xml 包含

<error-page>
    <exception-type>my.own.ResourceNotFoundException</exception-type>
    <location>/error/error404.xhtml</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/error/error500.xhtml</location>
</error-page>

在大多数情况下,包括 Ajax 请求,这都能正常工作:ResourceNotFoundException 将我带到错误页面。但是,当在带有 @PostConstruct 注释的方法中引发异常时,我总是会得到错误代码 500 的通用页面。

这是因为 JSF 将异常包装在其他东西中,而 web.xml 中的机制无法识别它吗?如果是,我怎样才能让它按预期工作?

这是我在服务器日志中看到的异常跟踪:

    Feb 07, 2013 11:08:32 AM com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error Rendering View[/my/projects/details/details.xhtml]
javax.el.ELException: //P:/codebase/code/portal/jsf-impl/target/classes/META-INF/resources/common/title.xhtml: Bei der Ressourcen-Einspeisung auf dem verwalteten Bean projectDetailsController ist ein Fehler aufgetreten.
    at com.sun.faces.facelets.compiler.TextInstruction.write(TextInstruction.java:90)
    at com.sun.faces.facelets.compiler.UIInstructions.encodeBegin(UIInstructions.java:82)
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:302)
    at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:309)
    at com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:105)
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
    at com.sun.faces.renderkit.html_basic.CompositeRenderer.encodeChildren(CompositeRenderer.java:78)
    at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at my.own.filters.SecurityFilter.doFilter(SecurityFilter.java:48)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:185)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:151)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at my.own.UTF8Valve.invoke(UTF8Valve.java:34)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
Caused by: com.sun.faces.mgbean.ManagedBeanCreationException: Bei der Ressourcen-Einspeisung auf dem verwalteten Bean projectDetailsController ist ein Fehler aufgetreten.
    at com.sun.faces.mgbean.BeanBuilder.invokePostConstruct(BeanBuilder.java:229)
    at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:105)
    at com.sun.faces.mgbean.BeanManager.createAndPush(BeanManager.java:409)
    at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:269)
    at com.sun.faces.el.ManagedBeanELResolver.resolveBean(ManagedBeanELResolver.java:244)
    at com.sun.faces.el.ManagedBeanELResolver.getValue(ManagedBeanELResolver.java:116)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at org.apache.el.parser.AstIdentifier.getValue(AstIdentifier.java:71)
    at org.apache.el.parser.AstValue.getValue(AstValue.java:147)
    at org.apache.el.parser.AstDeferredExpression.getValue(AstDeferredExpression.java:44)
    at org.apache.el.parser.AstCompositeExpression.getValue(AstCompositeExpression.java:50)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:189)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2362)
    at com.sun.faces.el.CompositeComponentAttributesELResolver$ExpressionEvalMap.get(CompositeComponentAttributesELResolver.java:345)
    at javax.el.MapELResolver.getValue(MapELResolver.java:52)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at org.apache.el.parser.AstValue.getValue(AstValue.java:169)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:189)
    at com.sun.faces.facelets.el.ELText$ELTextVariable.writeText(ELText.java:227)
    at com.sun.faces.facelets.el.ELText$ELTextComposite.writeText(ELText.java:150)
    at com.sun.faces.facelets.compiler.TextInstruction.write(TextInstruction.java:85)
    ... 43 more
Caused by: com.sun.faces.spi.InjectionProviderException
    at com.sun.faces.vendor.WebContainerInjectionProvider.invokeAnnotatedMethod(WebContainerInjectionProvider.java:119)
    at com.sun.faces.vendor.WebContainerInjectionProvider.invokePostConstruct(WebContainerInjectionProvider.java:99)
    at com.sun.faces.mgbean.BeanBuilder.invokePostConstruct(BeanBuilder.java:223)
    ... 66 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.faces.vendor.WebContainerInjectionProvider.invokeAnnotatedMethod(WebContainerInjectionProvider.java:117)
    ... 68 more
Caused by: my.own.ResourceNotFoundException: Did not find project
    at my.own.projects.details.ProjectDetailsController.createModel(ProjectDetailsController.java:198)

【问题讨论】:

    标签: jsf omnifaces


    【解决方案1】:

    正如您的日志所示,ResourceNotFoundException 包含在其他四个异常中。

    您可以像Duke's Forest example 中的那样开发自己的CustomExceptionHandler,而不是使用omnifaces FullAjaxExceptionHandler,甚至可以扩展它并降低原因,直到到达ResourceNotFoundException,然后使用NavigationHandler 重定向到所需的错误页面。

    这里是来自 Duke's Forest 示例的相关类和 faces-config.xml 的编辑版本。即使@PostConstruct 方法中发生异常,这也应该可以正常工作:

    CustomExceptionHandlerFactory.java

    package com.forest.exception;
    
    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;
        }
    
    }
    

    CustomExceptionHandler.java

    package com.forest.exception;
    
    public class CustomExceptionHandler extends ExceptionHandlerWrapper {
        private static final Logger log = Logger.getLogger(CustomExceptionHandler.class.getCanonicalName());
        private ExceptionHandler wrapped;
    
        CustomExceptionHandler(ExceptionHandler exception) {
            this.wrapped = exception;
        }
    
        @Override
        public ExceptionHandler getWrapped() {
            return wrapped;
        }
    
        private boolean includesResourceNotFoundException(Throwable t) {
            if(t == null) {
                return false;
            else {
                return t instanceof ResourceNotFoundException || includesResourceNotFoundException(t.getCause());
            }
        }
    
    
        @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
                if(hasResourceNotFoundException(t) {
                    try {
                        //log error ?
                        log.log(Level.SEVERE, "Critical Exception!", t);
    
                        //redirect error page
                        requestMap.put("exceptionMessage", t.getMessage());
                        nav.handleNavigation(fc, null, "/error/error500?face-redirect=true");
                        fc.renderResponse();
                    } finally {
                        //remove it from queue
                        i.remove();
                    }
                }
            }
            //parent hanle
            getWrapped().handle();
        }
    }
    

    faces-config.xml(部分)

    <factory>
            <exception-handler-factory>
                com.forest.exception.CustomExceptionHandlerFactory
            </exception-handler-factory>
    </factory>
    

    【讨论】:

    • 我们最终确实使用了自定义异常处理程序,但这种方法相当粗糙,因为异常被硬编码到处理程序中。我猜潜在的问题是JSF产生的确切异常堆栈有些不可预测,所以我们只能搜索一些已知原因......
    猜你喜欢
    • 2014-04-18
    • 2014-11-21
    • 1970-01-01
    • 2021-09-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    相关资源
    最近更新 更多