关山初度尘未洗,策马扬鞭再奋蹄!这篇文章主要讲述javax.faces.application.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)
答案 介绍每当
ViewExpiredException
设置为javax.faces.STATE_SAVING_METHOD
(默认)并且最终用户通过server
与<
h:form>
,<
h:commandLink>
或<
h:commandButton>
在视图上发送HTTP POST请求时,将抛出<
f:ajax>
,而相关的视图状态在会话中不再可用。视图状态被标识为
javax.faces.ViewState
的隐藏输入字段<
h:form>
的值。将状态保存方法设置为server
时,它仅包含引用会话中序列化视图状态的视图状态ID。因此,当会话由于某种原因(在服务器或客户端超时,或者在浏览器中由于某种原因不再维护会话cookie,或者在服务器中调用HttpSession#invalidate()
,或者由于服务器特定的会话cookie错误)如WildFly中所知,那么序列化视图状态在会话中不再可用,并且最终用户将获得此异常。要了解会话的工作情况,请参阅How do servlets work? Instantiation, sessions, shared variables and multithreading。JSF将在会话中存储的视图数量也有限制。达到限制时,最近最少使用的视图将过期。另见com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews。
将状态保存方法设置为
client
时,javax.faces.ViewState
隐藏输入字段包含整个序列化视图状态,因此当会话到期时,最终用户将不会获得ViewExpiredException
。但是,它仍然可能发生在群集环境中(“错误:MAC未验证”是有症状的)和/或在配置的客户端状态上存在特定于实现的超时和/或服务器在重新启动期间重新生成AES密钥时,另见Getting ViewExpiredException in clustered environment while state saving method is set to client and user session is valid如何解决它。无论解决方案如何,请确保您不使用
enableRestoreView11Compatibility
。它根本不会恢复原始视图状态。它基本上从头开始重新创建视图和所有相关的视图范围的bean,从而丢失所有原始数据(状态)。由于应用程序将以令人困惑的方式运行(“嘿,我的输入值在哪里...... ??”),这对用户体验非常不利。更好地使用无状态视图或<
o:enableRestorableView>
,这样您只能在特定视图上而不是在所有视图上进行管理。至于为什么JSF需要保存视图状态,请转到这个答案:Why JSF saves the state of UI components on server?
在页面导航上避免ViewExpiredException例如,为了避免
ViewExpiredException
当状态保存设置为server
时,在注销后导航回来,仅在注销后重定向POST请求是不够的。您还需要指示浏览器不缓存动态JSF页面,否则浏览器可能会从缓存中显示它们,而不是在您向服务器发送GET请求时从服务器请求新的(例如,通过后退按钮)。缓存页面的
javax.faces.ViewState
隐藏字段可能包含视图状态ID值,该值在当前会话中不再有效。如果您(ab)使用POST(命令链接/按钮)而不是GET(常规链接/按钮)进行页面到页面导航,并单击缓存页面上的这样的命令链接/按钮,那么这将依次与ViewExpiredException
失败。要在JSF 2.0中注销后触发重定向,请将
<
redirect />
添加到相关的<
navigation-case>
(如果有),或将?faces-redirect=true
添加到outcome
值。<
h:commandButton value="https://www.songbingjia.com/android/Logout" action="logout?faces-redirect=true" />
要么
public String logout() {
// ...
return "index?faces-redirect=true";
}
要指示浏览器不缓存动态JSF页面,请创建
Filter
,该FacesServlet
映射在@WebFilter(servletNames={"Faces Servlet"}) // Must match <
servlet-name>
of your FacesServlet.
public class NoCacheFilter implements Filter {@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
// HTTP 1.1.
res.setHeader("Pragma", "no-cache");
// HTTP 1.0.
res.setDateHeader("Expires", 0);
// Proxies.
}chain.doFilter(request, response);
}// ...
}
的servlet名称上,并添加所需的响应头以禁用浏览器缓存。例如。ViewExpiredException
在页面刷新时避免ViewExpiredException为了在状态保存设置为
server
时刷新当前页面时避免使用ViewExpiredException
,您不仅需要确保通过GET(常规链接/按钮)执行页面到页面导航,而且还需要确保您专门使用ajax提交表单。如果您同时提交表单(非ajax),那么您最好使视图无状态(请参阅后面的部分),或者在POST后发送重定向(请参阅上一节)。在页面刷新上使用com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews是默认配置,这是一种非常罕见的情况。只有当JSF将在会话中存储的视图数量限制被命中时,才会发生这种情况。因此,只有当您手动将限制方式设置得太低,或者您在“后台”中不断创建新视图时才会发生这种情况(例如,在同一页面中执行错误的ajax轮询或执行错误的404同一页面的损坏图像上的错误页面)。有关该限制的详细信息,另请参阅our JSF wiki page。另一个原因是在运行时类路径中有重复的JSF库相互冲突。
ViewExpiredException
概述了安装JSF的正确过程。处理ViewExpiredException如果你想在一个任意页面上的POST操作后处理一个不可避免的
error-page
,当你在另一个选项卡/窗口中注销时已经在某个浏览器选项卡/窗口中打开了,那么你想为此指定一个web.xml
<
error-page>
<
exception-type>
javax.faces.application.ViewExpiredException<
/exception-type>
<
location>
/WEB-INF/errorpages/expired.xhtml<
/location>
<
/error-page>
进入“你的会话超时”页面。例如。<
!DOCTYPE html>
<
html lang="en">
<
head>
<
title>
Session expired<
/title>
<
meta http-equiv="refresh" content="0;
url=#{request.contextPath}/login.xhtml" />
<
/head>
<
body>
<
h1>
Session expired<
/h1>
<
h3>
You will be redirected to login page<
/h3>
<
p>
<
a href="https://www.songbingjia.com/android/#{request.contextPath}/login.xhtml">
Click here if redirect didn't work or when you're impatient<
/a>
.<
/p>
<
/body>
<
/html>
如果您打算实际重定向到主页或登录页面,请在错误页面中使用元刷新标头。
0
【javax.faces.application.ViewExpiredException(无法恢复视图)】(
content
中的0
表示重定向之前的秒数,3
因此意味着“立即重定向”,您可以使用例如ExceptionHandler
让浏览器等待3秒重定向)请注意,在ajax请求期间处理异常需要特殊的Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request。另见OmniFaces
FullAjaxExceptionHandler
showcase page。你可以在<
error-code>
找到一个实例(这也包括非ajax请求)。另请注意,您的“常规”错误页面应映射到
500
的<
exception-type>
而不是java.lang.Exception
,例如java.lang.Throwable
。 ServletException
或ViewExpiredException
,否则包含在ViewExpiredException shown in java.lang.Throwable error-page in web.xml中的所有异常,例如<
error-page>
<
error-code>
500<
/error-code>
<
location>
/WEB-INF/errorpages/general.xhtml<
/location>
<
/error-page>
,仍将在一般错误页面中结束。另见transient
。<
f:view>
无国籍观点一种完全不同的替代方法是在无状态模式下运行JSF视图。这样就不会保存任何JSF状态,并且视图永远不会过期,而只是在每次请求时从头开始重建。您可以通过将
true
的<
f:view transient="true">
<
/f:view>
属性设置为javax.faces.ViewState
来打开无状态视图:"stateless"
这样,introduced隐藏字段将在Mojarra中获得
rendered
的固定值(此时尚未检查MyFaces)。请注意,此功能在Mojarra 2.1.19和2.2.0中是推荐阅读
- 项目已包含具有此名称的模块 - Android Studio
- 使用android AudioRecord获得32位样本吗()
- 使用从Jackson创建的对象在Android上使用OrmLite保存子集合
- Doctrine异常 - [DoctrineORMMappingMappingException]
- 如何更改UWP app文件夹名称或路径()
- 是否可以在没有管理员权限的情况下安装.appxbundle(UWP / XAML应用程序)()
- PrimaryLanguageOverride在发布appxbundle中不起作用
- 如何在android中的接口回调内部传输数据
- 在ASP.NET MVC App中初始化AutoMapper v6时出错