java嵌套的http调用api库

时间:2014-06-18 23:15:41

标签: java web-services api web playframework

我正在阅读playframework中的一些http webservice api,链接如下。

我无法理解这种嵌套如何使用flatmap。

有人可以给我一些提示,如何打击这一大块函数调用。

来自http://www.playframework.com/documentation/2.2.x/JavaWS

撰写结果 如果您想按顺序拨打多个电话,
这可以使用flatMap来实现:

public static Promise<Result> index() {
    final Promise<Result> resultPromise = WS.url(feedUrl).get().flatMap(
           new Function<WS.Response, Promise<Result>>() {
                public Promise<Result> apply(WS.Response response) {
                    return WS.url(response.asJson().findPath("commentsUrl").asText()).get().map(
                        new Function<WS.Response, Result>() {
                            public Result apply(WS.Response response) {
                                return ok("Number of comments: " + response.asJson().findPath("count").asInt());
                            }
                        }
                );
            }
        }
);
    return resultPromise;
}

1 个答案:

答案 0 :(得分:1)

flatMapmap是常见的Scala(或更常见的函数式编程)函数。它们都接受函数作为参数。为了将Play WS API转换为Java(以及其他所有内容),需要在Java中重新实现Scala的函数类型,以便您可以充分利用WS库。它在这里以与Scala编译器类似的方式完成。 Function<A,B>是一种需要apply方法的抽象类型。 apply的参数是函数的参数,apply的返回类型是函数的参数。

如果你在Java中有这个功能:

public String int2String(Integer integer) {
    return integer.toString();
}

这相当于:

new Function<Integer, String>() {
    public String apply(Integer integer) {
        return integer.toString();
    }
}

在一次WS调用的情况下,让我们开始更简单。 WS.url(...).get()会返回Promise<WS.Response>Promise承诺的值的容器类。为了处理它包含的值(或最终包含的值),我们需要使用map函数。对于Promise<WS.Response>map会接受Function<WS.Response, T>作为参数,其中T是您要将响应映射到的类型。

例如,让我们定义一个Function,它只返回Play HTTP WS.ResponseResult的正文:

Function<WS.Response, Result> echo = new Function<WS.Response, Result>() {
    public Result apply(WS.Response response) {
        return ok(response.asText());
    }
}

现在让我们在控制器的WS调用中使用这个Function

public static Promise<Result> index() {

    final Promise<Result> resultPromise = WS.url("http://google.com").get().map(echo);

    return resultPromise;

}

完成Promise后,之前定义的echo函数将在map内执行,并返回Promise<Result>。前面两个代码块也可以这样编写(与匿名函数合并为一个):

public static Promise<Result> index() {

    final Promise<Result> resultPromise = WS.url("http://google.com").get().map(
        new Function<WS.Response, Result>() {
            public Result apply(WS.Response response) {
                return ok(response.asText());
            }
        }
    );

    return resultPromise;
}

作为一个粗略的例子,让我们说我们需要进行两次WS调用。第二个WS调用将取决于第一个。也许第一次调用会给我们一些URL,我们将使用它来进行第二次WS调用。

这是flatMap出现的地方。我们需要两个函数来完成这个任务。第一个函数是传递给flatMap的函数,它将在收到第一个WS.Response时执行。第一个函数将使用第一个响应来进行第二个WS调用,该调用返回另一个必须映射的Promise<WS.Response>以获得我们的最终结果。因此,我们map第二个结果,第二个函数将WS.Response转换为我们的Result

那发生了什么?如果我们在两个实例中都使用了map而不是flatMap,那么事件链将会是这样的:

第一个get()返回Promise<WS.Response>,然后我们map包含WS.ResponsePromise<Result>。但是,这会给我们留下Promise<Promise<WS.Response>>,这不是很理想。在外部函数中使用flatMap会将Promise展平为单个Promise<Result>。 Simiarly,如果你正在做3个或更多嵌套调用,你会map每个结果都是一个内部函数,并且在外层只有一个flatMap来压扁所有内容。

这一切当然在斯卡拉看起来更加美丽。