24

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

似乎组件树状态应该只在单个请求期间作为临时数据结构需要,以帮助处理请求。它应该为每个请求从头开始重建。使用 JSF 2.0 部分状态保存使情况变得更好,因为只保存了表单数据,但我不明白为什么从前一个请求中获取表单数据是有用的。

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

4

2 回答 2

21

添加到先前的答案,自 JSF 2.0 以来partial state saving,默认使用所谓的东西。

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 中)也可能会有所帮助。

于 2011-10-31T17:45:49.520 回答
20

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

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

也可以看看:

于 2011-09-08T14:49:05.093 回答