#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
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. Спасибо за прекрасное объяснение. Да, это правильный способ.