播放Scala 2.4链接异步调用

时间:2015-06-11 13:01:22

标签: scala asynchronous playframework playframework-2.0

我正在试图弄清楚如何链接多个异步调用并返回结果。我目前正在尝试异步用户数据,并异步更新用户数据并返回结果,但似乎它无法正常工作:( 我用map {result =>好的(结果)},但是游戏仍然认为我正在返回一个对象。有什么帮助吗?

Cache-Control: max-age=86400

我遇到问题的主要部分是这一部分。我认为这是一些语法问题。有人可以帮忙吗? 感谢

def updateUserData() = Action.async { implicit request =>
updateUserForm.bindFromRequest.fold(
errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
{
  case (userData) =>
    request.session.get("email") match {
      case Some(email) =>
        getUser(email, userData.curent_password) map { userCheck =>
          if (userCheck) {
            updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
              Ok("please")
            }
            //val e = updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map {result => Ok("")}

            // user is valid now update the user data

            // call removeAuth to log out

            // redirect to home
            ///Ok (updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result => result})
            //Redirect(routes.settings.index()).addingToSession("email" -> email)
          } else {
            BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
          }
        }
      }
  })
}

1 个答案:

答案 0 :(得分:4)

问题在于您的类型,并且它们与所需的类型不匹配。

.fold必须在两个分支中产生Future[Result](错误和成功分支)。

在成功的表单绑定分支中,您有:

case (userData) => ... // The ... must evaluate to Future[Result]

看看你的第一个操作,我们看到:

request.session.get("email") match {
  case Some(email) => ...
}

这里的一个重要问题是None案件未得到处理! (但这不会导致类型不匹配)。如下所示将解决此问题:case None => Future.successful(BadRequest(...))

继续前进:在Some中你有以下内容:

getUser(email, userData.curent_password) map { userCheck =>
  if (userCheck) {
    updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
       Ok("please")
    }
  } else {
    BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option("")))
  }
}

这就是问题所在:

getUser将返回Future[X],当您映射时,您将Future[Y] YuserCheck => ...评估的内容。

在这种情况下,类型完全混淆,因为当您在真正的分支上if(usercheck)时,您在假分支上有Future[Result] Result。因此类型不会在两个分支上对齐,这是一个很大的问题,编译器会从中推断Any

要解决此问题,请在假分支中创建未来:Future.successful(BadRequest(....))

好的,既然我们已经修复了最内在的类型问题,那么让我们开始倒退。如果我们返回一个级别(Future[Result]之前),那么我们将getUser()内部Future[Future[Result]]。这不是我们想要的,因为我们需要Future[Result]

对此的解决方案是flatMap而不是map,因为当您需要使用相同的容器类型返回并使其展平时使用flatMap。一个简单的例子来理解这一点:

Seq(1, 2, 3).flatMap(i => Seq(i, i))
// res0: Seq[Int] = List(1, 1, 2, 2, 3, 3)

如果是Future s:

import scala.concurrent.Future   
import scala.concurrent.ExecutionContext.Implicits.global
Future(1).flatMap(i => Future(i*2))
// res1: scala.concurrent.Future[Int] = [....]

因此,我们发现我们没有双重嵌套,只有一个Future

回到你的例子,这将是我更新的代码,可以更好地工作:

def updateUserData() = Action.async { implicit request =>
  updateUserForm.bindFromRequest.fold(
    errors => Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(errors, Option(""), Option("")))),
    {
      case (userData) =>
        request.session.get("email") match {
          case Some(email) =>
            getUser(email, userData.curent_password).flatMap { userCheck =>
              if (userCheck) {
                updateUserOnService(email, userData.f_name, userData.l_name, userData.new_password) map { result =>
                  Ok("please")
                }
              } else {
                Future.successful(BadRequest(views.html.authenticated.settings.settings_hero(updateUserForm.bindFromRequest.withGlobalError(Messages("error.login", email)), Option(""), Option(""))))
              }
            }
        case None => Future.successful(BadRequest) // FIXME: Implement as you wish
        }
    })
}