我在一个项目中,我会写很多这样的页面,所以我想使用最有效的(编写)编码模式。
背景:过去我使用 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处理表单时, id和record属性都已设置。或者,您可以将这些属性保存在闪存中,但这有其自身的问题,我想避免。
那么有没有办法让这个编程模型在规范中工作呢?
更新:
我有一个变通方法,凭经验允许它在不诉诸闪存或视图范围变体的情况下工作。如上所述,在处理表单时,在第一次调用setId( )之前,会多次调用getRecord( ) 。然后最后调用save()方法。
我所做的是修改setId()如下:
public void setId(long value) {
id = value;
record = null;
}
这迫使getRecord()重新计算(即获取/构建)属性记录,然后后续调用工作。具体来说,使用正确初始化的对象(包括记录实体的内容)进入save()方法。我不知道之前对getRecord()的所有调用是为了什么。
在这一点上,我也不知道我可以依赖的是,在设置getId()之后,写入记录实体的所有值是否都会从UIinput组件传输。如果是这样,那么我可以使用这种模式。这是由规范控制还是只是靠运气?
有什么意见或建议吗?