Playframework 控制器外部的异步WS-calls和Wait()

Playframework 控制器外部的异步WS-calls和Wait(),playframework,Playframework,有没有办法在控制器之外使用await()机制 我不希望让代码在控制器中进行异步调用,而是将代码放在可由多个控制器重用的服务类中。然而,由于该方法受到保护,因此无法在控制器外部调用wait 例如,在控制器中: ServiceClass service = new My ServiceClass(); MyObject myObject= service.getMeAnObject(); render(myObject); 服务级别: public class Servic

有没有办法在控制器之外使用await()机制

我不希望让代码在控制器中进行异步调用,而是将代码放在可由多个控制器重用的服务类中。然而,由于该方法受到保护,因此无法在控制器外部调用wait

例如,在控制器中:

   ServiceClass service = new My ServiceClass();
   MyObject myObject= service.getMeAnObject();
   render(myObject);
服务级别:

   public class ServiceClass
   {
      ...
      public MyObject getMeAnObject()
      {
         String url = "http://...";
         Promise<HttpResponse> promise = url(url).getAsync();

         // do something here similar to await in a controller
         // that suspends the code waiting for the response
         // to be retrieved

         HttpResponse response = promise.get();
         return buildMyObjectFromResponse(reponse);
      }
      ...
   }
公共类服务类
{
...
公共MyObject getMeAnObject()
{
字符串url=”http://...";
Promise Promise=url(url).getAsync();
//在这里执行类似于在控制器中等待的操作
//这将暂停代码等待响应
//取回
HttpResponse response=promise.get();
返回buildMyObjectFromResponse(response);
}
...
}
有没有办法做到这一点

谢谢你的帮助


编辑:我遵照Pere的建议,让服务类实现了控制器,它可以工作,但是,有必要对使用它的控制器进行增强。我发现完成该任务的唯一方法是在调用控制器类中至少调用一次wait method()

但是,我仍然没有验证代码是否实际挂起


编辑2:我从谷歌集团得到的一个建议是,我应该真正尝试在控制器中执行等待操作,因此可能更好的解决方案是让服务返回 承诺并让控制员等待,但是 我没办法这么做,是吗

例如,在控制器中:

  ServiceClass service = new My ServiceClass(); 
  Promise<MyObject> promise = service.getMeAnObject(); 
  MyObject myObject = await(promise); 
  render(myObject); 
ServiceClass service = new My ServiceClass(); 
Promise<MyObject> promise = service.getMeAnObject(); 
MyObject myObject = await(promise); 
render(myObject); 
ServiceClass服务=新建我的ServiceClass();
Promise Promise=service.getMeAnObject();
MyObject MyObject=等待(承诺);
渲染(myObject);
服务级别:

  public class ServiceClass 
  { 
     ... 
     public Promise<MyObject> getMeAnObject() 
     { 
        String url = "http://..."; 
        // Somehow Build a Promise<MyObject> 
     } 
     ... 
  } 
public class ServiceClass 
{ 
    public Promise<MyObject> getMeAnObject() 
    { 
        String url = "http://..."; 
        return execute(WS.url(url).getAsync()); 
    } 

    private Promise<MyObject> execute(final Promise<HttpResponse> promise) 
    { 
        try 
        { 
            final Promise<MyObject> smartFuture = new Promise<MyObject>(); 
            ScheduledThreadPoolExecutor executor = MyAppThreadPools.getServiceThreadPool(); 

            executor.submit(new Runnable() 
                { 
                    @Override 
                    public void run() 
                    { 
                        try 
                        { 
                            smartFuture.invoke(new MyObject(promise.get())); 
                        } 
                        catch (Throwable e) 
                        {                
                            smartFuture.invokeWithException(e); 
                        } 
                    } 
                });

            return smartFuture; 
        } 
        catch (Exception e) 
        { 
            throw new RuntimeException(e); 
        } 
    } 
}
公共类服务类
{ 
... 
公共承诺getMeAnObject()
{ 
字符串url=”http://..."; 
//以某种方式建立一个承诺
} 
... 
} 
}

如您所述,Wait只能从控制器访问

使服务类扩展控制器,在其中创建许多受保护的支持方法,并将其用作控制器的父类


通过这种方式,您可以跨控制器共享实现,同时可以访问所有控制器方法(wait、render等)。

到目前为止,我认为这是我发现的最好的方法,除非在Play实例中管理单独的线程池有问题

我已经举例说明了Play在WSAsync.WSAsync请求中的作用 这似乎是有效的

本质上,等待是在控制器内完成的,但是服务类返回我期望服务返回的对象的承诺,这很好,因为我不知道如何在控制器级别检索该对象的细节

在控制器中:

  ServiceClass service = new My ServiceClass(); 
  Promise<MyObject> promise = service.getMeAnObject(); 
  MyObject myObject = await(promise); 
  render(myObject); 
ServiceClass service = new My ServiceClass(); 
Promise<MyObject> promise = service.getMeAnObject(); 
MyObject myObject = await(promise); 
render(myObject); 
ServiceClass服务=新建我的ServiceClass();
Promise Promise=service.getMeAnObject();
MyObject MyObject=等待(承诺);
渲染(myObject);
服务级别:

  public class ServiceClass 
  { 
     ... 
     public Promise<MyObject> getMeAnObject() 
     { 
        String url = "http://..."; 
        // Somehow Build a Promise<MyObject> 
     } 
     ... 
  } 
public class ServiceClass 
{ 
    public Promise<MyObject> getMeAnObject() 
    { 
        String url = "http://..."; 
        return execute(WS.url(url).getAsync()); 
    } 

    private Promise<MyObject> execute(final Promise<HttpResponse> promise) 
    { 
        try 
        { 
            final Promise<MyObject> smartFuture = new Promise<MyObject>(); 
            ScheduledThreadPoolExecutor executor = MyAppThreadPools.getServiceThreadPool(); 

            executor.submit(new Runnable() 
                { 
                    @Override 
                    public void run() 
                    { 
                        try 
                        { 
                            smartFuture.invoke(new MyObject(promise.get())); 
                        } 
                        catch (Throwable e) 
                        {                
                            smartFuture.invokeWithException(e); 
                        } 
                    } 
                });

            return smartFuture; 
        } 
        catch (Exception e) 
        { 
            throw new RuntimeException(e); 
        } 
    } 
}
公共类服务类
{ 
公共承诺getMeAnObject()
{ 
字符串url=”http://..."; 
返回execute(WS.url(url.getAsync());
} 
私人承诺执行(最终承诺)
{ 
尝试
{ 
最终承诺smartFuture=新承诺();
ScheduledThreadPoolExecutor=MyAppThreadPools.getServiceThreadPool();
执行者提交(新的可运行()
{ 
@凌驾
公开募捐
{ 
尝试
{ 
调用(新的MyObject(promise.get());
} 
捕获(可丢弃的e)
{                
智能未来。调用异常(e);
} 
} 
});
回归未来;
} 
捕获(例外e)
{ 
抛出新的运行时异常(e);
} 
} 
}
这似乎解决了我目前的问题


谢谢大家。

这可能太晚了,无法帮助您:)但方法是使用Promise.onredeme()方法调用控制器中返回和等待的新Promise

public Promise<Boolean> deauthorise() {
    final Promise<Boolean> promise = new Promise<>();

    WS.url("https://connect.stripe.com/oauth/deauthorize")
            .setParameter("client_secret", play.Play.configuration.getProperty("stripe.secretKey"))
            .setParameter("client_id", play.Play.configuration.getProperty("stripe.clientId"))
            .setParameter("stripe_user_id", this.stripeUserId)
            .postAsync()
            .onRedeem(new Action<Promise<HttpResponse>>() {
                @Override
                public void invoke(Promise<HttpResponse> result) {
                    HttpResponse response = result.getOrNull();
                    promise.invoke(response != null && response.success());
                }
            });
    return promise;
}
public Promise deauthorise(){
最终承诺=新承诺();
WS.url(“https://connect.stripe.com/oauth/deauthorize")
.setParameter(“client_secret”,play.play.configuration.getProperty(“stripe.secretKey”))
.setParameter(“client_id”,play.play.configuration.getProperty(“stripe.clientId”))
.setParameter(“stripe\u user\u id”,this.stripeUserId)
.postAsync()
.OnReceive(新操作(){
@凌驾
公共无效调用(承诺结果){
HttpResponse response=result.getOrNull();
promise.invoke(response!=null&&response.success());
}
});
回报承诺;
}

谢谢您的回复。它似乎确实起作用了。然而,在我看来,这并不是最好的解决方案,因为服务类在概念上不是控制器。理想情况下,这种代码中断机制可以在任何地方使用。