Primefaces 8.0, совместимый с Dynami c Model и Columns - PullRequest
1 голос
/ 29 мая 2020

У меня есть таблица данных primefaces, которая отображает данные из нескольких таблиц базы данных. Список выбора позволяет пользователю выбрать для отображения указанную таблицу базы данных c. Он работает так, как ожидалось, за исключением случаев, когда используется возможность фильтрации dataTable. Например, когда пользователь выбирает «DEPT» из списка выбора, dataTable отображается с данными из таблицы DEPT. Пользователь может обычно выбирать другие таблицы. Однако, если после фильтрации пользователь выбирает другую таблицу с именем «EMP», dataTable не может быть отображен за следующим исключением:

javax.el.PropertyNotFoundException: The class 'example.dto.Dept' does not have the property 'firstName'.
at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:576)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:291)
at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:156)

Вот файл .x html:

<h:form prependId="false">

    <p:outputLabel for="selTbl" value="Select a table:" />
    <p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
        completeMethod="#{mainBean.filterAuditTables}" cache="true" dropdown="true" effect="fade"
        minQueryLength="3" forceSelection="true" size="35" style="margin-left: 10px;">
        <p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}" process="@this" update="@form" />
    </p:autoComplete>

    <p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
        filteredValue="#{mainBean.filteredData}" resizableColumns="true" resizeMode="expand"
        sortMode="multiple">

        <f:facet name="header">
            <h:outputText value="#{mainBean.selectedTable}" />
        </f:facet>

        <p:columns value="#{mainBean.tableColumns}" var="col" sortBy="#{row[col.property]}"
            filterBy="#{row[col.property]}" filterMatchMode="contains">
            <f:facet name="header">
                <h:outputText value="#{col.header}" />
            </f:facet>
            <h:outputText value="#{row[col.property]}" />
        </p:columns>

    </p:dataTable>

</h:form>

MainBean. java:

@Named
@ViewScoped
public class MainBean implements Serializable {

    private static final long serialVersionUID = 1L;

    // these are used for the audited table selection list
    private List<String> auditedTables;
    private String selectedTable;

    // these are used in the table that displays the audit data
    private List<ColumnModel> tableColumns;
    private List<Auditable> data;
    private List<Auditable> filteredData;

    @Inject
    private AudviewService audviewService;

    @PostConstruct
    public void init() {
        auditedTables = audviewService.getAuditedTables();
    }

    public List<String> filterAuditTables(String query) {
        return auditedTables
                .stream()
                .filter(t -> t.contains(query.toUpperCase()))
                .collect(Collectors.toList());
    }

    public void onTableSelect(SelectEvent<String> event) {
        retrieveTableData();
    }

    public void retrieveTableData() {

        List<String> columns = audviewService.listTableColumns(selectedTable);

        // initialize columns for <p:dataTable>
        tableColumns = new ArrayList<ColumnModel>();
        for (String col : columns) {
            tableColumns.add(new ColumnModel(col, AudviewUtil.columnToProperty(col)));
        }

        // retrieve data for the selected table
        data = audviewService.getTableData(selectedTable);
    }

    /* getters and setters */
}

Обратите внимание, что Auditable - это интерфейс, реализованный Dept. java и Emp. java.

1 Ответ

1 голос
/ 30 мая 2020

Как вы заметили, проблема заключается в переключении с отфильтрованной или отсортированной таблицы данных на другую, если отфильтрованный или отсортированный столбец является полем, которого нет в новом выбранном классе. Простым решением было бы переместить все необходимые поля в суперкласс Auditable.

Другой подход состоит в разделении сброса и обновления данных в два этапа, здесь возможное решение (для целей тестирования я заменяю ваш сервис на stati c, поэтому при адаптации моего решения к вашему коду могут возникнуть ошибки):

x html

<h:form id="formTbl" prependId="false">

    <p:outputLabel for="selTbl" value="Select a table:" />
    <p:autoComplete id="selTbl" value="#{mainBean.selectedTable}"
        completeMethod="#{mainBean.filterAuditTables}" cache="true"
        dropdown="true" effect="fade" minQueryLength="3"
        forceSelection="true" size="35" style="margin-left: 10px;">
        <p:ajax event="itemSelect" listener="#{mainBean.onTableSelect}"
            process="@this" onstart="PF('vtWidget').clearFilters()" />
    </p:autoComplete>
    <p:remoteCommand name="btn" process="@this" update="audTblData" />

    <p:dataTable id="audTblData" value="#{mainBean.data}" var="row"
        filteredValue="#{mainBean.filteredData}" resizableColumns="true"
        resizeMode="expand" sortMode="multiple" widgetVar="vtWidget">

        <f:facet name="header">
            <h:outputText value="#{mainBean.selectedTable}" />
        </f:facet>

        <p:columns value="#{mainBean.tableColumns}" var="col"
            sortBy="#{row[col.property]}" filterBy="#{row[col.property]}"
            filterMatchMode="contains">
            <f:facet name="header">
                <h:outputText value="#{col.header}" />
            </f:facet>
            <h:outputText value="#{row[col.property]}" />
        </p:columns>

    </p:dataTable>

</h:form>

java

public void retrieveTableData() {

    List<String> columns = listTableColumns(selectedTable);

    // initialize columns for <p:dataTable>
    tableColumns = new ArrayList<ColumnModel>();
    for (String col : columns) {
        tableColumns.add(new ColumnModel(col + " header", col));
    }

    // retrieve data for the selected table
    data = getData(selectedTable);
    DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("formTbl:audTblData");
    if (dataTable != null) {
        dataTable.reset();
    }
    PrimeFaces.current().executeScript("btn()");
}

Обратите внимание, если вам также нужно управлять разбивкой на страницы.

...