4

JSF-PrimeFaces / JPAスタックで単一ページのマスター詳細ビューを実装するための良いパターンは何か知りたい. Web 上の資料やチュートリアルのほとんどは、ビューごとに 1 つのテーブルというかなり些細なパターンについてのみ議論しているようです。

しかし、データベースにCUSTOMERテーブルとORDERテーブルがあり、上半分に顧客 (たとえばp:datatableとして) を表示できる1 つのxhtmlページと、下半分に現在選択されている顧客の注文があることなどに興味があります。 (再びp:datatableとして)。JSF/PrimeFaces/バッキング Bean とファサード/エンティティ/JPA コードを最適に編成して、コードを最大限に再利用して一般的に適用可能な方法で上記を達成する方法は明確ではありません。例えば

  1. xhtmlビュー全体に対して 1 つのバッキング Bean を定義するか、ビューの各コンポーネント (マスター/詳細) に対して 1 つずつ、2 つのバッキング Bean を定義する必要がありますか?
  2. パターンを (同じレベルで) 複数の詳細テーブルに一般化できますか? たとえば、上半分にCUSTOMERテーブルのビューがあり、下半分にタブ付きビューがあり、それぞれORDERおよびPAYMENT詳細テーブルの 2 つのビューで構成されています (どちらもテーブルCUSTOMERとの N-1 関係にあります)。
  3. パターンを複数の詳細レベルに一般化できますか (たとえば、同じページにCUSTOMERINVOICE、およびINVOICELINEテーブルのビューを含めることができます)。
  4. 提案されたパターンが変更にどれだけ簡単に対応できるか。たとえば、編集可能なデータテーブルを使用すると、顧客の詳細を変更し、注文を削除して、変更のコミットボタンを使用して両方の変更を一度に完了することができます。
4

1 に答える 1

4

最近のトレーニング コースでは、次の概念の証明を構築します。マスター (部門) テーブルと詳細 (従業員) テーブルの 2 つのテーブルを含む単一のビューを作成しました。ビューは、cdi イベントを使用して通信する 2 つのコントローラー Bean によってサポートされていました。プルーフオブコンセプトは jee6-container (glassfish 3.1.1) にデプロイされました。

部門の行をクリックするたびに、ajax-Listener が cdi-Event を起動して、detail-Controller を更新し、その代わりに詳細テーブルを更新するという考え方です。このパターンは、複数のディテール テーブルまたは複数のマスター/ディテール/ディテール レベルに拡張できます。

エンティティを編集するには、テーブルの各行にエディター ボタンを追加するなどして、エディター ダイアログを開くことをお勧めします。新しい詳細を追加するには、テーブルのフッターで add-Actions を使用し、新しいエンティティでエディター ダイアログを開きます。エディター ダイアログの「OK」で、新しいエンティティで cdi イベントを再度発生させ、依存する詳細テーブルを更新します。作業を保存するには、マスター エンティティを保存する単一の「コミット」ボタンを使用します。トレーニングでは、適切に定義されたエンティティで jpa を使用し、@OneToMany 関係で orphanRemoval=true 属性を使用して esp を使用しました。

ビュー (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...

}
于 2015-10-09T09:56:02.187 に答える