Spring boot 从服务中的回调返回响应

问题描述 投票:0回答:2

我正在尝试使用 Spring boot 开发示例 Rest API 应用程序来测试我的 java 客户端库(这是 JS 客户端的转换)。 Java 客户端执行一些异步任务并返回响应作为回调。

这是我如何从示例应用程序的服务中调用它的示例。

@Async
public void initializeUser(InitRequest initRequest) {

    String BASE_URL = "http://sample_url";

    client.initUser(BASE_URL, initRequest, new ResponseCallback<InitRequest>() {

        @Override
        public void onSuccess(@NonNull InitRequest arg0) {
            // Return arg0 to controller
            System.out.println("User Initialized: " + arg0.getId());
        }

        @Override
        public void onError(@NonNull ResponseBody error) { 
            // Return error to controller
            System.out.println("User Initialize failed");
        }

        @Override
        public void validationError(@NonNull String arg0) {
             // return validationError to controller
            // TODO Auto-generated method stub

        }
    });
}

这里 initUser 是在我的客户端中实现的方法。当我从控制器调用此方法时。控制器在实际请求完成之前返回,我在邮递员中看不到任何响应。

这是一个控制器方法。

@RequestMapping(method=RequestMethod.POST, value = "/init" )
public void initUser( @RequestBody InitRequest initRequest) {
    experimentServices.initializeUser(initRequest);
    // wait for request to finish and send response to user
}

就像在 javascript 中一样,我可以使用 Promise 或 async/await 等待服务给出响应,然后再返回给用户。

我想知道......

1)如何在Java中实现类似的功能? (服务将一些数据返回给控制器,然后将其作为对最终用户的响应)。

2) Java 方法需要特定的返回响应,而服务可能会给出 Error、ValidationError 或 Successl 响应对象。有没有办法在一个函数中正确处理所有这些?

任何链接或文档都会有帮助。 谢谢

java spring spring-boot spring-rest
2个回答
0
投票

在您的代码中,您异步调用的方法是一个 void 方法,这意味着它不会返回任何内容。在 Spring 中,使用

@Async
注释 bean 的方法将使其在单独的线程中执行,即调用者将不等待被调用方法的完成。

所以,如果你想让控制器等待执行完成,如果你想等待结果我建议你使用

Future
。您可以采取将实际返回包装在
Future
实例中的方法。我还没有尝试编译此代码,但如下所示:

@Async
public Future<T> initializeUser(InitRequest initRequest) {

    String BASE_URL = "http://sample_url";

    client.initUser(BASE_URL, initRequest, new ResponseCallback<InitRequest>() {

        @Override
        public void onSuccess(@NonNull InitRequest arg0) {
            return new AsyncResult<InitRequest>(arg0);
            System.out.println("User Initialized: " + arg0.getId());
        }

        @Override
        public void onError(@NonNull ResponseBody error) { 
            return new AsyncResult<ResponseBody>(error);
            System.out.println("User Initialize failed");
        }

        @Override
        public void validationError(@NonNull String arg0) {
             return new AsyncResult<String>(arg0);
            // TODO Auto-generated method stub

        }
    });
}

并在其余控制器中接收此信息:

@RequestMapping(method=RequestMethod.POST, value = "/init" )
public InitRequest initUser( @RequestBody InitRequest initRequest) {
  Future<T> futureResult = experimentServices.initializeUser(initRequest);
  // wait for request to finish and send response to user
  if (futureResult.isDone()) {
      return futureResult.get();
  }
}

0
投票

最好的方法是避免服务器忙于等待,所以使用 DeferredResult:

private ExecutorService executor = ....

@RequestMapping(method=RequestMethod.POST, value = "/init" )
public DeferredResult<ResponseEntity<InitResponse>> initUser(@RequestBody InitRequest initRequest) {
    final DeferredResult<ResponseEntity<InitResponse>> output = new DeferredResult<>(5000L, 5000L);
    executor.submit(() -> {
        InitResponse response = processAndcreateRespnse(...);
        output.setResult(new ResponseEntity<>(response, HttpStatus.OK));
    });

    return output;
}
© www.soinside.com 2019 - 2024. All rights reserved.