从play 2调用多个Web服务

时间:2012-09-03 11:01:18

标签: web-services scala playframework-2.0

我是play2.0-Scala-beginner,必须调用多个Webservices来生成HTML页面。

在阅读The Play WS API页面和非常有趣article from Sadek Drobi之后,我仍然不确定实现此目标的最佳方法是什么。

这篇文章展示了一些我不完全理解为Play初学者的代码片段。

第4页的图2:

val response: Either[Response,Response] =
  WS.url("http://someservice.com/post/123/comments").focusOnOk

val responseOrUndesired: Either[Result,Response] = response.left.map {
  case Status(4,0,4) => NotFound
  case Status(4,0,3) => NotAuthorized
  case _ => InternalServerError
}

val comments: Either[Result,List[Comment]] = 
responseOrUndesired.right.map(r => r.json.as[List[Comment]])

// in the controller
comment.fold(identity, cs => Ok(html.showComments(cs)))

fold的最后一行是做什么的? commentcomments吗?我没有在Async块中对最后一个语句进行分组吗?

图4显示了如何将多个IO调用与单个for - 表达式组合在一起:

for {
  profile <- profilePromise
  events <- attachedEventsPromise
  articles <- topArticlesPromise
} yield Json.obj(
  "profile" -> profile,
  "events" -> events,
  "articles" -> articles )

}

// in the controller
def showInfo(...) = Action { rq =>
  Async {
    actorInfo(...).map(info => Ok(info))
  }
}

如何使用此代码段? (在for-expression之后,我对额外的}感到有点困惑。) 我应该写这样的东西吗?

var actorInfo = for {                // Model
  profile <- profilePromise
  events <- attachedEventsPromise
  articles <- topArticlesPromise
} yield Json.obj(
  "profile" -> profile,
  "events" -> events,
  "articles" -> articles )

def showInfo = Action { rq =>         // Controller
  Async {
    actorInfo.map(info => Ok(info))
  }
}

结合图2和图4中的片段(错误处理+ IO非阻塞调用的组合)的最佳方法是什么? (例如,如果任何被调用的web服务产生错误404,我想生成错误404状态代码。)

也许有人知道在播放框架中调用webservices的完整示例(在播放Sample应用程序或其他任何地方都找不到示例)。

1 个答案:

答案 0 :(得分:2)

我必须说在图2中显示的示例中该文章是错误的。方法focusOnOk在Play 2.0中不存在。我假设该文章的作者使用了Play 2的预发布版本。

关于comment,是的,它应该是comments。声明中的fold正在Either上运行。它需要2个函数作为参数。第一个是如果是左值则应用的函数。第二个是如果它是正确值则应用的函数。可在此处找到更详细的说明:http://daily-scala.blogspot.com/2009/11/either.html

那么这条线的作用是什么。如果我有一个左值(这意味着我得到了一个不需要的响应),请应用内置的identity函数,该函数只返回值。如果它具有正确的值(这意味着我得到了一个OK响应),请创建一个以某种方式显示注释的新结果。

关于Async,它实际上不是异步的。 focusOnOk是一个阻塞函数(来自Play 1.x的旧Java时代的残余)。但请记住,这不是有效的Play 2代码。

对于图4,尾随}实际上是因为它是图3中的部分替代。而不是许多承诺flatMap。您可以改为for comprehension。另外,我认为它应该是userInfo(...).map而不是actorInfo(...).map

您链接到的Play documentation实际上已经向您展示了一个完整的示例。

def feedTitle(feedUrl: String) = Action {
  Async {
    WS.url(feedUrl).get().map { response =>
      Ok("Feed title: " + (response.json \ "title").as[String])
    }
  }  
}

将获取feedUrl上的任何内容,并map使用responsestatus字段执行某些操作,您可以检查该字段是否为404或其他内容

为此,您链接文章的图3和图4应该为您提供一个起点。所以你有类似的东西,

def getInfo(...) : Promise[String] = {
  val profilePromise = WS.url(...).get()
  val attachedEventsPromise = WS.url(...).get()
  val topArticlesPromise = WS.url(...).get()

  for {
    profile <- profilePromise
    events <- attachedEventsPromise
    articles <- topArticlesPromise
  } yield {
    // or return whatever you want
    // remember to change String to something else in the return type
    profile.name 
  }
}

def showInfo(...) = Action { rq =>
  Async { 
    getInfo(...).map { info =>
      // convert your info to a Result
      Ok(info)
    }
  }
}