如何知道验证错误的原因
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";
【讨论】:
以上是关于如何知道验证错误的原因的主要内容,如果未能解决你的问题,请参考以下文章
插件@nomiclabs/hardhat-etherscan 中的错误:合约验证失败。原因:失败 - 无法验证 - 带有参数