jsf - com.sun.faces.numberOfViewsInSession 与 com.sun.faces.numberOfLogicalViews

标签 jsf jsf-2 viewstate mojarra viewexpiredexception

JSF 2 的 Mojarra 实现具有以下上下文参数:

  • com.sun.faces.numberOfViewsInSession(默认为 15)
  • com.sun.faces.numberOfLogicalViews(默认为 15)

它们有什么区别?文档并没有过多谈论这些。我的应用在某些页面上遇到了 ViewExpiredException 问题,但在我们将这些设置提高到(高得多)的值后,我们就不再遇到问题了。

我的应用程序是一款财务、表单密集、支持 ajax 的应用程序(某些屏幕有 50 多个输入,可以选择通过 AJAX 添加更多数据/输入)。

造成这种行为的原因是什么?我知道第一个参数定义了 session 中保留的“页面”数量,这可能对后退按钮有用,但触发 ViewExpiredException 的用例不使用后退按钮。第二个参数指的是什么?如果我停留在同一个屏幕上,但不断通过 AJAX 添加大量数据,这是否会导致页面需要大量逻辑 View ?

最佳答案

首先,Mojarra 实现无意中交换了这些上下文参数的含义。因此,如果您的印象是描述与字面上下文参数名称所暗示的完全相反,那么这确实是正确的。

<小时/>

com.sun.faces.numberOfLogicalViews

这基本上是基于 GET 请求的。每个 GET 请求都会在 session 中创建一个新 View 。

要进行试验,请将其值设置为 3,启动一个新的浏览器 session 并按顺序打开 4 个不同的浏览器选项卡(无论 URL 为何;可能相同,也可能不同),然后返回到第一个选项卡并在那里提交表格。您将获得ViewExpiredException ,因为该 View 已从 session 中 View 的 LRU(最近最少使用)映射中推出。如果您最多打开 3 个选项卡,则不会发生这种情况。

默认值为 15,这是现实世界中罕见的问题。如果您的网络应用程序确实设计为以这种方式使用(例如,邀请在多个选项卡中打开的社交/社区网站,例如讨论论坛或问答),那么您可以考虑使用客户端状态保存,而不是增加默认值。通过客户端状态保存,您将永远不会遇到此异常。另一种方法是使用 OmniFaces <o:enableRestorableView> 结合请求作用域 bean 和请求参数,或者 View 作用域 bean,它在(后)构造中检查是否需要恢复其自身状态。另一种选择是去 stateless with <f:view transient="true"> ,这样 View 就不再保存,但是您不能再使用 View 范围的 bean。

MyFaces 等效项是 org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION 默认为 20。

<小时/>

com.sun.faces.numberOfViewsInSession

这基本上是基于同步(非ajax!)POST 请求。每个同步 POST 请求都会创建一个新的逻辑 View 。它们都是基于物理 View 存储的,像这样 Map<PhysicalView, Map<LogicalView, ViewState>> 。因此,通过最多 15 个物理 View 和最多 15 个逻辑 View ,理论上您可以在 session 中拥有 15*15 = 225 个 View 。

要进行试验,请将其值设置为 3,使用同步表单打开 View ,提交 4 次,然后按浏览器的后退按钮 4 次,然后再次提交表单。您将获得ViewExpiredException ,因为该 View 已从逻辑 View 的 LRU(最近最少使用)映射中推出。如果您最多返回 3 次然后重新提交,则不会发生这种情况。

请注意,ajax 提交重用相同的逻辑 View (您可以通过查看 ajax 回发返回的完全相同的 javax.faces.ViewState 值来确认这一点)。无论如何,浏览器不支持后退按钮。浏览器的后退按钮只会让您返回到上一个同步请求,因此将所有这些 ajax 回发存储为 session 中的逻辑 View 是没有任何意义的。

由于默认值 15 以及当前仅使用 ajax 表单和禁用动态页面缓存的趋势,这是一个非常罕见的现实问题。正确设计的表单不应邀请您按浏览器的后退按钮。相反,他们应该在成功提交时重定向到目标 View ,而在失败时仅重新显示带有验证错误的相同表单。另请参阅提示 How to navigate in JSF? How to make URL reflect current page (and not previous one) 。此外,动态页面上的缓存经常被禁用,因此后退按钮基本上会给您一个全新的 View 。另请参阅Avoid back button on JSF web application 。如果您的应用程序也是如此,那么您可以安全地将值设置为 1。

MyFaces 最初没有相应的功能,并且也将其视为 session 中的物理 View 。在版本 2.0.6 中, org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION 出于类似的目的而引入,尽管具有不同的实现并且默认情况下处于禁用状态。

<小时/>

另请参阅:

关于jsf - com.sun.faces.numberOfViewsInSession 与 com.sun.faces.numberOfLogicalViews,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4105439/

相关文章:

asp.net - ascx 的 View 状态在回发之间丢失

forms - 仅验证表单的特定部分而不是整个表单

jsf - JSF 2 项目中 Tomcat 7 启动缓慢

java - JSF 2.0 注释不起作用

jsf - 如何评估 JSF 复合组件中的 MethodExpressions

asp.net - ASP.Net 中的 ViewState 加密

asp.net - 如何解码 View 状态

javascript - 如何将脚本库添加到 XPage 自定义 Java 控件

ajax - 使用 JSF 的 Servlet 过滤器

jsf-2 - 用户界面 :composition template ="<template from jar>"