没有@ViewScoped的JSF [英] JSF without @ViewScoped

查看:120
本文介绍了没有@ViewScoped的JSF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been using JSF for many years and in the next project we're aiming to make the web-tier as stateless as possible. One possibility I'm exploring is removing @ViewScoped beans in favour of @RequestScoped (plus one or two @SessionScoped beans as required). This is proving troublesome for complex pages with AJAX, datatables and conditional rendering. My question is: how well does JSF (and PrimeFaces) work with stateless web beans? Is this something that I should continue to explore, or is @ViewScope now so fundamental that it's not worth the effort?

我很高兴在撰写此问题时将其封闭为主要基于意见",但是我希望不是,我对@ViewScope解决的特定问题以及什么历史性的解决方法感兴趣我必须通过忽略@ViewScoped重新引入.

I appreciate as I write this question that it might be be closed as 'primarily opinion based', however I'm hoping that it isn't, I'm interested in specific problems that @ViewScope solved and what historic workarounds I'd have to re-introduce by ignoring @ViewScoped.

推荐答案

JSF(和PrimeFaces)在无状态Web Bean中的运行情况如何?

从技术上讲是可能的.

JSF主要使用视图状态来跟踪禁用",只读"状态.和渲染"的UIInputUICommand组件的属性以及提交的值",本地值"和和有效吗?" EditableValueHolder 组件(由UIInput实施).

JSF uses the view state primarily to keep track of the "disabled", "readonly" and "rendered" attributes of the UIInput and UICommand components as well as the "submitted value", "local value" and "is valid?" states of the EditableValueHolder components (implemented by among others UIInput).

在禁用"的情况下,只读"和渲染"的属性,如果它们表示一个EL表达式,那么JSF将在处理表单提交请求时重新检查它.下面是一个基本示例:

In case of "disabled", "readonly" and "rendered" attributes, if these represent an EL expression, then JSF will re-check it during processing the form submit request. Below is a basic example:

<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>

@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;
    }
}

首先点击切换"按钮,按钮,然后点击提交"按钮.如果是视图作用域的bean,它将很好地工作.但是,如果您在此处用@RequestScoped替换@ViewScoped,则它将失败,因为在JSF需要解码提交"消息时,toggled默认返回到false.按钮在回发请求期间单击,因此其rendered属性将评估false,最终JSF不会将操作事件排队.

First click the "toggle" button and then the "submit" button. In case of a view scoped bean, it'll work just fine. If you however replace @ViewScoped by @RequestScoped here, then it'll fail, because toggled defaults back to false at the moment JSF needs to decode the "submit" button during the postback request, and so its rendered attribute will evaluate false and ultimately JSF won't queue the action event.

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

In such case, you need to make sure yourself that the property is preinitialized to the expected value during (post)construction of the request scoped bean. One way is to use hidden input fields for this within the ajax-updated component. Here's the adjusted example:

<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;
    }
}

注意:很遗憾,<h:inputHidden>将不起作用,因为它仅在将动作事件排队之后 才更新模型值.甚至没有在上面加上immediate="true". 这为我带来了为OmniFaces新建<o:inputHidden>的想法.

NOTE: a <h:inputHidden> will unfortunately not work as it updates the model value only after the action event is to be queued. Even not with a immediate="true" on it. This brings me by the way on the idea for a new <o:inputHidden> for OmniFaces.

有了这些更改,就可以正常工作.

With these changes, it'll work fine.

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

However, as the state which was originally view scoped (the toggled property) has now become a request parameter, it's fully exposed to the world and therefore also tamperable by hackers. Hackers wanting to invoke the "submit" button without invoking the "toggle" button first can now simply manually add a request parameter toggled=true. Whether that's desirable depends on the business requirements of your application, but more than often it's totally undesirable.

这是JSF试图通过提供将这些敏感属性放置在@ViewScoped bean中的可能性来保护您的能力.

This is what JSF is trying to protect you from by offering the possibility to put these sensitive properties in a @ViewScoped bean instead.

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

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

True, but still not technically impossible. You only have to manually carry around the paginated, sorted and filtered states via manually populated hidden input fields as demonstrated above. The <p:dataTable> supports binding these states to bean properties. For example:

<p:dataTable ...
    first="#{bean.first}"
    sortField="#{bean.sortField}"
    sortOrder="#{bean.sortOrder}"
    filterBy="#{bean.filterBy}">
    ...
</p:dataTable> 

您可以按照前面的说明将它们复制到<input type="hidden">字段中(确保已被<p:ajax update>覆盖!),最后通过@ManagedProperty和/或@PostConstruct进行抓取.

You can just copy them into <input type="hidden"> fields as demonstrated before (which you make sure are covered by <p:ajax update>!) and finally grab them via @ManagedProperty and/or the @PostConstruct.

实际上,您是通过这种方式从根本上重塑了javax.faces.ViewState隐藏输入字段与@ViewScoped Bean结合使用时当前已经完成的工作.那么,为什么不立即使用它呢? :)

In effects, you're this way basically reinventing the job currently already done by javax.faces.ViewState hidden input field in combination with @ViewScoped beans. So why not using it right away? :)

如果您最关心的是内存使用情况,那么您需要精心设计bean,以使 only (仅视图范围)存储在@ViewScoped bean中,而 :请求范围内的状态存储在@RequestScoped bean中.例如,将数据模型放在请求范围的Bean中,将分页/排序/过滤的状态放在视图范围的Bean中是完全可以的.您可能还需要考虑 OmniFaces @ViewScoped ,因为那样会立即破坏视图状态,并且页面卸载时的物理bean.

If your primary concern is the memory usage, then you need to carefully design your beans in such way that only the view scoped state is stored in a @ViewScoped bean and that only the request scoped state is stored in a @RequestScoped bean. For instance, it's perfectly fine to put the data model in the request scoped bean and the paginated/sorted/filtered state in the view scoped bean. You may also want to consider OmniFaces @ViewScoped instead as that immediately destroys the view state and the physical bean when the page is unloaded.

也就是说,考虑到这个问题,几小时前我 验证并改进了 OptimusFaces 库,以确保它也完全支持<f:view transient="true">的无状态视图,以及新的集成测试. OptimusFaces的优点是,您不再需要手动担心会出现分页/分类/过滤状态. OptimusFaces会为您担心.

That said, with this question in mind, I've just a few hours ago verified and improved the OptimusFaces library to ensure that it also fully supports stateless views with <f:view transient="true">, along with a new integration test. The advantage of OptimusFaces is among others that you don't anymore need to manually worry about carrying around the paginated/sorted/filtered state. OptimusFaces will worry about it for you.

  • Why JSF saves the state of UI components on server?
  • JSF: Mojarra vs. OmniFaces @ViewScoped: @PreDestroy called but bean can't be garbage collected
  • How to choose the right bean scope?
  • What is the usefulness of statelessness in JSF?

这篇关于没有@ViewScoped的JSF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆