2

我在一个项目中,我会写很多这样的页面,所以我想使用最有效的(编写)编码模式。

背景:过去我使用 CODI 的 @ViewAccessScoped 来保存请求之间的状态,最近我开始使用 Flash 范围对象来保存状态。我不能使用 JSF @ViewScoped,因为我使用 CDI,而且它们不能很好地配合使用。所以我想看看我是否可以只用@RequestScoped 支持bean 来做到这一点。

页面是这样设计的(p 命名空间是 Primefaces):

            <f:metadata>
                <f:viewParam name="ID" value="#{backing.id}" />
            </f:metadata>

                ....

            <h1>Edit Object Page</h1>

            <h:form id="formObj" rendered="#{backing.accessOK}">

                <p:panelGrid columns="2">

                    <h:outputLabel value="Field #1:"/>
                    <p:inputText value="#{backing.record.field1}" />

                          (more input fields)

                    <h:outputLabel value="Action:" />
                    <h:panelGroup>
                        <p:commandButton value="Save"
                                         action="#{backing.save}"
                                         />
                        <p:commandButton value="Cancel" action="backing.cancel" />
                    </h:panelGroup>

                </p:panelGrid>
                <p:messages showDetail="true" showSummary="true" />

            </h:form>

如果页面被请求,方法accessOK()有能力阻止h:form被呈现。相反,p:messages会与accessOK()方法需要设置的任何FacesMessage (s)一起显示。

bean backing的模式如下所示:

@Named
@RequestScoped
public class Backing {

    private long id;
    private SomeJPAEntity record;
    private Boolean accessOK;

    public long getId() { return id; }

    public void setId(long value) { id = value; }

    public boolean accessOK() {
        if (accessOK != null) return accessOK;

        if (getRecord() == null) {
             // add a FacesMessage that explains the record
             // does not exist
             return accessOK = false;  // note single =
        }

        // do any other access checks, such as write permissions

        return accessOK = true;
    }

    public SomeJPAEntity getRecord() {
        if (record != null) return record;

        if (getId() > 0) record = // get the record from DB
        else record = new SomeJPAEntity();

        return record;
    }

    public String execute() {

         if (!accessOK()) return null;   // bad edit

         // do other integrity checks here.  If fail, set FacesMessages
         // and return null;

         if (getId() > 0) // merge the record back into the data base
         else  // persist the record

    }

}

这是这个模型的问题所在。单击 Save 按钮时,会构建一个新的Backing实例,然后在调用setID() setter之前,会多次调用getRecord() getter 。因此getRecord()中的逻辑中断,因为它不能依赖id属性在调用时有效。

当这是一个@ViewAccessScoped(或ViewScoped)支持 bean 时,当使用commandButton处理表单时, idrecord属性都已设置。或者,您可以将这些属性保存在闪存中,但这有其自身的问题,我想避免。

那么有没有办法让这个编程模型在规范中工作呢?

更新:

我有一个变通方法,凭经验允许它在不诉诸闪存或视图范围变体的情况下工作。如上所述,在处理表单时,在第一次调用setId( )之前,会多次调用getRecord( ) 。然后最后调用save()方法。

我所做的是修改setId()如下:

public void setId(long value) {
  id = value;
  record = null;
}

这迫使getRecord()重新计算(即获取/构建)属性记录,然后后续调用工作。具体来说,使用正确初始化的对象(包括记录实体的内容)进入save()方法。我不知道之前对getRecord()的所有调用是为了什么。

在这一点上,我也不知道我可以依赖的是,在设置getId()之后,写入记录实体的所有值是否都会从UIinput组件传输。如果是这样,那么我可以使用这种模式。这是由规范控制还是只是靠运气?

有什么意见或建议吗?

4

2 回答 2

2

我认为你可以对 CODI(或者更确切地说是即将到来的 DeltaSpike)感到安全,我在 Tomcat 中都使用得很好。他们将支持几乎所有。

Deltaspike 现在正在开发 JSF 模块,并且有很多活动,当该 brew 完成时,我相信您会对此感到满意。deltaspike 的每个模块都可以单独生产,尽管该项目仍在孵化中。

现在对于您的实际问题,我无法提出您尚未提出的任何建议。

但我想知道,这是其中一个可能需要绑定的案例f:viewParam吗?我不确定,因为我几乎从未使用过绑定。

于 2012-10-08T20:35:34.387 回答
1

CODI 和 DeltaSpike 为 CDI 启用 @ViewScoped。JSF < 2.2 中的 Flash-Scope 完全被多个窗口破坏。我认为摆脱 CODI 的唯一原因是迁移到 DeltaSpike,在它准备好之前,您可以同时使用两者。

于 2012-10-09T22:17:29.147 回答