如何知道验证错误的原因

发布于 2024-08-08 19:40:57 字数 4957 浏览 13 评论 0原文

如果由于某种原因保存失败,以下代码将抛出 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 并抛出一个运行时异常。但是现在如何将错误传递回调用控制器呢?以下不起作用。

   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
    }

The following code will throw a grails.validation.ValidationException if the save fails for some reason. But the result is a generic error. How can I know the actual cause of the error so I can report it back to the user?

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

This is the stack trace returned. I happen to know that it's caused by violating a unique contsraint, because I caused it on purpose, but there's nothing in the trace to indicate that was cause vs. some other constraint violation.

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

Update

OK, it seems that at least for now, the only way to get a transaction to roll back AND figure out what caused the error is to check if the save failed, get the failedobject.errors and throw a RuntimeException. But now how do you pass the errors back to the calling controller? The following doesn't work.

   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
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小梨窩很甜 2024-08-15 19:40:57

老问题,但如果有人偶然发现它:在服务中,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
    }
}

如果您在控制器中完成所有工作,则相同的想法。在这种情况下,您当然不需要抛出然后捕获异常,您可以当场处理 child.errors

Old question but if somebody stumbles upon it: in a service, the Grails (2.1) idiom is to call save() and throw a ValidationException if save failed.

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

You typically do not call save(failOnError: true). Instead, in your controller, you catch the ValidationException:

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

Same idea if you do all the work in your controller. In that case, you do not need to throw then catch an exception of course, you can process the child.errors on the spot.

盛夏已如深秋| 2024-08-15 19:40:57

我认为 ValidationException 具有对验证失败的对象的引用?如果确实如此,则检查错误属性以获取错误列表。

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

I would think that the ValidationException has a reference to the object that failed validation? If it does then check the errors property for the list of errors.

If not you will need to catch it and then check theChild.errors for the errors.

明月松间行 2024-08-15 19:40:57

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

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

另一种选择是不使用声明式事务;即在服务上设置 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() 调用期间将填充错误。您应该考虑在调用方中实例化 Child 并通过引用传递它,而不是传入 String 和 Parent,然后在服务中实例化 Child。然后,当 save() 失败时,即使 save(failOnError:true) 导致 ValidationException,也会填充子级的错误。调用者可以捕获 ValidationException,然后将子级作为视图模型的一部分传递回来。

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

Granted, the save(failOnError:true) approach currently yields too little information about what validation caused the problem. (Do you really want to parse exception messages in the controller anyway?) However, there are multiple alternatives you might consider to deal with two different issues, transaction rollback and communicating validation error information.

One alternative is to avoid the persistence of the data altogether. First, call theChild.validate() to see if theChild can be saved. If no validations fail, validate() returns true, so call theChild.save(). If validation errors occur, they will be recorded in the errors object on theChild. The newly created child returned to the calling controller can then be inspected for errors or simply displayed to the user in the view.

Another alternative is to not use declarative transactions; i.e. set static transactional = false on the service. Then, your code could manage the transaction itself; something like this:

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

Finally, your question implies you want the controller to do something with the errors information, such as rendering the original page so a user can correct entries. Since theChild is what's validated, returning the child won't work when an exception is being thrown (your own or ValidationException). However, the child will have errors populated during the save() call. Instead of passing in a String and Parent, then instantiating a Child in the service, you should consider instantiating the Child in the caller and passing it in by reference. Then, when the save() fails, the child's errors will be populated, even if the save(failOnError:true) results in a ValidationException. The caller can catch the ValidationException and then pass the child back as part of the model for the view.

Personally, I think the first alternative (call validate() first) or the last (instantiate the child outside the service) is preferable to managing transactions manually. In Grails, the declarative transaction management is all or nothing for the entire service. That is, if you set static transactional = false for the service, you'll have to manually manage all transactions in every method of the service. The KISS principle should be applied here.

归途 2024-08-15 19:40:57

尝试使用 grails 命令类进行验证参考此处

示例:

class ParentCommand  {
    .....field.....
     ........constraint.....
   }


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

Try to use grails command class for validation REFER HERE

example :

class ParentCommand  {
    .....field.....
     ........constraint.....
   }


def addChild(cName,ParentCommand cmd) {
     if(cmd.hasErrors()) {
    render (cmd.errors as JSON).toString();
    return "false";
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文