仅使用@RequestScoped编辑JPA实体的最佳JSF编码模式

时间:2012-10-07 21:36:16

标签: jsf-2 cdi

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

背景:过去我使用CODI的@ViewAccessScoped来保持请求之间的状态,最近我开始使用闪存范围对象来保存状态。我不能使用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:消息会显示 FaceOKMessage accessOK()方法需要设置。

bean 支持的模式如下所示:

@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

    }

}

这个模型出了什么问题。单击“保存”按钮后,将构建一个新的 Backing 实例,然后在之前有很多对 getRecord() getter 的调用>调用 setID() setter。因此 getRecord()中的逻辑会中断,因为它在调用时无法依赖 id 属性。

如果这是 @ViewAccessScoped (或 ViewScoped )支持bean,那么 id 记录使用 commandButton 处理表单时已设置属性。或者,您可以将这些属性保存在闪存存储中,但这有我想避免的问题。

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

更新:

我有一个解决方案,根据经验允许它无需使用flash或视图范围的变体即可工作。如上所述,处理表单时,在第一次调用 setId()之前,会有一些对 getRecord() 的调用。然后最后调用 save()方法。

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

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

这会强制 getRecord()重新计算(即获取/构建)属性记录,然后进行后续调用。具体而言,输入 save()方法,并正确初始化对象,包括记录实体的内容。我不知道先前对 getRecord()的所有调用是针对什么的。

此时我还不知道我可以依赖的是是否所有写入记录实体的值都将从 UIinput 组件设置 getId()之后。如果是这样,那么我可以使用这种模式。这是由规范控制还是运气好吗?

有任何意见或建议吗?

2 个答案:

答案 0 :(得分:2)

我认为你可以用CODI(或者更确切地说是DeltaSpike)感到安全。我已经很好地使用了Tomcat。他们几乎都支持所有人。

Deltaspike现在正在研究JSF模块,并且有很多活动,当这个酿造完成后,我相信你会对它感到满意。即使项目仍处于孵化阶段,deltaspike的每个模块都是单独生产的。

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

但是我想知道,这个案例中有一个人可能会关心对f:viewParam的约束吗?我不确定因为我几乎从未使用绑定。

答案 1 :(得分:1)

CODI和DeltaSpike为CDI启用@ViewScoped。 JSF中的Flash-Scope&lt; 2.2完全打破了多个窗口。我看到退出CODI的唯一原因是迁移到DeltaSpike,直到它准备就绪,你可以并行使用它们。