【问题标题】:Service call back to a Controller?服务回调到控制器?
【发布时间】:2014-04-16 11:02:00
【问题描述】:

Grails 使 Controller 调用 Service 和 Controller 将请求转发到另一个 Controller 变得非常容易。

所以假设你有一个这样的服务方法

List<String>  updateNames() {
   ...
}

您可以从任何控制器轻松调用它。

我想知道,如果你有一个边缘情况,你意识到你的服务方法中存在验证问题。您不想将异常抛出回您的控制器,因为这并不是一个真正的例外情况。但是您不能将错误消息从您的服务返回给调用的控制器,因为这意味着您必须使用一些包装器对象而不是一个不错的列表

对于这些情况,您是否可以让服务将服务器端转发到另一个控制器,这可能会向用户返回错误响应?

谢谢。

【问题讨论】:

  • 这在我看来是一个理想的例外用例......
  • 同意塞尔吉奥和约书亚的观点。通过使用命令对象或域实例本身,甚至可以在进入服务类之前处理所有验证异常。正如 Joshua 提到的关注点分离,服务不应该知道 http 调用或任何验证问题。它应该关心业务异常/场景。话虽如此,从服务中抛出运行时异常或错误将是我回滚事务的最后一件事。我们应该使用TransactionAspectSupport 来处理回滚。
  • @Ian Roberts 为什么?这是您期望可能发生的事情,用户可能输入了错误的数据。您的系统本身实际上并没有出现任何问题。

标签: grails


【解决方案1】:

Grails 在您的 bean 中已经有一个用于验证的结构,称为 Errors(来自 Spring)。例如,如果你有一个上传文件的服务,你可以很容易地在你的 bean 中附加验证错误:

class UploadService {
  void doUpload(MultipartFile file, MyDomainClass domainClassInstance) {
    if(validationsFail) {
      domainClassInstance.errors.rejectValue("myUploadField","my.i18n.code")
    }
  }
}

如果它不是域类,您可以考虑使用command object,因为它们也是可验证的。

在您的控制器中,只需检查您的实例是否有错误:

def upload() {
  MyDomainClass instance = ...
  uploadService.doUpload(request.getFile('file'), instance)
  if(!instance.hasErrors()) {
    //save and go on...
  }
}

另一种选择是使用@Joshua Moore 回答的例外情况。请记住扩展RuntimeException。否则,您的事务将不会自动回滚。

【讨论】:

    【解决方案2】:

    服务不会以这种方式了解 web/http 请求上下文。我不会讨论这条线是如何被会话或请求范围服务模糊的,因为它仍然不适用于您所询问的内容。另外,您真的不希望您的服务甚至知道它正在处理 web/http 请求,因为您希望分离职责并拥有良好/干净的设计。

    那么,回到你的问题。这正是从您的服务中引发异常并让您的控制器处理该异常的结果的情况。如果它是实例上的验证错误,那么您应该能够访问控制器中实例的错误集合(当然前提是它是您服务的输入)。

    作为关于服务异常的旁注。堆栈跟踪的填充成本很高。在 Grails 中更是如此,因为有很多部分在工作。如果您要从服务中引发自己的业务逻辑异常,我强烈建议您覆盖异常的 fillInStackTrace 方法以避免此成本。

    这是一个例子:

    package com.example
    
    class MyBusinessException extends RuntimeException {
    
        List<String> argList = []
    
        public MyBusinessException (String message, List<String> args){
            super(message)
    
            argList = args
        }
    
        public MyBusinessException (String message){
            super(message)
        }
    
        /**
        * Don't fill in the stack trace because we want things to be faster.
        **/
        @Override
        public Throwable fillInStackTrace() {
            // do nothing
            return this
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 2017-10-11
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      相关资源
      最近更新 更多