Play Framework 2.2动作组合返回自定义对象

Dav*_*vid 7 action scala before-filter playframework playframework-2.2

我正在尝试创建一个自定义play.api.mvc.Action,可用于CustomerAccount根据请求填充a 并传递CustomerAccount到控制器.

对播放2.2.x的文档,我创建了一个ActionActionBuilder,但我似乎无法返回CustomerAccount从动作中.

我目前的代码是:

case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)

case class Account[A](action: Action[A]) extends Action[A] {
  lazy val parser = action.parser

  def apply(request: Request[A]): Future[SimpleResult] = {
    AccountService.getBySubdomain(request.host).map { account => 
      // Do something to return the account like return a new AccountWrappedRequest?
      action(AccountWrappedRequest(account, request))
    } getOrElse {
      Future.successful(NotFound(views.html.account_not_found()))
    }
  }
}

object AccountAction extends ActionBuilder[AccountWrappedRequest] { 
  def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
    // Or here to pass it to the next request?
    block(request) // block(AccountWrappedRequest(account??, request))
  }

  override def composeAction[A](action: Action[A]) = Account(action) 
}
Run Code Online (Sandbox Code Playgroud)

注意:这不会编译,因为block(request)函数期望一种AccountWrappedRequest我无法填充的类型.它会在使用笔直时编译Request

另外...

最终,我希望能够将此帐户操作与身份验证操作相结合,以便CustomerAccount可以将其传递到身份验证操作,并且可以根据该客户的帐户提供用户身份验证.然后我想将客户帐户和用户传递给控制器​​.

例如:

Account(Authenticated(Action))) { request => request.account; request.user ... } 或者更好的是作为不需要自定义请求对象的单个对象.

Dav*_*vid 4

我不确定这是否是最好的方法,但我已经设法想出了一个似乎效果很好的解决方案。

关键是匹配请求,然后将其转换为AccountWrappedRequest内部invokeBlock,然后再将其传递给下一个请求。如果链中的另一个操作需要链中较早操作的值,则您可以类似地匹配请求,将其转换为访问请求参数所需的类型。

更新原始问题的示例:

case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)

case class Account[A](action: Action[A]) extends Action[A] {
  lazy val parser = action.parser

  def apply(request: Request[A]): Future[SimpleResult] = {
    AccountService.getBySubdomain(request.host).map { account => 
      action(AccountWrappedRequest(account, request))
    } getOrElse {
      Future.successful(NotFound(views.html.account_not_found()))
    }
  }
}

object AccountAction extends ActionBuilder[AccountWrappedRequest] { 
  def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
    request match {
      case req: AccountRequest[A] => block(req)
      case _ => Future.successful(BadRequest("400 Invalid Request"))
    }
  }

  override def composeAction[A](action: Action[A]) = Account(action) 
}
Run Code Online (Sandbox Code Playgroud)

然后在apply()另一个操作的方法中(在我的例子中是经过身份验证的操作),您可以类似地执行以下操作:

def apply(request: Request[A]): Future[SimpleResult] = {
  request match {
    case req: AccountRequest[A] => {
      // Do something that requires req.account
      val user = User(1, "New User")
      action(AuthenticatedWrappedRequest(req.account, user, request))
    }
    case _ => Future.successful(BadRequest("400 Invalid Request"))
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在 ActionBuilder 中将操作链接在一起

override def composeAction[A](action: Action[A]) = Account(Authenticated(action))
Run Code Online (Sandbox Code Playgroud)

如果然后将其传递到控制器中,AuthenticatedWrappedRequest您将可以访问和所有常用的请求参数。request.accountrequest.user

正如您所看到的,有几种情况下响应未知,这会生成BadRequest. 事实上,据我所知,这些永远不应该被调用,但它们就在那里以防万一。

我很想得到一些关于这个解决方案的反馈,因为我对 Scala 还很陌生,我不确定是否有更好的方法来达到相同的结果,但我希望这对某人也有用。