1

假设在我的 Controller 中有一组Sms对象。对于这些对象中的每一个,我想调用一个 Web 服务,然后对于所有成功的调用返回 sms 对象以进行查看。

控制器:

def inviteBySms() = Action {
    implicit request => {
      val smsSet = getSet()
      Async {
        smsSet.map(sms => callSmsService(sms).map(response => {
          response.status match {
            case 200 => {
              // somehow add the sms object to a success set  
            }
            case _ => {
              // ignore
            }
          }
        }))
      // Return Ok() with the success Set[SMS]
      }
    } 

}

控制器中的方法:

def postToService(sms: Sms) = {

    val params = Map(Seq(current.configuration.getString("sms.service.user").getOrElse("")),
          "pass" -> Seq(current.configuration.getString("sms.service.password").getOrElse("")),
          "mobilephone" -> Seq(sms.number))
        )


    val futureResponse = WS.url(Play.current.configuration
          .getString("sms.service.url").getOrElse(""))
          .withHeaders("Content-Type" -> "application/x-www-form-urlencoded; charset=utf-8")
          .post(params)
}
4

2 回答 2

1

经过进一步讨论,这是比我第一次尝试最正确的答案。

在我的代码中,我刚刚将 Sms 定义为type Sms = String,我只是直接调用 WS.url().get 就可以了。

首先,callSmsService(sms: Sms)应该调用服务而不是返回Response但已经返回map()取决于返回是否为 200。我们的想法是返回原始Sms实例,None以便我们以后可以聚合它们:

def callSmsService(sms: Sms): Future[Option[Sms]] = {
  WS.url(sms).get
    .map { 
      response => if (response.status == 200) Some(sms) else None
    }
}

您现在map()可以使用此功能设置初始短信:

val futureOptionSet: Set[Future[Option[Sms]]] = smsSet.map { sms => callSmsService(sms) }

然后,您必须将 theSet[Future]转换为全局Future[Set](您需要一个独特的 Future 来构建Future[Result]ask by Async{...}):

val optionSetFuture: Future[Set[Option[Sms]]] = Future.sequence(futureOptionSet)

现在,您可以映射全球 Future 以仅收集成功的短信

val smsSetFuture: Future[Set[Sms]] = optionSetFuture.map { set => set.collect { case Some(sms) => sms }}

有了这个最后Future,您现在可以执行 amap()来构建一个Future[Response]

smsSetFuture.map( successfulSmsSet: Set[Sms] => {
  // do something with successfulSmsSet
  ok(...) 
})

我已经详细介绍了显式返回类型,但您当然可以在没有中间值和显式类型的情况下组合几个步骤。

于 2013-05-24T19:01:29.243 回答
0

首先,我会打电话:

smsSet.map(sms => callSmsService(sms))

得到一个 Set[Future[Response]] 并用 Future.sequence 包装它以获得一个 Future[Set[Response]] :

Future.sequence(smsSet.map(sms => callSmsService(sms)))

然后在 Future[Set[Response]] 上,您可以 filter() 和 map() 获得 Future[Set[SMS]]

val futureSetSms = Future.sequence(smsSet.map(sms => callSmsService(sms)))
   .filter{_.status == 200}
   .map(response => {...construct your SMS...})

然后,您只需将其映射到可供 Async{} 使用的 Future[Result] :

futureSetSms.map { smsSet => Ok(...) }
于 2013-05-24T14:14:49.513 回答