我很想知道在JSF-PrimeFaces / JPA堆栈中实现单页主 – 详细视图的一些好模式.似乎网络上的大多数材料和教程只讨论每个视图模式相当简单的一个表.
但我对数据库中有CUSTOMER和ORDER表以及一个xhtml页面感兴趣,你可以在上半部分查看客户(例如ap:datatable)和下半部分当前选定客户的订单(再次作为ap:datatable).我不清楚如何最好地组织JSF / PrimeFaces / backing beans和facade / entities / JPA代码,以最普遍适用的方式实现上述代码,并最大限度地重用代码.例如.
>我应该为整个xhtml视图定义一个支持bean还是两个支持bean,一个用于视图的每个组件(主/详细信息)?
>可以将模式推广到多个细节表(在同一级别)吗?例如.查看上半部分的CUSTOMER表和下半部分的选项卡视图,分别包含ORDER和PAYMENT详细信息表的两个视图(与表CUSTOMER的N-1关系)
>可以将模式推广到多个细节级别(例如,在同一页面上有一个CUSTOMER,INVOICE和INVOICELINE表的视图.
>提议的模式也很容易适应修改.例如.使用可编辑的数据表,可以使用提交更改按钮一次性更改客户详细信息并删除订单并最终确定两个更改.
最佳答案 对于最近的培训课程,我们构建以下proofOfConcept.我们创建了一个包含两个表的视图,一个是master(departements)和一个detail(employees)表.该视图由两个使用cdi事件进行通信的控制器bean支持.将proofOfConcept部署到jee6-container(glassfish 3.1.1).
这个想法是每当你点击一个部门行时,ajax-Listener就会激活一个cdi-Event来更新detail-Controller,然后更新详细信息表.此模式可以扩展到多个详细信息表或多个主 – 详细信息级别.
为了编辑您的entites,我建议打开一个编辑器对话框,例如在表格的每一行添加一个编辑按钮.要添加新的详细信息,请在表的页脚中使用add-Actions,然后使用新实体打开编辑器对话框.在编辑器中的“ok” – 对话框中,您再次使用新实体触发cdi事件,以根据详细信息表进行更新.要保存您的工作,请使用单个“提交”-Button,它会保存master-Entity.在训练中,我们使用jpa和正确定义的实体,尤其是使用@OneToMany关系中的orphanRemoval = true属性.
视图(scott.xhtml):
<p:panel id="deptPanel" header="Departements">
<p:dataTable id="deptTable" var="dept" value="#{deptUiController.departements}"
selectionMode="single" rowKey="#{dept.id}">
<p:ajax event="rowSelect" listener="#{deptUiController.onRowSelect}" update="@form"/>
<p:column headerText="Name">
<h:outputText id="name" value="#{dept.dname}"/>
</p:column>
<p:column headerText="Location">
<h:outputText id="loc" value="#{dept.loc}"/>
</p:column>
<p:column headerText="# of Emps">
<h:outputText id="size" value="#{dept.emps.size()}"/>
</p:column>
</p:dataTable>
</p:panel>
<p:panel id="empPanel" header="Employees in departement #{deptUiController.currentDept.dname}">
<p:dataTable id="empTable" var="emp" value="#{empUiController.employees}">
<p:column headerText="Name">
<h:outputText id="name" value="#{emp.ename}"/>
</p:column>
<p:column headerText="Job">
<h:outputText id="job" value="#{emp.job}"/>
</p:column>
<p:column headerText="Hiredate">
<h:outputFormat id="hiredate" value="{0,date,dd.MM.yyyy}">
<f:param value="#{emp.hiredate}"/>
</h:outputFormat>
</p:column>
</p:dataTable>
</p:panel>
主控制器:
@Named
@SessionScoped
public class DeptUiController implements Serializable {
private boolean initialized = false;
@EJB
private ScottCRUD crudEJB;
private List<Departement> departements;
private Departement currentDept;
public void populateData() {
if ( !initialized ) {
departements = crudEJB.findAllDepartements();
currentDept = departements.isEmpty() ? null : departements.get(0);
initialized = true;
fireDeptChange();
}
}
@Inject
private Event<Departement> deptChangeEvt;
private void fireDeptChange() {
deptChangeEvt.fire( currentDept );
}
public void onRowSelect(SelectEvent event) {
currentDept = (Departement) event.getObject();
fireDeptChange();
}
... getter, setter, more actions...
}
详细 – 控制器
@Named
@SessionScoped
public class EmpUiController implements Serializable {
private List<Employee> employees;
private Employee currentEmp;
private void populateData(Departement master) {
if ( master==null ) {
employees = Collections.emptyList();
} else {
employees = master.getEmps();
}
currentEmp = employees.isEmpty() ? null : employees.get(0);
}
public void observeDeptChanged( @Observes Departement master ) {
populateData( master );
}
... getter, setter, more actions...
}