【问题标题】:How To Know The Cause Of A Validation Error如何知道验证错误的原因
【发布时间】:2010-12-11 01:43:24
【问题描述】:

如果由于某种原因保存失败,以下代码将抛出 grails.validation.ValidationException。但结果是一般错误。我怎样才能知道错误的实际原因,以便将其报告给用户?

 def addChild(cName,Parent theParent) {
    println "add child: ${cName}"
    def theChild = new Child(name:cName,parent:theParent)
    theChild.save(failOnError:true)
    return theChild
}

这是返回的堆栈跟踪。我碰巧知道它是由违反唯一约束引起的,因为我是故意造成的,但是跟踪中没有任何内容表明这是导致违反其他约束的原因。

org.codehaus.groovy.runtime.InvokerInvocationException: grails.validation.ValidationException: Validation Error(s) Occurred During Save

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)

    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)

    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)

    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)

    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)

    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)

    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)

    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)

    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)

    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)

    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)

    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)

    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)

    at java.lang.Thread.run(Thread.java:619)

Caused by: grails.validation.ValidationException: Validation Error(s) Occurred During Save

    at AddRecordsService.addChild(AddRecordsService.groovy:30)

    at AddRecordsService$addChild.callCurrent(Unknown Source)

    at AddRecordsService.addAll(AddRecordsService.groovy:11)

    at AddRecordsService$$FastClassByCGLIB$$e47d68f4.invoke(<generated>)

    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)

    at AddRecordsService$$EnhancerByCGLIB$$cdfdcc61.addAll(<generated>)

    at AddRecordsService$addAll.call(Unknown Source)

    at AddrecordController$_closure2.doCall(AddrecordController.groovy:14)

    at AddrecordController$_closure2.doCall(AddrecordController.groovy)

    ... 32 more

更新

好的,至少目前看来,让事务回滚并找出导致错误的唯一方法是检查保存是否失败,获取 failedobject.errors 并抛出 RuntimeException。但是现在如何将错误传递回调用控制器?以下不起作用。

   def addChild(cName,Parent theParent) {
        println "add child: ${cName}"
        def theChild = new Child(name:cName,parent:theParent)

       //theChild.save(failOnError:true)
       //theChild.save()


        if(!theChild.save()){
            println theChild.errors
             throw new RuntimeException(theChild.errors)
            //throw new RuntimeException('unable to save child')
        } 


        return theChild
    }

【问题讨论】:

  • 你得到什么样的错误信息?

标签: grails grails-validation


【解决方案1】:

老问题,但如果有人偶然发现:在服务中,Grails (2.1) 习惯用法是调用 save() 并在 save 失败时抛出 ValidationException。

 if (!theChild.save()) {
     throw new ValidationException(theChild.errors)
 } 

您通常不会致电save(failOnError: true)。相反,在您的控制器中,您会捕获 ValidationException:

try {
    service.addChild(child)
} catch (ValidationException e) {
    errors.allErrors.each {
        // do something with each error code
    }
}

如果您在控制器中完成所有工作,则同样的想法。这种情况下当然不需要 throw then catch 异常,你可以当场处理child.errors

【讨论】:

    【解决方案2】:

    我认为 ValidationException 引用了验证失败的对象?如果是,则检查错误列表中的错误属性。

    如果没有,您需要捕获它,然后检查 theChild.errors 中的错误。

    【讨论】:

    【解决方案3】:

    当然,save(failOnError:true) 方法目前产生的关于什么验证导致问题的信息太少。 (您真的想在控制器中解析异常消息吗?)但是,您可能会考虑多种替代方案来处理两个不同的问题,事务回滚和传达验证错误信息。

    另一种选择是完全避免数据的持久性。首先,调用 theChild.validate() 来查看是否可以保存 theChild。如果没有验证失败,则 validate() 返回 true,因此调用 theChild.save()。如果发生验证错误,它们将被记录在 theChild 的 errors 对象中。然后可以检查返回给调用控制器的新创建的子节点是否有错误,或者只是在视图中向用户显示。

    另一种选择是不使用声明式事务;即在服务上设置 static transactional = false。然后,您的代码可以管理事务本身;像这样:

    Child.withTransaction { txStatus ->
       try {
         child.save(failOnError:true)
       } catch (ValidationException e) {
         // rollback, but swallow exception, requiring caller to check child for errors
         txStatus.setRollbackOnly()
       }
    }
    

    最后,您的问题暗示您希望控制器对错误信息进行处理,例如呈现原始页面,以便用户可以更正条目。由于 theChild 是经过验证的,因此在引发异常(您自己的异常或 ValidationException)时返回孩子将不起作用。但是,在 save() 调用期间,孩子将填充错误。与其传入 String 和 Parent,然后在服务中实例化 Child,不如考虑在调用者中实例化 Child,然后通过引用传入。然后,当 save() 失败时,将填充子错误,即使 save(failOnError:true) 导致 ValidationException。调用者可以捕获 ValidationException,然后将孩子作为视图模型的一部分传回。

    就个人而言,我认为第一种选择(首先调用 validate())或最后一种(在服务之外实例化子)比手动管理事务更可取。在 Grails 中,声明式事务管理是整个服务的全部或全部。也就是说,如果您为服务设置 static transactional = false,您将不得不手动管理服务的每个方法中的所有事务。这里应该应用 KISS 原则。

    【讨论】:

      【解决方案4】:

      尝试使用 grails 命令类进行验证REFER HERE

      示例:

      class ParentCommand  {
          .....field.....
           ........constraint.....
         }
      
      
      def addChild(cName,ParentCommand cmd) {
           if(cmd.hasErrors()) {
          render (cmd.errors as JSON).toString();
          return "false";
      } 
      

      【讨论】:

        猜你喜欢
        • 2022-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-03
        • 1970-01-01
        • 2015-07-30
        • 2016-11-22
        • 1970-01-01
        相关资源
        最近更新 更多