通过长堆栈转储,Grails可能有点像熊一样调试。找到问题的根源可能很棘手。我在BootStrap.groovy中做过几次烧伤,例如“def foo = new Foo(a:a,b:b).save()”。您最喜欢调试Grails应用程序的技巧是什么?
答案 0 :(得分:33)
一些一般提示:
less stacktrace.log
)...一次在你的查看器中,搜索.groovy和.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
和useOldAliasMetadataBehavior=true
中均正确用户名,密码和主机的数据库,并确保您知道连接器版本的来龙去脉(即mysql连接器版本5.1.X有一个奇怪的问题,可能需要您设置DataSource.groovy
的别名{{1}})中的网址等等。有许多模式需要学会识别。
答案 1 :(得分:16)
为了补充Chris King关于保存的建议,我写了一个可重复使用的闭包:
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)
此外,我使用debug plugin - 它允许额外的日志记录,我将标签添加到我的主要底部 - 这使我可以查看会话/请求中的所有变量。
Runtime Logging plugin允许在运行时启用日志记录。
在撰写此答案时,P6SPY plugin似乎也很有用 - 它会通过充当代理来记录您的应用对数据库所做的所有陈述。
Grails Console也很有用。我用它来交互式地浏览并试验一些代码,这些代码在调试时也很方便。
当然,能够通过调试器是很好的。我切换到IntelliJ IDEA,因为它具有最好的Grails / Groovy支持。
答案 2 :(得分:14)
我曾经问过一位经验丰富的常规开发人员如何有效地调试他的应用程序。他的回答是:
我写测试了!
他有一个非常好的观点:如果你的代码有足够的单元和集成测试,你几乎不需要调试任何东西。另外,你可以向你的开发人员说出类似的东西......
对于Grails:
答案 3 :(得分:7)
使用GrailsUtil记录异常。
try{
...
}catch (Exception e){
log.error("some message", GrailsUtil.sanitize(e))
...
}
答案 4 :(得分:5)
将此代码添加到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
答案 5 :(得分:4)
我不确定这是否可以开箱即用,但在webapps中,我觉得有一个“我是谁?”很有用。设施在各种视图文件中。
这个想法是在呈现的HTML中发出一条消息,以识别片段。当我第一次遇到应用程序时尤其如此。
在Grails中,我使用自定义标记执行此操作。例如,考虑学生的list.gsp:
<g:debug msg="student list" />
以下是代码:
class MiscTagLib {
def debug = { map ->
if (grailsApplication.config.grails.views.debug.mode == true) {
def msg = map['msg']
out << "<h2>${msg}</h2><br/>"
}
}
}
关键是,如果需要,您可以将这些标签留在那里,因为它们仅在Config.groovy中启用模式时出现:
grails.views.debug.mode=true
答案 6 :(得分:4)
查看源代码!这已经让我多次拯救了我!现在,代码在GitHub上托管,比以往更容易。只需按“t”键即可开始输入以查找您正在寻找的课程!
答案 7 :(得分:2)
以下是来自Grails人员的@ groovymag收集的一些技巧:
答案 8 :(得分:1)
对于简单的应用程序,我使用println语句。这是非常简单的技巧。对于复杂的应用程序,在intellij idea中使用调试模式。