2

我是 play2.0-Scala 初学者,必须调用多个 Web 服务来生成 HTML 页面。

在阅读了The Play WS API页面和来自 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 表达式之后的额外 - 有点困惑。)我应该写这样的东西吗?

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 状态代码)。

也许有人知道在 play framework 中调用 webservices 的完整示例(在 play Sample applications 或其他任何地方都找不到示例)。

4

1 回答 1

2

不得不说,您在图2中展示的示例中的文章是错误的。该方法focusOnOk在Play 2.0中不存在。我假设文章的作者当时使用的是 Play 2 的预发布版本。

关于comment,是的,应该是commentsfold语句中的Either. 它需要2个函数作为参数。第一个是如果它是左值则应用的函数。第二个是一个函数,如果它是一个正确的值。更详细的解释可以在这里找到:http: //daily-scala.blogspot.com/2009/11/either.html

所以这条线的作用是。如果我有一个左值(这意味着我得到了一个不想要的响应),应用内置identity函数,它只会给你返回值。如果它具有正确的值(这意味着我得到了 OK 响应),请创建一个以某种方式显示评论的新结果。

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

至于图 4,尾随}实际上是因为它是图 3 中的部分替代品。而不是众多的 promise flatMap。你可以做一个for 理解。另外,我认为它应该userInfo(...).map代替actorInfo(...).map.

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

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

将获得 feedUrl 中的任何内容,然后您可以使用该字段map执行某些操作,您可以检查它是否为 404 或其他内容。responsestatus

为此,链接文章的图 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)
    }
  }
}
于 2012-09-03T16:00:13.023 回答