没有@ViewScoped的JSF

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了没有@ViewScoped的JSF相关的知识,希望对你有一定的参考价值。

我已经使用JSF多年了,在下一个项目中,我们旨在使Web层尽可能地无状态。我正在探索的一种可能性是删除@ViewScoped豆,改为使用@RequestScoped(根据需要再加上一个或两个@SessionScoped豆)。对于带有AJAX,数据表和条件渲染的复杂页面,这很麻烦。我的问题是:JSF(和PrimeFaces)在无状态Web Bean上的性能如何?这是我应该继续探索的东西,还是@ViewScope现在如此基础以至于不值得付出努力?

[我很高兴在撰写此问题时以“基于主要观点”的形式将其关闭,但是我希望并非如此,我对@ViewScope解决的特定问题以及我所采用的历史解决方法感兴趣不得不通过忽略@ViewScoped重新引入。

答案

JSF(和PrimeFaces)如何与无状态Web Bean配合使用?

在技术上是可行的。

[JSF主要使用视图状态来跟踪UIInputUICommand组件的“禁用”,“只读”和“渲染”属性以及“提交的值”,“本地值”和“已验证?” EditableValueHolder组件的状态(由EditableValueHolder等实现)。

对于“ disabled”,“ readonly”和“ rendered”属性,如果它们表示一个EL表达式,那么JSF将在处理表单提交请求时重新检查它。下面是一个基本示例:

UIInput

<h:form>
    <h:commandButton value="toggle" action="#{bean.toggle}">
        <f:ajax render="panel" />
    </h:commandButton>
    <h:panelGroup id="panel">
        <h:commandButton value="submit" action="#{bean.submit}" rendered="#{bean.toggled}">
            <f:ajax />
        </h:commandButton>
    </h:panelGroup>
</h:form>

首先单击“切换”按钮,然后单击“提交”按钮。如果是视图作用域的bean,它将很好地工作。但是,如果在此处用@Named @ViewScoped public class Bean implements Serializable { private static final long serialVersionUID = 1L; private boolean toggled; public void toggle() { this.toggled = !toggled; } public void submit() { System.out.println("Submitted"); } public boolean isToggled() { return toggled; } } 替换@ViewScoped,则它将失败,因为在回发请求期间JSF需要解码“提交”按钮时,@RequestScoped默认返回到toggled,因此其[ C0]属性将评估false,最终JSF不会将操作事件排队。

在这种情况下,您需要确保自己在请求范围的Bean的(后)构造过程中将属性预先初始化为期望值。一种方法是在ajax更新的组件中为此使用隐藏的输入字段。这是调整后的示例:

rendered

false

注意:<h:form> <h:commandButton value="toggle" action="#{bean.toggle}"> <f:ajax render="panel" /> </h:commandButton> <h:panelGroup id="panel"> <input type="hidden" name="toggled" value="#{bean.toggled}" /> <h:commandButton value="submit" action="#{bean.submit}" rendered="#{bean.toggled}"> <f:ajax /> </h:commandButton> </h:panelGroup> </h:form> 不幸地将不起作用,因为它仅更新模型值之后动作事件要排队。即使没有@Named @RequestScoped public class Bean { @Inject @ManagedProperty("#{param.toggled}") private boolean toggled; public void toggle() { this.toggled = !toggled; } public void submit() { System.out.println("Submitted"); } public boolean isToggled() { return toggled; } } 这顺便带给了我关于OmniFaces的新<h:inputHidden>的想法。

有了这些更改,它将可以正常工作。

但是,由于最初在视图范围内的状态(immediate="true"属性)现在已成为请求参数,因此它已完全暴露给世界,因此也容易受到黑客的篡改。希望先调用“提交”按钮而无需先调用“切换”按钮的黑客现在可以简单地手动添加请求参数<o:inputHidden>。是否令人满意取决于您的应用程序的业务需求,但是比通常情况下,完全不希望如此。

这是JSF试图通过提供将这些敏感属性放入toggled bean中的可能性来保护您的方法。


这对于带有AJAX,数据表和条件渲染的复杂页面来说是麻烦的

是正确的,但在技术上仍不可行。您只需要通过手动填充的隐藏输入字段手动携带分页,排序和过滤的状态,如上所示。 toggled=true支持将这些状态绑定到Bean属性。例如:

@ViewScoped

您可以按照前面的说明将它们复制到<p:dataTable>字段中(确保已被<p:dataTable ... first="#{bean.first}" sortField="#{bean.sortField}" sortOrder="#{bean.sortOrder}" filterBy="#{bean.filterBy}"> ... </p:dataTable> 覆盖!),最后通过<input type="hidden">和/或<p:ajax update>抓取它们。

实际上,您是通过这种方式从头开始通过@ManagedProperty隐藏输入字段与@PostConstruct bean的结合来重塑当前已经完成的工作。那么,为什么不立即使用它呢? :)

如果您最关心的是内存使用情况,那么您需要以如下方式精心设计bean:将视图范围状态存储在javax.faces.ViewState bean中,并且将请求范围限定为[only]状态存储在@ViewScoped bean中。例如,将数据模型放入请求范围的Bean中,将分页/排序/过滤的状态放入视图范围的Bean中是完全可以的。您可能还需要考虑@ViewScoped,因为当页面被卸载时,它立即破坏视图状态和物理bean。就是说,考虑到这个问题,我已经@RequestScoped验证并改进了OmniFaces @ViewScoped库,以确保它也完全支持@ViewScoped的无状态视图以及新的集成测试。 OptimusFaces的优点是,您不再需要手动担心会出现分页/分类/过滤状态。 OptimusFaces会为您担心。另请参见:

just a few hours ago

  • <f:view transient="true">
  • Why JSF saves the state of UI components on server?
  • 以上是关于没有@ViewScoped的JSF的主要内容,如果未能解决你的问题,请参考以下文章

    JSF 2.x @ViewScoped 托管 bean 线程安全吗?

    JSF 2.2 @ViewScoped 绑定错误?

    JSF 2.2 ViewScoped Bean 被多次创建

    在 JSF 中如何以及何时销毁 @ViewScoped bean?

    JSF ViewScoped bean 在所有 ajax 请求中的唯一 ID?

    即使在刷新页面后,Firefox 也会在 JSF-Viewscoped-Managed-Bean 中保留数组的内容