簡體   English   中英

Play Framework 2.2動作組合返回自定義對象

[英]Play Framework 2.2 action composition returning a custom object

我正在嘗試創建一個自定義的play.api.mvc.Action ,它可用於根據請求填充CustomerAccount並將CustomerAccount傳遞給控制器​​。

Play 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) 
}

注意:這將無法編譯,因為block(request)函數需要一種我無法填充的AccountWrappedRequest類型。 它將在使用直接Request時進行編譯

另外...

最終,我希望能夠將此帳戶操作與身份驗證操作相結合,以便可以將CustomerAccount傳遞到身份驗證操作,並且可以根據該客戶的帳戶提供用戶身份驗證。 然后我想將客戶帳戶和用戶傳遞給控制器​​。

例如:

Account(Authenticated(Action))) { request => request.account; request.user ... } Account(Authenticated(Action))) { request => request.account; request.user ... }或更好的作為不需要自定義請求對象的單個對象。

我不確定這是否是最好的方法,但我設法提出了一個似乎運作良好的解決方案。

關鍵是匹配請求將其轉換為AccountWrappedRequest內的invokeBlock然后再將其傳遞給下一個請求。 如果鏈中的另一個Action期望來自鏈中較早操作的值,則可以類似地將請求轉換為您需要訪問請求參數的類型。

從原始問題更新示例:

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) 
}

然后在另一個Action(在我的情況下為Authenticated操作apply()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"))
  }
}

您可以在ActionBuilder中將操作鏈接在一起

override def composeAction[A](action: Action[A]) = Account(Authenticated(action))

如果然后將AuthenticatedWrappedRequest傳遞給控制器​​,則可以訪問request.accountrequest.user和所有常用請求參數。

正如您所看到的,有幾種情況下響應未知會產生BadRequest 實際上,就我所知,這些應該永遠不會被調用,但它們只是在那里。

我很想得到關於這個解決方案的一些反饋,因為我對Scala還是比較新的,我不確定是否有更好的方法來做同樣的結果,但我希望這對某人也有用。

我寫了一個獨立的小(ish)示例來完成你正在尋找的東西:

https://github.com/aellerton/play-login-example

我放棄了嘗試使用play框架中存在的Security類。 我相信他們很好,但我無法理解他們。

簡要指南......

在示例代碼中,控制器聲明為使用AuthenticatedRequests特征:

object UserSpecificController extends Controller with AuthenticatedRequests {
  ...
}

使用RequireAuthentication操作強制任何頁面要求身份驗證(或重定向以獲取它):

def authenticatedIndex = RequireAuthentication { implicit request: AuthenticatedRequest[AnyContent] =>
  Ok("This content will be accessible only after logging in)
}

使用AbandonAuthentication操作完成AbandonAuthentication

def signOut = AbandonAuthentication { implicit request =>
  Ok("You're logged out.").withNewSession
}

請注意,為此,您必須覆蓋AuthenticatedRequests特征中的方法,例如:

override def authenticationRequired[A](request: Request[A]): Future[SimpleResult] = {
  Future.successful(
    Redirect(routes.LoginController.showLoginForm).withSession("goto" -> request.path)
  )
}

還有更多; 最好看看代碼。

HTH安德魯

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM