如果使用控制器来实现其他API,则需要处理抛出的任何异常并返回通用或特定格式良好的REST响应。
我们无法使用全局错误URL映射方法,因为该应用程序具有许多具有不同响应要求的API和接口,而且我们也不知道哪种类型的Grails'将抛出HTTP错误代码(例如,不知道它是否为400,422,500等)。此外,如果我们使用错误页面映射,我们将无法将相关数据放入JSON响应中。
E.g。这将生成GrailsRuntimeException:
class SomeController {
def payload = request.JSON
def someMethod() {
BigDecimal x = new BigDecimal(payload.notExists)
}
问题是,似乎无法捕获任何错误。
E.g。这种做法都没有:
def handleRuntimeException(RuntimeException e) {
render("some JSON error message")
}
也不是这种方法:
try {
:
}
catch (GrailsRuntimeException e) {
render("some JSON error message")
}
作品 - 它永远不会发现错误。
尝试了GroovyRuntimeException,Exception,MissingMethodException,Throwable等。
我们能想到的唯一解决方案是不在控制器中做任何工作,在服务中做所有事情,显然我们可以发现错误。
这种方法:
static mappings = {
"500"(controller: "error")
}
不希望我们需要几个原因:
决定了唯一的方法是将所有代码移动到服务中,除了传递请求之外,不在控制器中执行任何操作,并渲染结果字符串。即,所有参数处理,尤其是数字转换,都在服务中完成。
答案 0 :(得分:1)
默认情况下,服务是事务性的,因此它们是放置写入数据库的代码的好地方,因为它应该始终在事务中发生。无论是否具有交易性,它们对于业务逻辑都非常出色,您可以使用@Transactional
对单个方法进行注释,以将方法划分为在事务中运行的方法和不在事务中的方法。 ;或者将服务分成一些完全交易的服务和一些不是。
如果您将所有与HTTP相关的代码保存在控制器中,从params
执行数据绑定,并调用帮助程序类(服务,域类,标记库等),您可以很好地分离关注点,如果服务层对params
,HttpServletRequest
,HTTP会话等没有任何了解,那么它可以在其他Grails应用程序中轻松重用,甚至可以在非Grails应用程序中重复使用。它们也更容易测试,因为没有那么多相互关联的代码需要被模拟,否则会使测试更友好。
使用这种方法,控制器基本上变成哑路由器,接受请求,调用帮助程序来完成实际工作,委派页面呈现或响应写入,或重定向或转发。
答案 1 :(得分:0)
我很晚才回答这个问题,但我认为这可能有助于人们绊脚石并寻找解决方案。
以下是我的一篇解释Custom exception handling in grails and error responses for RESTfull services
的博客希望这可以帮助某人
答案 2 :(得分:0)
我正在使用grails 3.2.4并且没有问题,因为您已在此处解释过。我已将所有业务逻辑移到服务类中,并通过父控制器特征捕获异常。在这里,我在另一个ParentExceptionController特征中处理此异常,该特征由从服务类发生此类异常的类实现。示例:
UserService {
boolean create(Map params) {
throw new InvalidParameterException('some message')
}
UserController implements ParentExceptionController {
UserService userService
userService.create(params.userDetails)
}
trait ParentExceptionController {
Object handleInvalidParameterException(InvalidParameterExceoption exception) {
log.error 'log message'
respond([message: exception.message])
}
first and second both are working in my case.