如何知道验证错误的原因

时间:2009-10-28 22:55:10

标签: grails grails-validation

如果由于某种原因导致保存失败,则以下代码将抛出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
}

这是返回的堆栈跟踪。我碰巧知道它是由于违反了一个独特的contsraint造成的,因为我是故意造成的,但是跟踪中没有任何内容表明这是因为其他一些约束违规造成的。

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
    }

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

我认为ValidationException有一个对验证失败的对象的引用?如果是,则检查errors属性以获取错误列表。

如果不是,则需要捕获它,然后检查theChild.errors以查找错误。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

示例:

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


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