使用OmniFaces o:validateMultiple验证p:dataTable或p:treeTable中的多个输入

问题描述 投票:1回答:1

我有一个看起来像这样的UI:

enter image description here

游戏中不能有重复的球衣号码,所以我想要该列中所有UIInput的验证器。

我立即想到使用OmniFaces的o:validateMultiple

但是,这似乎不起作用。通过单击按钮提交表单将导致:

22:30:20,917 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-7) java.lang.IllegalArgumentException: ValidateMultiple attribute 'components' must refer existing client IDs. Client ID ':score-input-form:home-box-score-table:0:jersey-nbr-input' cannot be found.
    at org.omnifaces.component.validator.ValidateMultipleFields.findInputComponent(ValidateMultipleFields.java:324)
    at org.omnifaces.component.validator.ValidateMultipleFields.collectComponents(ValidateMultipleFields.java:248)
    at org.omnifaces.component.validator.ValidateMultipleFields.validateComponents(ValidateMultipleFields.java:205)
    at org.omnifaces.component.validator.ValidatorFamily.processValidators(ValidatorFamily.java:68)
    at javax.faces.component.UIForm.processValidators(UIForm.java:269)
    at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:632)
    at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
    at javax.faces.component.UIForm.visitTree(UIForm.java:405)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1747)
    at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:424)
    at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:285)
    at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:65)
    at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:252)
    at org.omnifaces.context.OmniPartialViewContext.processPartial(OmniPartialViewContext.java:122)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1330)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:77)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:201)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:670)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:55)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
    at java.lang.Thread.run(Thread.java:748)

这是我的代码示例...

Bean:

@Named
@ViewScoped
public class DebugTableValidateMultipleManager implements Serializable
{
    private static final long serialVersionUID = 1L;

    private SimpleScore selectedEntity;

    private TreeNode rootNode;

    @PostConstruct
    public void init()
    {
        this.selectedEntity = new SimpleScore();

        List<SimplePlayerStat> playerStats = Arrays.asList( new SimplePlayerStat( "Michael Jordan", 23 ), new SimplePlayerStat( "Dirk Nowitzki", 41 ) );

        this.selectedEntity.setPlayerStats( playerStats );
    }

    public SimpleScore getSelectedEntity()
    {
        return selectedEntity;
    }

    public void setSelectedEntity( SimpleScore selectedEntity )
    {
        this.selectedEntity = selectedEntity;
    }

    public void save()
    {
        System.out.println( "Saving simple score: " + selectedEntity );

        FacesContext.getCurrentInstance().addMessage( "score-button-form:growl", new FacesMessage( "Score successfully saved." ) );
    }

    public TreeNode getRootNode()
    {
        // System.out.println( "------- getRootNode(): " + rootNode );

        if ( rootNode == null )
        {
            System.out.println( getClass().getSimpleName() + ": -------------------------------------- Selected score: " + selectedEntity );

            // init navigation tree
            rootNode = new DefaultTreeNode( selectedEntity, null );

            List<SimplePlayerStat> playerStats = selectedEntity.getPlayerStats();

            for ( SimplePlayerStat playerStat : playerStats )
            {
                // player stats: jersey nbr, starter, DNP
                TreeNode playerStatNode = new DefaultTreeNode( SimplePlayerStat.class.getSimpleName(), playerStat, rootNode );
                playerStatNode.setExpanded( true );
            }
        }

        return rootNode;
    }

    public void setRootNode( TreeNode rootNode )
    {
        this.rootNode = rootNode;
    }

    // validation

    public void validateJerseyNbrs( FacesContext context, List<UIInput> components, List<Object> values )
    {
        // get home or away score entity
        SimpleScore score = selectedEntity;

        List<Integer> jerseyNbrs = score.getPlayerStats().stream().map( SimplePlayerStat::getJerseyNbr ).collect( Collectors.toList() );

        // determine frequencies of jersey nbrs
        Map<Integer, Long> frequencies = jerseyNbrs.stream().collect( Collectors.groupingBy( j -> j, Collectors.counting() ) );

        System.out.println( "Frequencies:\n" + frequencies );

//        if ( players.contains( player ) )
        {
            throw new ValidatorException( FacesMsgUtils.newErrorMessage( "There are " + frequencies + " of jersey numbers in this!" ) );
        }
    }

    public String getValidatorIds()
    {
        IntStream indices = IntStream.range( 0, selectedEntity.getPlayerStats().size() );

        List<String> ids = indices.mapToObj( id -> ":score-input-form:home-box-score-table:" + id + ":jersey-nbr-input" ).collect( Collectors.toList() );

        String idString = ids.stream().collect( Collectors.joining( " " ) );

        System.out.println( "Validator IDs: " + idString );

        return idString;
    }

    public class SimpleScore implements Serializable
    {
        private static final long serialVersionUID = 1L;

        private List<SimplePlayerStat> playerStats;

        public List<SimplePlayerStat> getPlayerStats()
        {
            return playerStats;
        }

        public void setPlayerStats( List<SimplePlayerStat> playerStats )
        {
            this.playerStats = playerStats;
        }
    }

    public class SimplePlayerStat implements Serializable
    {
        private static final long serialVersionUID = 1L;

        private String name;
        private Integer jerseyNbr;

        public SimplePlayerStat( String name, Integer jerseyNbr )
        {
            this.name = name;
            this.jerseyNbr = jerseyNbr;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public Integer getJerseyNbr()
        {
            return jerseyNbr;
        }

        public void setJerseyNbr(Integer jerseyNbr)
        {
            this.jerseyNbr = jerseyNbr;
        }
    }
}

Facelet:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:o="http://omnifaces.org/ui"
      xmlns:of="http://omnifaces.org/functions"
      xmlns:p="http://primefaces.org/ui">

    <f:view>

        <h:head>
        </h:head>

        <h:body>

            <div style="margin-left: auto; margin-right: auto; width: 500px; font-size: 0.8em;">

                <h1>Game Manager</h1>

                <h:form id="score-input-form">

                    <!--p:treeTable id="home-box-score-table"
                                 value="#{debugTableValidateMultipleManager.rootNode}"
                                 var="obj"
                                 nodeVar="node"
                                 styleClass="box-score-tree-table">

                        <f:facet name="header">
                            Home Team
                        </f:facet>

                        <p:column id="name"
                                  headerText="Player"
                                  styleClass="width-30 text-left">
                            <h:outputText value="#{obj.name}" />
                        </p:column>

                        <p:column id="jersey-nbr"
                                  headerText="Jersey Number"
                                  styleClass="width-10 text-right">
                            <p:inputNumber id="jersey-nbr-input"
                                           value="#{obj.jerseyNbr}"
                                           required="true"
                                           requiredMessage="Jersey number is required."
                                           maxlength="2"
                                           decimalPlaces="0"
                                           styleClass="" />
                        </p:column>

                    </p:treeTable-->

                    <p:dataTable id="home-box-score-table"
                                 value="#{debugTableValidateMultipleManager.rootNode.data.playerStats}"
                                 var="obj"
                                 styleClass="box-score-tree-table">

                        <f:facet name="header">
                            Home Team
                        </f:facet>

                        <p:column id="name"
                                  headerText="Player"
                                  styleClass="width-30 text-left">
                            <h:outputText value="#{obj.name}" />
                        </p:column>

                        <p:column id="jersey-nbr"
                                  headerText="Jersey Number"
                                  styleClass="width-10 text-right">
                            <p:inputNumber id="jersey-nbr-input"
                                           value="#{obj.jerseyNbr}"
                                           required="true"
                                           requiredMessage="Jersey number is required."
                                           maxlength="2"
                                           decimalPlaces="0"
                                           styleClass="" />
                        </p:column>

                    </p:dataTable>

                    <div class="clear-both" />

                    <o:validateMultiple id="home-validator"
                                        components=":score-input-form:home-box-score-table:0:jersey-nbr-input :score-input-form:home-box-score-table:1:jersey-nbr-input"
                                       omponents="@form:home-box-score-table:0:jersey-nbr-input"
                                       mponents="#{debugTableValidateMultipleManager.validatorIds}"
                                        validator="#{debugTableValidateMultipleManager.validateJerseyNbrs}" />

                    <p:messages severity="error" />

                    <p:commandButton id="save-button"
                                     icon="fa fa-save"
                                     value="Save"
                                     action="#{debugTableValidateMultipleManager.save()}"
                                     process="@form"
                                     update="@form"
                                     style="margin-top: 10px;" />

                </h:form>

            </div>            

        </h:body>

    </f:view>

</html>

问题

为什么不起作用?

这是OmniFaces中的错误/缺失功能吗?

查看ValidateMultipleFields类中的OmniFaces代码

private UIInput findInputComponent(UIComponent parent, String clientId, PropertyKeys property) {

    UIComponent found = parent.findComponent(clientId);     <-- results in null!

    if (found == null) {
        throw new IllegalArgumentException(format(
            ERROR_UNKNOWN_COMPONENT, getClass().getSimpleName(), property, clientId));
    }
    else if (!(found instanceof UIInput)) {
        throw new IllegalArgumentException(format(
            ERROR_INVALID_COMPONENT, getClass().getSimpleName(), property, clientId, found.getClass().getName()));
    }

    return (UIInput) found;
}

并查看生成的HTML ...

enter image description here

...我正在使用的ID似乎是正确的,并且搜索策略parent.findComponent(clientId)可能不适用于p:dataTablep:treeTable ...🤷迭代♂等迭代组件>

如果有人可以看一下,我会很高兴。

也许对此有另一种解决方案,但我简单看不到,所以如果有另一种方法可以验证p:dataTablep:treeTable中的多个输入,请告诉我。


编辑:

我用p:dataTable来解释我的问题,但是我不知道该组件具有完全不同的继承层次结构。 p:dataTableUIData延伸,而p:treeTableUITree延伸。

显然,分层数据当然更复杂。

这是我正在使用的真实用户界面:

enter image description here

这会导致使用o:validateUniqueColumn的异常:

00:02:17,223 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (default task-2) java.lang.IllegalArgumentException: Parent component of o:validateUniqueColumn must be enclosed in an UIData component.
    at org.omnifaces.taghandler.ValidateUniqueColumn.apply(ValidateUniqueColumn.java:114)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:161)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:135)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:96)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:161)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:135)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:96)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:161)
    at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:203)
    at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:135)
    at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:96)
    at com.sun.faces.facelets.tag.ui.CompositionHandler.apply(CompositionHandler.java:195)
    at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:94)
    at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:88)

我有一个如下所示的用户界面:游戏中不得有重复的球衣号码,因此我需要该列中所有UIInput的验证器。我立即想出了使用OmniFaces的o:...

validation jsf primefaces omnifaces
1个回答
2
投票

<o:validateMultiple>还不是要以这种方式使用,而是以中继器组件中的单个组件为目标。它仅对XHTML源代码中定义的物理多个组件起作用,而实际上不适用于HTML输出中产生的多个组件。

© www.soinside.com 2019 - 2024. All rights reserved.