通过长堆栈转储,Grails可能有点像熊一样调试.找到问题的根源可能很棘手.我在BootStrap.groovy中做过几次烧伤,例如"def foo = new Foo(a:a,b:b).save()".您最喜欢调试Grails应用程序的技巧是什么?
一些一般提示:
清除stacktrace.log,做grails run-app,然后在查看器中打开stacktrace.log(我更喜欢less stacktrace.log
linux)...一旦在你的查看器中,搜索.groovy和.gsp ...这通常会带你到你的东西实在在意.
当堆栈跟踪引用GSP文件中的行号时,您应该在浏览器?showSource
中使用查询字符串打开该视图,即http://localhost:8080/myProject/myController/myAction?showSource
...这显示已编译的GSP源,并且堆栈跟踪中的所有GSP行号引用已编译的GSP,而不是实际的GSP来源
永远,始终,始终围绕您的保存,至少有一些最小的错误处理.
例:
try { if(!someDomainObject.save()) { throw new Exception ("Save failed") } } catch(Exception e) { println e.toString() // This will at least tell you what is wrong with // the instance you are trying to save someDomainObject.errors.allErrors.each {error -> println error.toString() } }
除此之外,很多东西只是归结为识别堆栈跟踪和错误消息......很多时候,Grails在它给你的错误消息中非常无益,但你可以学会识别模式,如下所示:
一些最难理解的错误是因为你没有运行grails clean
或grails upgrade
...为了避免这些问题,我总是在命令行上使用以下命令来运行grails:grails clean; yes | grails upgrade; grails run-app
如果错误与类的重复定义有关,请确保在类的文件顶部声明类所属的包
如果错误与架构元数据,连接,套接字或类似的内容有关,请确保您的数据库连接器已插入,请lib/
确保您DataSource.groovy
的用户名,密码和主机的数据库内和数据库中的权限都是正确的,并确保你知道你的连接器版本的来龙去脉(即mysql连接器版本5.1.X有一个奇怪的问题,别名,可能需要你useOldAliasMetadataBehavior=true
在网址上设置DataSource.groovy
)
等等.有许多模式需要学会识别.
为了增加Chris King关于save的建议,我写了一个可重用的闭包:
Closure saveClosure = { domainObj -> if(domainObj.save()) println "Domain Object $domainObj Saved" else { println "Errors Found During Save of $domainObj!" println domainObj.errors.allErrors.each { println it.defaultMessage } } }
然后你可以在任何地方使用它,它将负责错误报告:
def book = new Book(authorName:"Mark Twain") saveClosure(book)
另外,我使用调试插件 - 它允许额外的日志记录,我将标签添加到我的主要底部 - 这使我可以查看会话/请求中的所有变量.
运行时日志插件允许在运行时启用日志记录.
在编写这个答案时,P6SPY插件似乎也很有用 - 它通过充当代理来记录您的应用程序对数据库所做的所有语句.
Grails Console也很有用.我用它来交互式地浏览并试验一些代码,这些代码在调试时也很方便.
当然,能够通过调试器是很好的.我切换到IntelliJ IDEA,因为它具有最好的Grails/Groovy支持.
我曾经问过一位经验丰富的常规开发人员,他是如何有效地调试他的应用程序的.他的回答是:
我写测试!
他有一个非常好的观点:如果你的代码有足够的单元和集成测试,你几乎不需要调试任何东西.另外,你可以向你的开发人员说出类似的东西......
对于Grails:
单元测试
功能测试
非常优秀的grails app测试developerWorks文章
使用GrailsUtil记录异常.
try{ ... }catch (Exception e){ log.error("some message", GrailsUtil.sanitize(e)) ... }
有关sanitize的更多信息.
将此代码添加到Bootsrap.groovy:init将覆盖save方法并执行其他一些代码,在这种情况下打印出错误消息.
class BootStrap { def grailsApplication def init = {servletContext -> grailsApplication.domainClasses.each { clazz -> clazz.clazz.get(-1) def gormSave = clazz.metaClass.getMetaMethod('save') clazz.metaClass.save = {-> def savedInstance = gormSave.invoke(delegate) if (!savedInstance) { delegate.errors.each { println it } } savedInstance } def gormSaveMap = clazz.metaClass.getMetaMethod('save', Map) clazz.metaClass.save = { Map m -> def savedInstance = gormSaveMap.invoke(delegate, m) if (!savedInstance) { delegate.errors.each { println it } } savedInstance } def gormSaveBoolean = clazz.metaClass.getMetaMethod('save', Boolean) clazz.metaClass.save = { Boolean b -> def savedInstance = gormSaveBoolean.invoke(delegate, b) if (!savedInstance) { delegate.errors.each { println it } } savedInstance } } ... }
希望有人帮助:)
(我知道它不是真的干)
参考:http://grails.1312388.n4.nabble.com/How-to-override-save-method-on-domain-class-td3021424.html