2017-09-15 43 views
0

我是新来玩框架(2.6.x)和斯卡拉。我有一个返回Future [JsValue]的函数。如何在后续函数中使用Future [JsValue]?在未来的[JsValue]中使用后续函数播放框架2.6x

def getInfo(): Future[JsValue] ={} 

以下函数将使用JsValue中的值来计算某些内容。我不得不从json响应中提取一个值。 val currentWeight = (jsValue \ "weight").as[String].toDouble

def doubleAmounts(currentWeight: Double): Double = { 
    currentWeight*2.0 
} 

什么是在这里处理未来的正确方法?我应该使用地图还是onComplete从json获取weight

我试过这个,但只有在我已经打电话给doubleAmounts()后才能解决。

val weight = getInfo() map { response => 
    if (response.toString().length > 0) (response \ "weight").as[String]) 
    else throw new Exception("didn't get response") 
} 

回答

0

的问题是,一旦你开始Futures说话,你需要保持Futures说话,这个想法是,在同一台服务器将处理所有这些等待和环境的变化,所以发挥它自身可以处理你的保证在某些情况下,你会返回结果。

因此,不要在您的控制器中调用返回Any的函数,而是可以处理Future[Any]

val weight: Future[String] = getInfo() map { response => 
    if (response.toString().length > 0) (response \ "weight").as[String]) 
    else throw new Exception("didn't get response") 
} 

如果你有几个未来的呼叫,其中每一个从其他未来需要的结果,您可以使用对于理解避免地图地狱。例如,这里是一个小更复杂的例子:

def processSync(databaseServer: DatabaseServer, databaseIdentity: DatabaseIdentity): Future[String] = { 
    val info = for { 
     catalogs <- databaseSyncService.getCatalogs(databaseServer.address, databaseServer.port, databaseIdentity.login, databaseIdentity.password) 
     clubbers <- getClubbers(databaseServer.id) 
     ignoredCatalogs <- ignoredCatalogService.get(databaseServer.id) 
    } yield (catalogs, clubbers, ignoredCatalogs) 
    val result = info.map{ 
     case(catalogs, clubbers, ignoredCatalogs) => { 
     val currentCatalogs = (clubbers.map(clubber => 
      Seq(Some(clubber.mainSchema), clubber.archiveSchema, clubber.blacklistSchema, clubber.logsSchema).flatten 
     ).flatten ++ ignoredCatalogs).toSet 
     val serverCatalogs = catalogs.toSet 
     if(currentCatalogs == serverCatalogs) { 
      "synchronized" 
     } else { 
      "outOfSync" 
     } 
     } 
    }.recover{ 
     case sqlE: SQLServerException =>{ 
     logger.error(s"Conection error with ${databaseServer.name}", sqlE) 
     "connectionError" 
     } 
    } 
    for{ 
     realResult <- result 
     _ <- databaseServerRepo.updateSync(databaseServer.id, realResult) 
    } yield realResult 
    } 

在每个值是未来,但吼叫我们就可以访问自己的价值,在的对,你用得到目的,以纪念什么需要被退回。

其他示例可以是该控制器调用(忽略shilouete部分,是一种认证库,简单地认为返回类型作为未来[结果]):

def sync(id: Int) = silhouette.SecuredAction.async { implicit request: SecuredRequest[DefaultEnv, AnyContent] => 
    val actions = for { 
     (server, identity) <- databaseServerService.getWithIdentity(id) 
     databaseCatalogs <- databaseSyncService.getCatalogs(server.address, server.port, identity.login, identity.password) 
     ignoredCatalogs <- ignoredCatalogService.get(id) 
     clubberIntegrations <- clubberIntegrationService.getClubbersListOrAutoFill(id, databaseCatalogs, ignoredCatalogs.map(_.name)) 
    } yield Future.successful { 
     val catalogs = databaseCatalogs.map { x => 
     val ignoredCatalogNotes = ignoredCatalogs.filter(_.name == x).map(_.note).headOption 
     DatabaseCatalog(x, ignoredCatalogNotes.getOrElse(""), ignoredCatalogNotes.isDefined) 
     } 
     Ok(web.databaseserver.views.html.databaseServerSync(request.identity, server, DatabaseServerForSync(clubberIntegrations, catalogs))) 
    } 
    actions.recover { 
     case _: SQLServerException => { 
     databaseServerService.getName(id).map(x => { 
      Redirect(web.databaseserver.controllers.routes.DatabaseServerController.list()) 
      .flashing("error" -> Messages("databaseSync.couldNotConnect", x)) 
     }) 
     } 
    }.flatMap(x => x) 
    } 

另外,我忘了提,如果您需要处理使用Future和其他功能的函数,则可以使用Future.successful来转换后者,也可以使用Future.sequenceSeq[Future[Any]]转换为Future[Seq[Any]]和其他函数,以帮助您以不同方式处理期货。