如何知道验证错误的原因

Posted

技术标签:

【中文标题】如何知道验证错误的原因【英文标题】: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
    

【问题讨论】:

你得到什么样的错误信息? 【参考方案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 中的错误。

【讨论】:

感谢您的回复。它让我进行了更好的搜索。看起来这将在 1.2RC1 jira.codehaus.org/browse/GRAILS-5146 中得到解决【参考方案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";
 

【讨论】:

以上是关于如何知道验证错误的原因的主要内容,如果未能解决你的问题,请参考以下文章

apache xampp如何找到内部错误500的原因

由于未知原因,存档验证失败并出现错误

我如何知道 MS Access DB 损坏的实际原因

如何找到切换按钮崩溃的原因?

插件@nomiclabs/hardhat-etherscan 中的错误:合约验证失败。原因:失败 - 无法验证 - 带有参数

SSL证书错误啥原因