Play Framework 2 - 调用Web服务并返回一个对象

时间:2013-06-13 20:01:05

标签: java playframework-2.0

我有一个模型,我希望从Web服务中填充详细信息。我想异步这样做,以免阻塞服务器线程。我们假装它是一个登录服务。

现在我要做的是向远程服务器发出请求并最终返回User模型对象。所以方法签名看起来像这样:

public static User loginUser(String username, String password) {

我理解为了对Web服务进行异步调用,我应该使用Promise

Promise<WS.Response> wsPromise = WS.url("http://myserver.com/login")
            .setContentType("application/json; charset=utf-8")
            .post("... the username and password ...");

尚未启动请求。我可以在此对象上调用get()来阻止对服务的调用。这有效。

为了异步执行此操作,我认为我需要映射它并以某种方式执行它。

Promise<User> resultPromise = wsPromise.map(new F.Function<WS.Response, User>() {
    @Override
    public User apply(WS.Response response) throws Throwable {
        System.out.println(response.getBody());
        return new User(... based on something extracted from the returned JSON ...);
    }
});

现在如何触发此操作?如果我在get()上拨打resultPromise,它会拨打电话,但最终会触发超时例外。我无法使用async(...)方法,因为这只会返回Result

查看其他示例(https://github.com/jroper/play-promise-presentation/blob/master/src/main/java/controllers/Application.java),这似乎是模式。即我们总是希望返回一个Result对象。但是,我无法查询Result对象,我也没有计划将该特定对象发送给用户。

实际上,这些示例似乎调用了Web服务,将JSON结果映射到对象,然后立即将它们映射回相同的JSON。当我想将用户(在我的情况下)传递回调用函数时没什么用。

老实说,我对这种异步性质有点困惑(你可能已经猜到了)。特别是,这实际上是一个阻止操作,因为我们必须等待Web服务返回响应。文档似乎表明使用Promise / Future模式可以避免这种阻塞。

底线是:如何在不阻止Play Framework服务器中的线程的情况下将Web服务调用的结果映射回模型对象?

随意滥用我对Play Framework缺乏经验......

2 个答案:

答案 0 :(得分:2)

这个答案可能为时已晚,但会发布,以防万一其他人现在仍然想知道这个问题,并希望得到问题的答案。

有两种方法可以实现这一点,即使两者都使用相同的JsonNode类:

  1. 第一个是你所期待的:“新用户(..something ...)”
  2. 在这种情况下,您可以使用JsonNode的“get”方法来获取创建User对象所需的特定数据(我的示例中的用户名和电子邮件,因为您没有指定必填字段)。

    Promise<User> resultPromise = wsPromise.map(new F.Function<WS.Response, User>() {
        @Override
        public User apply(WS.Response response) throws Throwable {
            System.out.println(response.getBody());
            return Json.fromJson(response.asJson(), User.class);
        }
    });
    
    1. 另一个选项是,如果您知道Web Service确实返回User对象的有效Json表示。
    2. 就我个人而言,我认为这个选项更容易,并且依赖于fromJson's method from Json类。

      UserControl

      我希望这个答案可以帮助人们想知道如何以一种简单的方式做到这一点。

答案 1 :(得分:1)

WS调用上的

.get().post(...)实际上触发WS调用。 (不要将WS.get()myPromise.get()混淆......它们是完全不同的。)

保持这种设计完全异步的技巧是让Promise一直向下,从Controller响应一直向下。

为此,您必须明智地使用Promise API中的map()flatMat()sequence()方法。

在您的特定情况下,您使用WS调用里面的结果来执行WS调用返回时发生的map()的代码。这就是你使用响应实际做事的地方。

这种范例在Scala中更容易使用“for comprehensions”,但在Java中仍然可以使用嵌套flatMap调用链以map调用结束。