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 フレームワークの経験不足を悪用してください...