Spring boot возвращает ответ от обратного вызова в сервисах - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь разработать пример приложения Rest API с использованием Spring boot для тестирования моей java клиентской библиотеки (которая является преобразованием JS клиента). Java клиент выполняет некоторые асинхронные c задачи и возвращает ответ в виде обратного вызова.

Вот пример того, как я вызываю его из службы моего примера приложения.

@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 я могу использовать обещания или async / ждут, пока службы дадут ответ, прежде чем вернуться к пользователю.

Я хотел бы знать .....

1) Как добиться чего-то подобного в Java? (Службы возвращают некоторые данные контроллеру, который затем отправляется как ответ конечному пользователю.)

2) Java методам необходимо указать c ответ возврата, в то время как службы могут выдавать объект ответа Error, ValidationError или Successfull. Есть ли способ правильно обработать все это в одной функции?

Любые ссылки или документация помогут. Спасибо

1 Ответ

0 голосов
/ 31 марта 2020

В вашем коде метод, который вы вызываете асинхронно, является пустым методом, то есть он ничего не возвращает. В Spring аннотирование метода компонента с помощью @Async заставит его выполняться в отдельном потоке, т.е. вызывающая сторона не будет ждать завершения вызванного метода.

Итак, если вы хотите, чтобы контроллер дождался завершения выполнения, если вы хотите дождаться результата, я предлагаю вам использовать 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

        }
    });
}

и в контроллере rest, чтобы получить это:

@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();
  }
}
...