我知道如何使用UrlMappings在Grails中执行泛型异常处理,并使用ErrorController进行常规异常处理,这样如果异常转义控制器,用户将被发送到通用错误页面并记录异常。我也知道如何使用try / catch块来处理特定异常并尝试从中恢复。
但是在大多数控制器中,如果发生异常,我只想给用户一个稍微更具体的错误消息。所以在创建操作中,我想告诉用户该项目未创建。或者在导入操作中,我想告诉用户导入失败。现在,控制器看起来像:
class ThingController {
def create = {
try {
// The real controller code, which quickly hands it off to a service
} catch (Exception e) {
handleException(e, "There was an error while attempting to create the Thing")
}
}
def delete = {
try {
// The real controller code, which quickly hands it off to a service
} catch (Exception e) {
handleException(e, "There was an error while attempting to delete the Thing")
}
}
private void handleException(Exception e, String message) {
flash.message = message
String eMessage = ExceptionUtils.getRootCauseMessage(e)
log.error message(code: "sic.log.error.ExceptionOccurred", args: ["${eMessage}", "${e}"])
redirect(action:index)
}
}
请注意,catch块根据异常的类型或内容不做任何不同的操作;他们只是根据控制器提供稍微更具描述性的错误消息。 “真正的”控制器代码通常是6-10行,因此只需更改错误消息就可以使用额外的4行代码。此外,CodeNarc“CatchException”规则抱怨,这强化了我的观点,即必须有更好的方法来做到这一点。我假设其他Grails应用程序有类似的要求。什么是惯用方式,根据异常冒出的操作指定不同的错误消息?
我对通过解决此问题的特定方式的经验给出的答案感兴趣,甚至更好地链接到我可以在实践中看到解决方案的代码库。
答案 0 :(得分:27)
Grails具有一般处理控制器异常的机制。 您可以在专用的错误控制器中执行此操作。常规控制器不需要使用try / catch。
控制器:
class ThingController {
def create() {
def id = params.id as Long
if (id == null) {
throw new MissingPropertyException("thingId")
}
// The real controller code, which mostly parses things out and hands it
// off to a service.
// Service methods can throws exception
}
}
在UrlMappings中添加处理500错误:
class UrlMappings {
static mappings = {
// Exception handling in ErrorController
"500"(controller: "error")
}
}
ErrorController:
class ErrorController {
def index() {
def exception = request.exception.cause
def message = ExceptionMapper.mapException(exception)
def status = message.status
response.status = status
render(view: "/error", model: [status: status, exception: exception])
}
}
您可以使用此方法处理REST和非REST异常。 还有Declarative Exception Handling插件,但我没有
<强>更新强>
您可以在错误控制器中获取特定的错误消息。 当在控制器中抛出新的RuntimeException(“尝试删除Thing时出错”),然后在错误控制器中request.exception.cause.message将显示消息:“尝试删除Thing时出错”。 / p>
答案 1 :(得分:1)
另见How to know from where was thrown error 500 (Grails)
我根据控制器上的注释创建自定义错误页面,为多个控制器提供常见的异常处理程序。
class ErrorsController {
def index() {
def initialController = request.exception?.className
if (initialController) {
def controller = grailsApplication.getArtefact("Controller", initialController).getReferenceInstance()
// do some rendering based on the annotations
render "Controller: ${initialController}, annotations ${controller.getClass().getDeclaredAnnotations()}"
return
}
render 'no initial controller'
}