玩框架2.3 ActionBuilder组成问题

时间:2015-01-21 22:32:46

标签: scala playframework playframework-2.3

我非常喜欢播放框架2.3的ActionBuilder和andThen方法,它允许您动态编写动作。

这是我想要如何使用动作组合的片段:

def showHomepage = RedirectingAction andThen
    AuthenticatedAction andThen NotificationAction async { request =>
      Future {
        Ok(views.html.homepage.render(request.user, request.notifications ))
     }
 }

您可以猜到,NotificationAction依赖于AuthenticatedAction,因此需要包含User对象的AuthenticatedRequest。

代码抱怨:

object NotificationAction extends ActionBuilder[NotificationAuthRequest] {
    def invokeBlock[A](request: AuthenticatedRequest[A], block: (NotificationAuthRequest[A]) => Future[Result]) = { ...

错误是: 对象创建不可能,因为方法invokeBlock在特征ActionFunction类型为[A](请求:play.api.mvc.Request [A],块:controllers.v3.ScalaHomepageController.NotificationAuthRequest [A] => scala.concurrent.Future [ play.api.mvc.Result])scala.concurrent.Future [play.api.mvc.Result]未定义

显然它只允许:

def invokeBlock[A](request: Request[A], block: ...

但不是:

def invokeBlock[A](request: AuthenticatedRequest[A], block: ...

如果有人能对此有所了解,我真的很感激。也许我的方法是错误的,但我不喜欢预组合动作的想法(比如使用ActionFunction),因为我可能会有更多的动作,我可能会在以后混合使用。

以下是代码:

case class AuthenticatedRequest[A](val user: Option[User], request: Request[A]) extends  WrappedRequest(request)

case class NotificationAuthRequest[A](val user: Option[User], val notifications: Option[List[UserNotificationData]], request: Request[A]) extends  WrappedRequest(request)


  object RedirectingAction extends ActionBuilder[Request] {

      def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
          Future {
            Redirect(REDIRECT_URL + request.uri + paramString)
          }
      }
  }

  object AuthenticatedAction extends ActionBuilder[AuthenticatedRequest] {

    def invokeBlock[A](request: Request[A], block: (AuthenticatedRequest[A]) => Future[Result]) = {
      request.cookies.get("uid") map {
        cookie =>
          val user = userClient.getUserById(userId(cookie)).get
          block(AuthenticatedRequest[A](user, request))
      } getOrElse {
        block(AuthenticatedRequest[A](userClient.getUserById(uid).get, request))
      }
    }


    def userId(cookie: Cookie) = {
      if(AppUtil.isProd) cookie.value else IMPERSONATE_ID.getOrElse(cookie.value)
    }
  }

  object NotificationAction extends ActionBuilder[NotificationAuthRequest] {
    def invokeBlock[A](request: AuthenticatedRequest[A], block: (NotificationAuthRequest[A]) => Future[Result]) = {
      request.user.map {
        user => block(NotificationAuthRequest[A](Some(user), userClient.getNotifications(user.getId).get.map(_.toList), request))
      }.getOrElse {
        block(NotificationAuthRequest[A](None, None, request))
      }
    }
  }

1 个答案:

答案 0 :(得分:6)

阅读文档我认为你需要有ActionRefiners和ActionTransformers。

这就是我提出的:

package controllers

import play.api.mvc._

import scala.concurrent.Future

case class User(id: Long)

case class UserNotificationData(text: String)

case class AuthRequest[A](user: Option[User], request: Request[A]) extends WrappedRequest(request)

case class AuthNotificationRequest[A](user: Option[User], notifications: Option[List[UserNotificationData]], request: Request[A]) extends WrappedRequest(request)

object RedirectingAction extends ActionBuilder[Request] {

  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    block(request)
  }
}

object AuthenticatedAction extends ActionBuilder[AuthRequest] with ActionTransformer[Request, AuthRequest] {

  def transform[A](request: Request[A]) = Future.successful {
    request.cookies.get("uid") map {
      cookie =>
        val user = Some(User(1))
        AuthRequest[A](user, request)
    } getOrElse {
      AuthRequest[A](Some(User(1)), request)
    }
  }
}

object WithNotifications extends ActionTransformer[AuthRequest, AuthNotificationRequest] {
  def transform[A](request: AuthRequest[A]) = Future.successful {
    request.user.map { user => AuthNotificationRequest[A](Some(user), Some(List(UserNotificationData("Notification"))), request)} getOrElse {
      AuthNotificationRequest[A](None, None, request)
    }
  }
}

object Application extends Controller {

  def index = (RedirectingAction andThen AuthenticatedAction andThen WithNotifications) { request: AuthNotificationRequest[AnyContent] =>
    Ok(views.html.index("Your new application is ready."))
  }

}