Play framework 2.3 ActionBuilder组合问题
Play framework 2.3 ActionBuilder composition issue
我非常喜欢 play framework 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]) = { ...
错误是:
不可能创建对象,因为 [A] 类型的特征 ActionFunction 中的方法 invokeBlock(请求:play.api.mvc.Request[A],块:控制器。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))
}
}
}
阅读文档我认为您需要 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."))
}
}
我非常喜欢 play framework 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]) = { ...
错误是: 不可能创建对象,因为 [A] 类型的特征 ActionFunction 中的方法 invokeBlock(请求:play.api.mvc.Request[A],块:控制器。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))
}
}
}
阅读文档我认为您需要 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."))
}
}