使用自定义过滤器对动态列进行Primeface

时间:2017-08-25 14:23:30

标签: jsf primefaces jsf-2 filter datatable

我需要渲染一个动态的,可过滤的表,其中包含大多数包含文本的列和一些包含布尔值的列。因此,我基本上想要结合这两个例子:

Filter& Dynamic Columns

所以我有da p:datatable,其中包含以下内容:

<p:columns
    value="#{cc.attrs.tableController.tableColumns}"
    var="column"
    headerText="#{column.header}"
    columnIndexVar="colIndex"
    style="#{column.style}"
    sortBy="#{item[column.property]}"
    filterBy="#{item[column.property]}"
    filterMatchMode="contains">

<f:facet name="filter">
    <p:inputText onkeyup="PF('#{cc.attrs.tableController.tableName}').filter()" style="width: 90%" rendered="#{!column.binary}"/>
    <p:selectOneButton onchange="PF('#{cc.attrs.tableController.tableName}').filter()" rendered="#{column.binary}">
        <f:selectItem itemLabel="All" itemValue=""/>
        <f:selectItem itemLabel="Y" itemValue="true"/>
        <f:selectItem itemLabel="N" itemValue="false"/>
    </p:selectOneButton>
</f:facet>

<h:outputText styleClass="#{item.markedForDeleteStyle}" value="#{item[column.property]}" rendered="#{!column.binary}"/>
<h:panelGroup layout="block" rendered="#{column.binary}"
              class="#{item.archivFlagBoolean ? 'ui-state-active' : 'ui-state-error'}"
              style="border:none!important; background:none!important; color:green!important; box-shadow: none!important;">
    <p:outputPanel layout="inline"
                   styleClass="ui-icon ui-icon-circle-check"
                   style="margin: auto"
                   rendered="#{item.archivFlagBoolean}"/>
    <p:outputPanel layout="inline"
                   styleClass="ui-icon ui-icon-circle-close"
                   style="margin: auto"
                   rendered="#{!item.archivFlagBoolean}"/>
</h:panelGroup>

问题来自方面的两个过滤器。只使用其中一个工作正常,但在过滤时使用两者都会导致此错误(是的,这是整个堆栈跟踪):

25.08.2017 15:45:47 com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback visit
SCHWERWIEGEND: java.lang.NullPointerException

我尝试了不同的版本,使用includes,c:if,甚至交换p:列

<c:forEach items="#{cc.attrs.tableController.tableColumns}" var="column">
    <p:column [...]>

但所有这些变种都导致了相同的错误。

有没有办法动态地将列附加到具有多个不同过滤器的表中?

修改

所以,我创建了一个包含3个文件的简约示例:

的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.logicbig.example</groupId>
<artifactId>data-table-filtering</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>6.1</version>
</dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-api</artifactId>
        <version>2.2.14</version>
    </dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-impl</artifactId>
        <version>2.2.14</version>
    </dependency>
    <dependency>
        <groupId>org.fluttercode.datafactory</groupId>
        <artifactId>datafactory</artifactId>
        <version>0.8</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.6.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <path>/</path>
            </configuration>
        </plugin>
    </plugins>
</build>
</project>

支持Bean:

import org.fluttercode.datafactory.impl.DataFactory;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@ManagedBean
@ViewScoped
public class RecordBean {
private List<Record> recordList = new ArrayList<>();

@PostConstruct
private void init() {
    DataFactory dataFactory = new DataFactory();
    for (int i = 1; i < 50; i++) {
        Record employee = new Record();
        employee.setId(i);
        employee.setName(dataFactory.getName());
        employee.setActive(new Random().nextBoolean());
        recordList.add(employee);
    }
}

public List<Record> getRecordList() {
    return recordList;
}

public List<ColumnModel> getColumns() {
    List<ColumnModel> columns = new ArrayList<>();
    columns.add(new ColumnModel("Id", "id"));
    columns.add(new ColumnModel("Name", "name"));
    columns.add(new ColumnModel("Active", "active", true));
    return columns;
}

public class Record {
    private long id;
    private String name;
    private boolean active;

    public long getId () {return id;}
    public void setId (long id) {this.id = id;}
    public String getName () {return name;}
    public void setName (String name) {this.name = name;}
    public boolean isActive() {return active;}
    public void setActive(boolean active) {this.active = active;}
}

public class ColumnModel {
    private String header;
    private String property;
    private boolean isBinary;
    public ColumnModel(String header, String property) {
        this(header, property, false);
    }
    public ColumnModel(String header, String property, boolean isBinary) {
        this.header = header;
        this.property = property;
        this.isBinary = isBinary;
    }

    public String getHeader() {return header;}
    public String getProperty() {return property;}
    public boolean isBinary() {return isBinary;}
}
}

和index.xhtml。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:p="http://primefaces.org/ui">

<h:head></h:head>
<h:body>
    <h:form>
        <p:dataTable var="record" value="#{recordBean.recordList}" widgetVar="recordWidget">
            <p:columns var="column" value="#{recordBean.columns}" headerText="#{column.header}" filterBy="#{record[column.property]}" filterMatchMode="contains">
                <f:facet name="filter">
                    <p:inputText onkeyup="PF('recordWidget').filter()" rendered="#{!column.binary}"/>
                    <p:selectOneButton onchange="PF('recordWidget').filter()" rendered="#{column.binary}">
                        <f:selectItem itemLabel="All" itemValue=""/>
                        <f:selectItem itemLabel="Y" itemValue="true"/>
                        <f:selectItem itemLabel="N" itemValue="false"/>
                    </p:selectOneButton>
                </f:facet>
                <h:outputText value="#{record[column.property]}" />
            </p:columns>
        </p:dataTable>
    </h:form>
</h:body>
</html>

同样的事情:任何一个过滤器都可以正常工作,但是当同时使用两个过滤器时我得到一个错误。构建此示例时,我注意到Catalina记录的错误与IntelliJ不同:

28-Aug-2017 11:05:43.576 INFORMATION [http-nio-8080-exec-7] com.sun.faces.context.PartialViewContextImpl.processPartial java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
 java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaDataWithoutColumnGroups(FilterFeature.java:402)
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaData(FilterFeature.java:293)
at org.primefaces.component.datatable.feature.FilterFeature.decode(FilterFeature.java:93)
at org.primefaces.component.datatable.DataTable.processValidators(DataTable.java:847)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at org.primefaces.component.api.UIData.visitTree(UIData.java:827)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

28-Aug-2017 11:05:43.577 WARNUNG [http-nio-8080-exec-7] com.sun.faces.lifecycle.ProcessValidationsPhase.execute java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
 javax.faces.FacesException: java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:273)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaDataWithoutColumnGroups(FilterFeature.java:402)
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaData(FilterFeature.java:293)
at org.primefaces.component.datatable.feature.FilterFeature.decode(FilterFeature.java:93)
at org.primefaces.component.datatable.DataTable.processValidators(DataTable.java:847)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at org.primefaces.component.api.UIData.visitTree(UIData.java:827)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
... 28 more

28-Aug-2017 11:05:43.577 SCHWERWIEGEND [http-nio-8080-exec-7] com.sun.faces.context.AjaxExceptionHandlerImpl.handlePartialResponseError java.lang.ClassCastException: javax.faces.component.UIPanel cannot be cast to javax.faces.component.ValueHolder
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaDataWithoutColumnGroups(FilterFeature.java:402)
at org.primefaces.component.datatable.feature.FilterFeature.populateFilterMetaData(FilterFeature.java:293)
at org.primefaces.component.datatable.feature.FilterFeature.decode(FilterFeature.java:93)
at org.primefaces.component.datatable.DataTable.processValidators(DataTable.java:847)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at org.primefaces.component.api.UIData.visitTree(UIData.java:827)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
at  org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

这有帮助吗?

1 个答案:

答案 0 :(得分:0)

对于PrimeFaces 7.0(及更低版本),这是不可能的。 forum post解释了详细信息,并提供了指向其他帖子和解决问题的请求的有用链接。

基本上,对于二进制列,您需要使用filterOptions的{​​{1}}属性(对于其他列,请使用空<p:columns>),并扩展类DataTableRenderer,如发布以避免filterOptions

一旦PrimeFaces #4846PrimeFaces #4847关闭,应该可以不修补PrimeFace JAR或覆盖渲染器类。