【问题标题】:Validation doesn't always validate验证并不总是有效
【发布时间】:2013-09-21 16:14:13
【问题描述】:

在我的 bean 被持久化之前,我想验证几个字段。

我有 inputText、selectOne、SelectManyListBox、...

我的问题是,其中一些验证已经完成,而另一些则没有......

例如。我有

<tr>
  <td><h:outputLabel value="#{msg.subscriptionFormFieldPhone}:" /></td>
  <td><h:inputText
           id="phone"
           value="#{detailModel.afterObject.phone}"
           disabled="#{detailModel.mode == detailModel.viewMode or (detailModel.mode == detailModel.editMode and !loggedUser.hasPermission('CMN backoffice permission id'))}" />
      <h:messages for="phone" style="color:red; font-size:12px;" />
  </td>
</tr>

...

<tr>
  <td><h:outputLabel value="#{msg.subscriptionFormFieldFund}:" /></td>
  <td>
    <table>
      <tr>
        <td><h:inputText
               id="fund"
               value="#{detailModel.afterObject.fund}" disabled="true">
          <f:converter converterId="ch.ethz.id.cmn.FundConverter" />
        </h:inputText>
        <h:messages for="fund" style="color:red; font-size:12px;" />
        </td>

    <td valign="top">
      <!-- add button -->
          <h:commandButton styleClass="waiButton"
             value="#{lakshmiMsg.commonButtonAddExisting}"
             action="#{detailController.gotoFundSelection()}"
             rendered="#{(detailModel.mode == detailModel.createMode and detailModel.afterObject.fund == null) or ((detailModel.mode != detailModel.viewMode and detailModel.afterObject.fund == null))}"
             disabled="#{detailModel.mode == detailModel.multiEditMode}" />

      <!-- delete button -->
          <h:commandButton styleClass="waiButton"
             value="#{lakshmiMsg.commonButtonDelete}"
             action="#{detailController.deleteFund()}"
             rendered="#{((detailModel.mode == detailModel.editMode) and loggedUser.hasPermission('CMN backoffice permission id')) or (detailModel.mode == detailModel.createMode and detailModel.afterObject.fund != null)}"
             disabled="#{detailModel.mode == detailModel.multiEditMode}" />
    </td>
      </tr>
    </table>
  </td>
</tr>
<tr>
  <td><h:outputLabel value="#{msg.subscriptionFormFieldOwner}:" /></td>
  <td>
    <table>
      <tr>
        <td><h:inputText id="owner"
               value="#{detailModel.afterObject.owner}"
               disabled="true">
              <f:converter converterId="ch.ethz.id.cmn.UserConverter"></f:converter>
            </h:inputText>
            <h:messages for="owner" style="color:red; font-size:12px;" />
        </td>
        <td valign="top">
      <!-- add button -->
          <h:commandButton styleClass="waiButton"
             value="#{lakshmiMsg.commonButtonAddExisting}"
             action="#{detailController.gotoUserSelection()}"
             rendered="#{(detailModel.mode == detailModel.createMode and detailModel.afterObject.owner == null) or ((detailModel.mode != detailModel.viewMode and detailModel.afterObject.owner == null))}"
             immediate="true"
             disabled="#{detailModel.mode == detailModel.multiEditMode}" />

      <!-- delete button -->
          <h:commandButton styleClass="waiButton"
             value="#{lakshmiMsg.commonButtonDelete}"
             action="#{detailController.deleteOwner()}"
             rendered="#{((detailModel.mode == detailModel.editMode) and loggedUser.hasPermission('CMN backoffice permission id')) or (detailModel.mode == detailModel.createMode and detailModel.afterObject.owner != null)}"
             immediate="true"
             disabled="#{detailModel.mode == detailModel.multiEditMode}" />
    </td>
      </tr>
    </table>
  </td>
</tr>

...

<tr>
  <td valign="top">
     <h:outputLabel value="#{msg.subscriptionFormFieldDataOptions}:" /></td>
  <td>
    <table>
      <tr>
        <td>
          <h:selectManyListbox
             id="dataOptions"
             value="#{detailModel.selectedDataOptions}"
             size="5"
             disabled="#{detailModel.mode == detailModel.viewMode or (detailModel.mode == detailModel.editMode and !loggedUser.hasPermission('CMN backoffice permission id'))}">
             <f:selectItems value="#{detailModel.afterObject.dataOptions}" 
                var="sdo" itemLabel="#{sdo.dataOptionName}"
                itemValue="#{sdo}" />
          </h:selectManyListbox>
          <h:messages for="dataOptions" style="color:red; font-size:12px;" />
        </td>
        ...
     </tr>
   </table>
  </td>
</tr>
...

在我的 bean(与 detailModel.afterObject 绑定)中,我用 @NotNull 标记了字段 和@Size(min=1)。

@NotNull( message = "{validation.emptyPhoneNumber}" )
@Pattern( regexp = "^(((41)(\\s?)(-?))|(0))(7)(\\d{1})(\\s?)(-?)(\\d{3})(\\s?)(-?)(\\d{2})(\\s?)(-?)(\\d{2})", message = "{validation.notValidPhoneNumber}" )
private String phone;

@NotNull( message = "{validation.emptyFund}" )
@Size(min=1, message = "{validation.emptyFund}" )
private String              fund;

@NotNull( message = "{validation.emptyOwner}" )
@Size(min=1, message = "{validation.emptyOwner}" )
private String owner;

@ManyToMany( fetch = FetchType.LAZY, cascade = {} )
@JoinTable( name = "CMN_MAP_SUBSCRIPTION_TO_DATAOPTION" )
@NotNull( message = "{validation.emptyDataOption}" )
@Size(min=1, message = "{validation.emptyDataOption}" )
private Set< DataOption > dataOptions;  

好吧,第一个 inputText(电话)已经过验证,如果我将其留空或模式不匹配,我会收到错误消息,但对于其他人来说,(显然)没有验证;如果我将它们留空,则不会出现任何消​​息...

唯一的区别是fund和owner inputFileds有一个转换器,最后一个是selectManyListBox,它映射到一个Set,而所有其他的都映射到String。

由于持久性随后失败,我在日志中有一条错误消息,并且在那里我可以看到 ConstraintViolationException,但我不明白为什么它在验证时没有声明在页面上而不是堆栈上显示消息在日志中跟踪...

[exec] [#|2013-09-17T11:26:49.901+0200|WARNING|glassfish3.1.2|javax.enterprise.resource.jta.com.sun.enterprise.transaction|_ThreadID=420;_ThreadName=Thread-2;|DTX5014: Caught exception in beforeCompletion() callback:
 [exec] javax.persistence.PersistenceException: error during managed flush
 [exec]     at org.hibernate.ejb.AbstractEntityManagerImpl$CallbackExceptionMapperImpl.mapManagedFlushFailure(AbstractEntityManagerImpl.java:1515)
 [exec]     at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.beforeCompletion(SynchronizationCallbackCoordinatorImpl.java:109)
 [exec]     at org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization.beforeCompletion(RegisteredSynchronization.java:53)
 [exec]     at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435)
 [exec]     at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855)
 [exec]     at com.sun.enterprise.transaction.UserTransactionImpl.commit(UserTransactionImpl.java:208)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.common.TransactionHelper.commitTransaction(TransactionHelper.java:74)
 [exec]     at ch.ethz.id.wai.lakshmi.stdcmp.boo.processing.BusinessObjectOrderProcessing.processOrder(BusinessObjectOrderProcessing.java:121)
 [exec]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 [exec]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
 [exec]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 [exec]     at java.lang.reflect.Method.invoke(Method.java:601)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.invokeWorkflowStep(LakshmiServerBean.java:850)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.executeNextWorkflowStep(LakshmiServerBean.java:796)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.executeNextWorkflowStep(LakshmiServerBean.java:707)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.continueWorkflow(LakshmiServerBean.java:627)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.processLakshmiComponentResponse(LakshmiServerBean.java:576)
 [exec]     at ch.ethz.id.wai.lakshmi.engine.ejb.LakshmiServerBean.onMessage(LakshmiServerBean.java:397)
 [exec]     at sun.reflect.GeneratedMethodAccessor967.invoke(Unknown Source)
 [exec]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 [exec]     at java.lang.reflect.Method.invoke(Method.java:601)
 [exec]     at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
 [exec]     at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
 [exec]     at com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:4180)
 [exec]     at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5368)
 [exec]     at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5348)
 [exec]     at com.sun.ejb.containers.MessageBeanContainer.deliverMessage(MessageBeanContainer.java:1099)
 [exec]     at com.sun.ejb.containers.MessageBeanListenerImpl.deliverMessage(MessageBeanListenerImpl.java:81)
 [exec]     at com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:171)
 [exec]     at com.sun.proxy.$Proxy409.onMessage(Unknown Source)
 [exec]     at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:260)
 [exec]     at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
 [exec]     at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
 [exec]     at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
 [exec] Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [ch.ethz.id.wai.cmn.bo.Subscription] during persist time for groups [javax.validation.groups.Default, ]
 [exec] List of constraint violations:[
 [exec]     ConstraintViolationImpl{interpolatedMessage='Please specify a fund', propertyPath=fund, rootBeanClass=class ch.ethz.id.wai.cmn.bo.Subscription, messageTemplate='{validation.emptyFund}'}
 [exec]     ConstraintViolationImpl{interpolatedMessage='Please specify a fund', propertyPath=fund, rootBeanClass=class ch.ethz.id.wai.cmn.bo.Subscription, messageTemplate='{validation.emptyFund}'}
 [exec]     ConstraintViolationImpl{interpolatedMessage='Please specify a owner', propertyPath=owner, rootBeanClass=class ch.ethz.id.wai.cmn.bo.Subscription, messageTemplate='{validation.emptyOwner}'}
 [exec]     ConstraintViolationImpl{interpolatedMessage='{validation.emptyDataOption}', propertyPath=dataOptions, rootBeanClass=class ch.ethz.id.wai.cmn.bo.Subscription, messageTemplate='{validation.emptyDataOption}'}
 [exec] ]
 [exec]     at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:159)
 [exec]     at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:94)
 [exec]     at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:185)
 [exec]     at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:81)
 [exec]     at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
 [exec]     at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
 [exec]     at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:275)
 [exec]     at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
 [exec]     at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
 [exec]     at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
 [exec]     at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:402)
 [exec]     at org.hibernate.engine.transaction.synchronization.internal.SynchronizationCallbackCoordinatorImpl.beforeCompletion(SynchronizationCallbackCoordinatorImpl.java:104)
 [exec]     ... 32 more
 [exec] |#]

欢迎提供帮助、提示、提示...

更新:

我在手机inputText和基金inputText中编写并添加了一个Validator:

<f:validator validatorId="ch.ethz.id.cmn.validator.SubscriptionValidator" />

我在 validate 方法中设置了一个断点。

好吧,对于电话来说,方法是调用的,对于基金来说不是!

我很困惑。我的 html 代码中的某些内容阻止了验证...

更新 2:

如果我删除disabled="true",它就会起作用。它是如此想要还是一个错误?如果字段被禁用,有没有办法让它工作?

更新 3:

现在我真的很困惑... 在将 disabled 替换为 readonly all (但 selectManyListBox )之后,在我尝试编辑页面中的某些值后,它可以很好地工作。 虽然我没有更改/删除基金和所有者字段,但我收到了验证错误消息...... 我在 bean 的 getters 方法中放置了一个断点并设置了值,即不为空。那么为什么@NotNull 仍然抱怨呢? 如果我删除 bean 中的注释并在 html 中添加 required 和 requiredMessage,也会发生这种情况。

【问题讨论】:

    标签: validation jsf-2 bean-validation


    【解决方案1】:

    发现问题出在disabled="true"后,找到了答案。 请参阅jsf (richfaces) readonly input text validation,Balus 的回答;)

    更新:

    嗯,它适用于 inputText 但不适用于 selectManyListBox 如果我删除禁用...

    有什么想法吗?

    【讨论】:

      猜你喜欢
      • 2012-10-04
      • 1970-01-01
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 2015-06-28
      • 2015-12-04
      • 2017-01-08
      相关资源
      最近更新 更多