11

我在 PlayFramework2/Scala 中开发了一个小服务器,它必须从多个 WS(REST/JSON)中检索数据,从这些 WS 中操作数据,然后组合并返回结果。

我知道如何调用一个WS,操作数据并返回一个异步响应。但我不知道如何连续调用多个 Web 服务,处理每次调用之间的数据并生成汇总答案。

例子:

  • 从 WebService A获取我喜欢的歌曲列表
  • 然后,对于每首歌曲,从 WS B获取艺术家详细信息(按歌曲调用)
  • 然后,使用AB响应生成并返回某些内容(例如聚合列表)
  • 然后,返回结果

我被 WS API ( WS.url(url).get => Promise[Response]) 的异步处理阻塞了。我必须依靠 Akka 来解决这个问题吗?

谢谢你。

4

1 回答 1

19

flatMap并且map是你的朋友!这两种Promise类型的方法允许将 a 的结果转换Promise[A]为另一个Promise[B]

下面是一个简单的例子(我故意写了比需要更多的类型注释,只是为了帮助理解转换发生在哪里):

def preferredSongsAndArtist = Action {
  // Fetch the list of your preferred songs from Web Service “A”
  val songsP: Promise[Response] = WS.url(WS_A).get
  val resultP: Promise[List[Something]] = songsP.flatMap { respA =>
    val songs: List[Song] = Json.fromJson(respA.json)
    // Then, for each song, fetch the artist detail from Web Service “B”
    val result: List[Promise[Something]] = songs.map { song =>
      val artistP = WS.url(WS_B(song)).get
      artistP.map { respB =>
        val artist: Artist = Json.fromJson(respB.json)
        // Then, generate and return something using the song and artist
        val something: Something = generate(song, artist)
        something
      }
    }
    Promise.sequence(result) // Transform the List[Promise[Something]] into a Promise[List[Something]]
  }
  // Then return the result
  Async {
    resultP.map { things: List[Something] =>
      Ok(Json.toJson(things))
    }
  }
}

没有不必要的类型注释并使用“for comprehension”符号,您可以编写以下更具表现力的代码:

def preferredSongsAndArtist = Action {
  Async {
    for {
      // Fetch the list of your preferred songs from Web Service “A”
      respA <- WS.url(WS_A).get
      songs = Json.fromJson[List[Song]](respA.json)
      // Then, for each song, fetch the artist detail from Web Service “B”
      result <- Promise.sequence(songs.map { song =>
        for {
          respB <- WS.url(WS_B(song)).get
          artist = Json.fromJson[Artist](respB.json)
        } yield {
          // Then, generate and return something using the song and artist
          generate(song, artist)
        }
      })
    // Then return the result
    } yield {
      Ok(Json.toJson(result))
    }
  }
}
于 2012-04-03T13:11:06.513 回答