我从最新的 Java 开发中了解到,抛出 RuntimeException
并以面向方面的方式处理它是当前服务层错误处理的趋势。这意味着,如果出现任何问题,您只需抛出一个 RuntimeException
或更好,让 Bean Validation 发挥作用。
优点是:您不会因 try-catch
和 if(entity.getName() == nil)
检查而阻塞代码。一切都在后台检查,这使您的代码更具可读性。
所以我想知道,这将如何在 Grails 中完成?当然,如果我使用 .save(failOnError:true)
,我会得到一个不错的 ValidationException
。但这会导致非常不愉快的默认错误页面,根本不会提高 Web 应用程序的可用性。
我还需要将它放在 Controller 级别的 try-catch
block 中吗?假设 EntityService
有一个方法,如下所示:
def toggleSomething(String entityId) = {
if(!someOtherPrerequisite) {
throw new EntityException("SomeOtherPrerequisite was not satisfied") // extends RuntimeException
}
Entity entity = Entity.get(entityId)
entity.someProperty = somePropertyValue
entity.save(failOnError:true) // throws a ValidationException
}
然后 Controller 会像这样调用它:
def toggle = {
try {
entityService.toggleSomething(params.id)
}
catch(e) {
flashHelper.error 'I'm sorry, something went wrong.'
}
}
但是当 Grails 在很多方面都是新学校时,这似乎是相当老派了。有没有一种方法可以更好地处理 RuntimeExceptions
而不会用 try-catch
阻塞代码?
最佳答案
我遵循的模式是:
如果错误可以包含在 Grails 域中,则不要直接处理异常处理。如果您的服务方法主要处理您的 grails 域,那么当出现错误时,它们会出现在 domain.errors 集合中。在 Controller 中,只需检查这些错误 (hasErrors())。由于无论如何都会在幕后抛出 RuntimeException,因此您的事务将回滚,没有伤害,也没有犯规。
如果您正在处理第 3 方库(可能是外部网络服务等),那么不要害怕异常。正因为 Grails (Groovy) 不需要您处理它们,所以拥有/使用它们仍然很好。
有时上述情况都不适用,也许您的服务方法应该只针对某些逻辑的结果返回一些 true 或 false 标志。以你的例子为例:
服务
def toggleSomething(String entityId) = {
if(!someOtherPrerequisite) {
return false
}
}
Entity entity = Entity.get(entityId)
entity.someProperty = somePropertyValue
entity.save() // throws a ValidationException
return entity.hasErrors()
}
Controller
def toggle = {
if (!entityService.toggleSomething(params.id)) {
flashHelper.error 'I'm sorry, something went wrong.'
}
}
不幸的是,可能没有绝对正确或错误的方法来处理这个问题。所以期待与我不同的答案。
关于服务层中的验证和验证错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9762120/