为什么JSF保存组件树状态?

时间:2011-09-08 13:53:33

标签: jsf jsf-2 state-saving

托管bean状态和组件树状态之间似乎存在差异。您可以使用 @RequestScoped @SessionScoped 之类的注释来控制托管bean状态,但似乎您无法选择是否保存组件树状态(尽管您可以选择是保存在服务器还是客户端上)。

组织树状态似乎只应在单个请求的持续时间内作为临时数据结构来帮助处理请求。它应该从头开始为每个请求重建。使用JSF 2.0,部分状态保存使情况更好,因为只保存表单数据,但我不明白为什么甚至从前一个请求中形成数据是有用的。

如果您的应用程序仅使用请求范围托管bean,那么在请求之间保存组件树状态尤其没有意义。即使您的应用程序具有会话范围托管bean,我也会假设托管bean将保持状态,组件树仍然不需要在请求之间具有任何状态。

2 个答案:

答案 0 :(得分:21)

添加到上一个答案,因为默认情况下使用了名为partial state saving的JSF 2.0。

JSF(Facelets)中的默认视图描述语言在每次请求后从原始Facelet创建整个组件树,并从相应的标记属性初始化组件。然后它标志着国家。

然后将每个后续状态更改记为增量更改,这是实际保存的状态。它可能只是没有这样的变化,然后视图状态是空的(由于一个错误,状态从来没有真正空,但最近已经修复。有关详细信息,请参阅http://java.net/jira/browse/JAVASERVERFACES-2203

所以最重要的问题是,当这个非空时,这个状态实际上是什么?

正如BalusC已经指出的那样,这可能会对组件树进行动态更改。这些更改可以从支持bean启动,也可以从静态组件启动。执行此动态更改的组件类型的一个简单示例是一个表组件,它根据数据集中的实际列数创建子列组件。

视图状态的另一个重要用法是记住组件内部已更改但尚未推入模型的值。这可以是轻触开关组件中的开关,移动拨号组件中的滑块等。

一个特定的例子是viewParam组件,它记住了初始化它的请求参数(GET或非参与POST参数的查询字符串参数)。有关详细信息,请参阅此处:http://arjan-tijms.omnifaces.org/2011/07/stateless-vs-stateful-jsf-view.html

与状态组件有很强的关系,记住UI状态和失败的转换或验证。在这种情况下,UI组件将记住用户输入的值,并记住存在转换/验证错误。

该州的另一种用法是优化。一些组件计算他们认为计算成本昂贵的值并将它们存储在视图状态中。例如,UIInput组件在第一次回发后执行此操作:

private boolean validateEmptyFields(FacesContext ctx) {

    if (validateEmptyFields == null) {
        ExternalContext extCtx = ctx.getExternalContext();
        String val = extCtx.getInitParameter(VALIDATE_EMPTY_FIELDS_PARAM_NAME);

        if (val == null) {
            val = (String) extCtx.getApplicationMap().get(VALIDATE_EMPTY_FIELDS_PARAM_NAME);
        }
        if (val == null || "auto".equals(val)) {
            validateEmptyFields = isBeansValidationAvailable(ctx);
        } else {
            validateEmptyFields = Boolean.valueOf(val);
        }
    }

    return validateEmptyFields;

}

validateEmptyFields存储在视图状态后,因此无需在以下表单提交时再次计算。如果用户可以在重新计算或存储(众所周知的时空优化)之间做出选择,那将是一种改进。

国家的概念是从早期概念开始就困扰着Web应用程序开发的。每个人都希望进行基本上有状态的互动,但几乎没有人愿意处理或甚至考虑它。

JSF一直试图在这里提供答案,但它显然并不完美,而且还有改进的余地。 JSF坚持能够恢复视图状态(甚至是空视图状态)可能很麻烦,尽管在另一个答案中提到它确实提供了针对CSRF的隐式保护。 JSF 2.2将获得更明确的CSRF保护(参见例如http://arjan-tijms.omnifaces.org/p/jsf-22.html#869),所以我们将来可能会看到一些变化。

有一个选项可以关闭每个组件的状态并有一个简单的钩子来恢复状态,而框架不能(如在ASP.NET中)也可能有帮助。

答案 1 :(得分:17)

因为可以根据初始请求以编程方式更改组件树。无论何时必须处理表单数据,这都不一定可以在后续请求中重现。

此外,我的印象是您认为组件树也包含模型值。这不是真的。它仅保存对模型值(托管bean属性)的引用(通过表达式语言)。视图状态不复制/复制/包含模型状态。它只是一个纯UI组件树。也许你的困惑是基于此。请注意,术语“表单数据”将被解释为提交的值和模型值。

另见: