Как создать действия в Google с использованием Spring Boot и библиотеки Java

#java #spring-boot #actions-on-google

#java #spring-загрузка #действия в Google

Вопрос:

Я пытаюсь создать действия в Google с помощью Spring Boot amp; Dialogflow. В котором я пытался использовать доступную библиотеку Javahttps://github.com/actions-on-google/actions-on-google-java

Но не смог понять, как мне реализовать эти аннотации в моем приложении Spring Boot. Например: @ForIntent

Я попробовал шаблонный код с точкой входа в App Enginehttps://github.com/actions-on-google/dialogflow-webhook-boilerplate-java Я смог запустить этот код, но не смог понять его реализацию в приложении Spring boot.

При загрузке Spring: мы используем @RestController в приложении для сопоставления запросов

Но с действиями в Google была бы только одна ссылка на запрос, мы можем предоставить в качестве веб-крючка для выполнения. Итак, где я должен использовать @ForIntent в моем коде, чтобы определить намерение и изменить тело запроса и тело ответа.

Ответ №1:

Я действительно сделал это в какой-то момент и основал его на примере Silly Name Maker. Я основал его на одном из канонических образцов Spring Boot, поэтому я не собираюсь гарантировать, что это «оптимально», но это довольно чистая реализация.

Вы можете оставить SillyNameMakerApp тот же самый, неизмененный. Вместо ActionsServlet вы можете создать оболочку Spring Boot, подобную этой:

 @SpringBootApplication
public class HelloworldApplication {
    private static final Logger LOG = LoggerFactory.getLogger(SillyNameMakerApp.class);
    private final App actionsApp = new SillyNameMakerApp();

    @Value("${TARGET:World}")
    String message;

    @RestController
    class HelloworldController {
        @GetMapping("/")
        String serveAck() {
            return "App is listening but requires valid POST request to respond with Action response.";
        }

        @RequestMapping(value = "/", method = RequestMethod.POST, produces = { "application/json" })
        String serveAction(@RequestBody String body, @RequestHeader Map<String, String> headers) {
            try {
                return actionsApp.handleRequest(body, headers).get();
            } catch (InterruptedException | ExecutionException e) {
                return handleError(e);
            }
        }

        private String handleError(Exception e) {
            e.printStackTrace();
            LOG.error("Error in App.handleRequest ", e);
            return "Error handling the intent - "   e.getMessage();
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(HelloworldApplication.class, args);
    }
}
  

Ответ №2:

Я не в курсе, как работает действие в Google, но, взглянув на это на более высоком уровне, в примере приложения запросы обрабатываются через ActionServlet

https://github.com/actions-on-google/dialogflow-webhook-boilerplate-java/blob/master/src/main/java/com/example/ActionsServlet.java

The ActionServlet.java класс, расширяет обычный старый Java-сервлет, называемый HttpServlet, если вы заглянете внутрь метода doPost():

 private final App actionsApp = new MyActionsApp(); ----> Bullet Point - 1

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
    String body = req.getReader().lines().collect(Collectors.joining());
    LOG.info("doPost, body = {}", body);

    try {
      String jsonResponse = actionsApp.handleRequest(body, getHeadersMap(req)).get(); ----> Bullet Point - 2
      LOG.info("Generated json = {}", jsonResponse);
      res.setContentType("application/json");
      writeResponse(res, jsonResponse);
    } catch (InterruptedException e) {
      handleError(res, e);
    } catch (ExecutionException e) {
      handleError(res, e);
    }
  }
  

Итак, ваш вопрос заключается в том, как сделать то же самое в Spring Boot. Spring использует DispatcherServlet для сопоставления входящих запросов с контроллерами, поэтому внутренне spring использует аналогичные механизмы для сопоставления входящих запросов. Чтобы ответить на ваш вопрос, в терминологии Spring Boot, вы хотите сделать что-то вроде приведенного ниже:

 @RestController("/action")
public class ActionController{

    @Autowired
    private App actionsApp;

    @PostMapping("/")
    public void handleActions(){
       // Similar method call like Bullet Point 2
       // I assume handleRequest() method will call the @ForIntent method here ?? No idea
       actionsApp.handleRequest(.....);
    }
}
  

И настройте MyActionsApp.java , как показано ниже:

  @Service
public class MyActionsApp extends DialogflowApp {

  private static final Logger LOGGER = LoggerFactory.getLogger(MyActionsApp.class);

  @ForIntent("Default Welcome Intent")
  public ActionResponse welcome(ActionRequest request) {
    LOGGER.info("Welcome intent start.");
    ResponseBuilder responseBuilder = getResponseBuilder(request);
    ResourceBundle rb = ResourceBundle.getBundle("resources");
    User user = request.getUser();

    if (user != null amp;amp; user.getLastSeen() != null) {
      responseBuilder.add(rb.getString("welcome_back"));
    } else {
      responseBuilder.add(rb.getString("welcome"));
    }

    LOGGER.info("Welcome intent end.");
    return responseBuilder.build();
  }

  @ForIntent("bye")
  public ActionResponse bye(ActionRequest request) {
    LOGGER.info("Bye intent start.");
    ResponseBuilder responseBuilder = getResponseBuilder(request);
    ResourceBundle rb = ResourceBundle.getBundle("resources");

    responseBuilder.add(rb.getString("bye")).endConversation();
    LOGGER.info("Bye intent end.");
    return responseBuilder.build();
  }
}
  

PS: Я предполагаю, что метод actionsApp.handleRequest(..) каким-то образом вызовет @ForIntent на основе какой-то другой конфигурации. Но если вы хотите перенести реализацию ActionServlet на SpringBoot, это было бы способом сделать это.

Дайте мне знать, работает это или нет.

Комментарии:

1. Спасибо за прекрасное объяснение. Да, это правильный способ.