JSF / PrimeFaces中的单页主 - 细节

时间:2012-10-23 13:44:58

标签: jsf jpa primefaces master-detail

我很想知道在 JSF-PrimeFaces / JPA 堆栈中实现单页主 - 明细视图的一些好模式。似乎网络上的大多数材料和教程只讨论每个视图模式相当简单的一个表。

但我对数据库中的 CUSTOMER ORDER 表以及一个 xhtml 页面感兴趣,您可以在其中查看客户(例如,上半部分为 p:datatable ),下半部分为当前所选客户的订单(再次为 p:datatable )。我不清楚如何最好地组织JSF / PrimeFaces / backing beans和facade / entities / JPA代码,以最普遍适用的方式实现上述代码,并最大限度地重用代码。 E.g。

  1. 我应该为整个 xhtml 视图定义一个支持bean,还是为视图的每个组件(主/详细信息)定义一个支持bean?
  2. 可以将模式推广到多个细节表(在同一级别)吗?例如。查看上半部分的 CUSTOMER 表格和下半部分的标签视图,其中包含订单付款的两个视图细分表(与表 CUSTOMER
  3. 的N-1关系)
  4. 可以将模式推广到多个细节层次(例如,在同一页面上显示 CUSTOMER INVOICE 的视图INVOICELINE 表。
  5. 建议的模式也很容易适应修改。例如。使用可编辑的数据表,可以使用提交更改按钮一次性更改客户详细信息并删除订单并最终完成两项更改。

1 个答案:

答案 0 :(得分:2)

对于最近的培训课程,我们构建以下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-event以根据详细信息表进行更新。要保存您的工作,请使用单个" commit" -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...

}