【问题标题】:Combine CompletionStage in play framework action in Java在 Java 中将 CompletionStage 组合到 play 框架动作中
【发布时间】:2018-06-09 20:09:10
【问题描述】:

我尝试在播放框架中组合 CompletionStages,然后返回类似 ok() 的结果。这是我的设置:

AccountDao 有两种方法:

public CompletionStage<Account> getUserByEmail(String email) {
    return supplyAsync(() -> ebeanServer.find(Account.class).setUseCache(true).where().eq(EMAIL, email).findOne(), executionContext).thenApply(account -> {
        return account;
    });
}

public CompletionStage<Void> updateAccount(Account account) throws OptimisticLockException{
    return runAsync(() -> {
        ebeanServer.update(account);
    }, executionContext);
}

然后我让我的控制器执行操作:

public CompletionStage<Result> editAccount() {
    Map<String, String[]> form_values = request().body().asFormUrlEncoded();
    return CompletableFuture.completedFuture(ok());
}

所以现在在操作中我想首先执行 getUserByEmail 然后我想设置一些值并使用 updateAccount 方法更新它。如何在不阻塞播放上下文的情况下结合这两个阶段?我用 thenCompose 和 combine 尝试了不同的设置,但我不明白......

这是我的尝试之一:

public CompletionStage<Result> editAccount() {
    Map<String, String[]> form_values = request().body().asFormUrlEncoded();
    accountDao.getUserByEmail(session().get("accountEmail")).thenCompose(x -> accountDao.updateAccount(x).thenApplyAsync(account -> {
        return ok("Going to save account edits");
    }, httpExecutionContext.current()));
    return CompletableFuture.completedFuture(ok("Fehler am Ende"));
}

这里的问题是,我无法从以前访问帐户 (x),因为我无法将其设置为函数...像这样:

public CompletionStage<Result> editAccount() {
    Map<String, String[]> form_values = request().body().asFormUrlEncoded();
    accountDao.getUserByEmail(session().get("accountEmail")).thenCompose(x -> {
        //Update vars in x and then save to database
        accountDao.updateAccount(x);
    }.thenApplyAsync(account -> {
        return ok("Going to save account edits");
    }, httpExecutionContext.current()));
    return CompletableFuture.completedFuture(ok("Fehler am Ende"));
}

这里我得到错误:这个表达式的目标类型必须是一个函数接口并且plays说我必须在函数末尾包含return语句!

我只是不明白...感谢您的帮助!

@Marimuthu Madasamy 这不正是我想要的。在您的 awnser 中,我会两次更新帐户。在 accountDao.updateAccount(account) 和 accountDao.saveAccount(account) 中的 etime;我想要这样的东西:

return accountDao.getUserByEmail("mail").thenCompose(account -> {
       account.setName("NewName");
       accountDao.save(account);
    } .thenApplyAsync(voidInput -> {
        return ok("Account saved");
    }, httpExecutionContext.current()));

在这种情况下,只更新一次帐户,并且只在 httpExecutionContext 上返回结果

【问题讨论】:

    标签: java database playback completable-future completion-stage


    【解决方案1】:

    如果我正确理解您的问题,您想在updateAccount(account) 方法调用之后访问(保存?)帐户。

    由于updateAccount方法返回CompletionStage&lt;Void&gt;,当你在这个阶段调用thenApplyAsync时,输入类型只会是Void而不是Account。但是使用以下代码,您仍然可以访问从 getUserByEmail 返回的帐户,假设 updateAccount 通过您的文本“update vars in x”改变帐户:

    public CompletionStage<Result> editAccount() {
        return accountDao
                .getUserByEmail(email)
                .thenCompose(account -> accountDao.updateAccount(account)
                        .thenApplyAsync(voidInput -> {
                            // here you still have access to the `account` from `getUserByEmail` method
                            accountDao.saveAccount(account);
                            return ok("Account saved");
                        }, httpExecutionContext.current());
    }
    

    【讨论】:

    • 我编辑了我的问题。也许您知道如何实现这一目标?
    • 我不在 CompletionStage 控制器中使用 HttpExecutionContext。但它仍然有效。你能解释一下为什么会这样吗?
    【解决方案2】:

    好的,在 Marimuthu Madasamy 的支持下,我在这里找到了自己的遮阳篷!谢谢。我试着解释一下。首先是代码:

    public CompletionStage<Result> editAccount() {
        Map<String, String[]> form_values = request().body().asFormUrlEncoded();
        return accountDao.getUserByEmail(session().get("accountEmail")).thenApply(account -> {
            System.out.println("Async get Account / "+Thread.currentThread());
            account.setCompany(form_values.get("company")[0]);
            return accountDao.updateAccount(account);
        }).thenApplyAsync(account -> {
            System.out.println("Async resutl / "+Thread.currentThread());
            return ok("Account saved normal");
        }, httpExecutionContext.current()).exceptionally(e ->{
            System.out.println("Async exception / "+Thread.currentThread());
            System.out.println(e.getLocalizedMessage());
            return ok(e.getLocalizedMessage());
        });
    }
    

    好的,首先我执行 accountDao.getUserByEmail(),正如您在我的 awnser 顶部看到的那样,它返回 CompletionStage 并在我的数据库执行上下文中执行。接下来使用 thenApply 我得到结果并执行下一个异步方法。我使用 thenApply 代替 thenApplyAsync ,因此下一个调用也使用数据库执行上下文执行,而无需显式设置。在 accountDao.updateAccount() 之后,我在 httpExecutionContext 上执行下一阶段以重播结果或异常退出!我真的希望它很清楚并且可以帮助一些人!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-04
      • 2014-06-19
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多