添加到先前的答案,自 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 中)也可能会有所帮助。