javax.faces.application.ViewExpiredException:无法恢复视图

时间:2010-09-04 15:45:31

标签: jsf jsf-2 logout viewexpiredexception

我用容器管理的安全性编写了简单的应用程序。问题是当我登录并打开另一个我注销的页面时,然后我回到第一页,我点击任何链接等或刷新页面我得到这个例外。我想这是正常的(或者可能不是:))因为我退出了会话被破坏了。我应该怎么做才能将用户重定向到例如index.xhtml或login.xhtml,并使他免于看到错误页面/消息?

换句话说,如何在我退出后自动将其他页面重定向到索引/登录页面?

这是:

javax.faces.application.ViewExpiredException: viewId:/index.xhtml - View /index.xhtml could not be restored.
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at filter.HttpHttpsFilter.doFilter(HttpHttpsFilter.java:66)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
    at java.lang.Thread.run(Thread.java:619)

10 个答案:

答案 0 :(得分:330)

答案 1 :(得分:55)

您是否尝试在web.xml下面添加以下行?

<context-param>
   <param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
   <param-value>true</param-value>
</context-param>

当我遇到这个问题时,我发现这非常有效。

答案 2 :(得分:5)

首先,在更改 web.xml 之前,您需要做的是确保您的ManagedBean implements Serializable

@ManagedBean
@ViewScoped
public class Login implements Serializable {
}

特别是如果您使用 MyFaces

答案 3 :(得分:3)

避免使用Richfaces中的多部分表单:

if (showA)
{
  model.List = model.List.Where(x => (x.a1 != null && x.a1 != 0) || (x.a2 != null && x.a2 != 0));
}
if (showB)
{
  model.List = model.List.Where(x => (x.b1 != null && x.b1 != 0) || (x.b2 != null && x.b2 != 0));
}
if (showC)
{
  model.List = model.List.Where(x => (x.c1 != null && x.c1 != 0) || (x.c2 != null && x.c2 != 0));
}

如果您使用的是Richfaces,我发现多部分表单中的ajax请求会在每个请求中返回一个新的View ID。

如何调试:

在每个ajax请求上返回一个View ID,只要View ID始终相同,就可以了。如果您在每个请求中获得新的视图ID,则存在问题,必须修复。

答案 4 :(得分:0)

您可以使用自己的自定义AjaxExceptionHandler或primefaces-extensions

更新faces-config.xml

...
<factory>
  <exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...

在jsf页面中添加以下代码

...
<pe:ajaxErrorHandler />
...

答案 5 :(得分:0)

我收到了这个错误:javax.faces.application.ViewExpiredException。当我使用不同的请求时,我发现那些具有相同的JsessionId,即使在重新启动服务器之后也是如此。 所以这是由于浏览器缓存。只需关闭浏览器并尝试即可。

答案 6 :(得分:0)

当我们的页面闲置x个时间时,视图将过期并抛出javax.faces.application.ViewExpiredException以防止这种情况发生 一种解决方案是创建扩展ViewHandler的CustomViewHandler 并覆盖restoreView方法,所有其他方法都被委托给Parent

import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

public class CustomViewHandler extends ViewHandler {
    private ViewHandler parent;

    public CustomViewHandler(ViewHandler parent) {
        //System.out.println("CustomViewHandler.CustomViewHandler():Parent View Handler:"+parent.getClass());
        this.parent = parent;
    }

    @Override 
    public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
    /**
     * {@link javax.faces.application.ViewExpiredException}. This happens only  when we try to logout from timed out pages.
     */
        UIViewRoot root = null;
        root = parent.restoreView(facesContext, viewId);
        if(root == null) {
            root = createView(facesContext, viewId);
        }
        return root;
    }

    @Override
    public Locale calculateLocale(FacesContext facesContext) {
        return parent.calculateLocale(facesContext);
    }

    @Override
    public String calculateRenderKitId(FacesContext facesContext) {
        String renderKitId = parent.calculateRenderKitId(facesContext);
        //System.out.println("CustomViewHandler.calculateRenderKitId():RenderKitId: "+renderKitId);
        return renderKitId;
    }

    @Override
    public UIViewRoot createView(FacesContext facesContext, String viewId) {
        return parent.createView(facesContext, viewId);
    }

    @Override
    public String getActionURL(FacesContext facesContext, String actionId) {
        return parent.getActionURL(facesContext, actionId);
    }

    @Override
    public String getResourceURL(FacesContext facesContext, String resId) {
        return parent.getResourceURL(facesContext, resId);
    }

    @Override
    public void renderView(FacesContext facesContext, UIViewRoot viewId) throws IOException, FacesException {
        parent.renderView(facesContext, viewId);
    }

    @Override
    public void writeState(FacesContext facesContext) throws IOException {
        parent.writeState(facesContext);
    }

    public ViewHandler getParent() {
        return parent;
    }

}   

然后你需要将它添加到你的faces-config.xml

<application>
    <view-handler>com.demo.CustomViewHandler</view-handler>
</application>

感谢以下链接的原始答案: http://www.gregbugaj.com/?p=164

答案 7 :(得分:-2)

请在您的web.xml中添加此行 它对我有用

<context-param>
        <param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name> 
        <param-value>true</param-value>     
    </context-param>

答案 8 :(得分:-2)

我自己遇到了这个问题并意识到这是因为我创建的过滤器的副作用是过滤了应用程序上的所有请求。只要我修改过滤器以仅选择某些请求,就不会发生此问题。在您的应用程序中检查此类过滤器并查看它们的行为可能会很好。

答案 9 :(得分:-3)

我将以下配置添加到 web.xml ,然后解决了。

<context-param>
    <param-name>com.sun.faces.numberOfViewsInSession</param-name>
    <param-value>500</param-value>
</context-param>
<context-param>
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>500</param-value>
</context-param>