И теперь от нас ожидают ввод цифр — «Введите номер напоминания из списка.» После ввода которых они попадут в нужный метод для обработки. Вот наш переключатель состояния:
public class BotStateCash < private final MapbotStateMap = new HashMap<>(); public void saveBotState(long userId, BotState botState) < botStateMap.put(userId, botState); >>
Обычная мапа с ID пользователя и его состоянием. Поле int adminId это для меня ) Дальше логика метода handleUpdate проверят что это за сообщение? Сallbackquery или просто текст?
Если это обычный текст, то мы отправляемся в метод handleInputMessage, где мы обрабатываем кнопки основного меню, и, если на них нажали, то устанавливаем нужное состояние, если же не нажали и это незнакомый текст, то устанавливаем состояние из кэша, если его нет, то устанавливаем стартовое состояние. Дальше текст уже переходит в обработку метода handle с нужным нам состоянием. Теперь приведем логику класса MessageHandler, который отвечает за обработку сообщений в зависимости от состояния бота:
TELEGRAM BOT ТАЙМЕР | Python 3, Питон 3
public class MessageHandler < private final UserDAO userDAO; private final MenuService menuService; private final EventHandler eventHandler; private final BotStateCash botStateCash; private final EventCash eventCash; public MessageHandler(UserDAO userDAO, MenuService menuService, EventHandler eventHandler, BotStateCash botStateCash, EventCash eventCash) < this.userDAO = userDAO; this.menuService = menuService; this.eventHandler = eventHandler; this.botStateCash = botStateCash; this.eventCash = eventCash; >public BotApiMethod handle(Message message, BotState botState) < long userId = message.getFrom().getId(); long chatId = message.getChatId(); SendMessage sendMessage = new SendMessage(); sendMessage.setChatId(String.valueOf(chatId)); //if new user if (!userDAO.isExist(userId)) < return eventHandler.saveNewUser(message, userId, sendMessage); >//save state in to cache botStateCash.saveBotState(userId, botState); //if state =. switch (botState.name()) < case («START»): return menuService.getMainMenuMessage(message.getChatId(), «Воспользуйтесь главным меню», userId); case («ENTERTIME»): //set time zone user. for correct sent event return eventHandler.enterLocalTimeUser(message); case («MYEVENTS»): //list events of user return eventHandler.myEventHandler(userId); case («ENTERNUMBEREVENT»): //remove event return eventHandler.removeEventHandler(message, userId); case («ENTERDESCRIPTION»): //enter description for create event return eventHandler.enterDescriptionHandler(message, userId); case («ENTERDATE»): //enter date for create event return eventHandler.enterDateHandler(message, userId); case («CREATE»): //start create event, set state to next step botStateCash.saveBotState(userId, BotState.ENTERDESCRIPTION); //set new event to cache eventCash.saveEventCash(userId, new Event()); sendMessage.setText(«Введите описание события»); return sendMessage; case («ENTERNUMBERFOREDIT»): //show to user selected event return eventHandler.editHandler(message, userId); case («EDITDESCRIPTION»): //save new description in database return eventHandler.editDescription(message); case («EDITDATE»): //save new date in database return eventHandler.editDate(message); case («ALLEVENTS»): //only admin return eventHandler.allEvents(userId); case («ALLUSERS»): //only admin return eventHandler.allUsers(userId); case («ONEVENT»): // on/off notification return eventHandler.onEvent(message); case («ENTERNUMBERUSER»): //only admin return eventHandler.removeUserHandler(message, userId); default: throw new IllegalStateException(«Unexpected value: » + botState); >> >
в методе handle мы проверяем с каким состоянием к нас поступило сообщения и направляем его в обработчик событий – класс EventHandler. Тут у нас появилось два новых класса, MenuService и EventCash. MenuService – здесь мы создаем все наши менюшки. EventCash – аналогично как и BotStateCash будет сохранять части нашего события после ввода и когда ввод будет завершен, то мы сохраним событие в базе.
Как добавить таймер обратного отсчета в письмо
Ну т.е. когда мы наживаем создать событие, в кэш создается новый объект Event -eventCash.saveEventCash(userId, new Event()); Потом мы вводим описание события, и добавляем его в кэш:
Event event = eventCash.getEventMap().get(userId); event.setDescription(description); //save to cache eventCash.saveEventCash(userId, event);
Потом вводим число:
Event event = eventCash.getEventMap().get(userId); event.setDate(date); //save data to cache eventCash.saveEventCash(userId, event);
Класс CallbackQueryHandler аналогичен MessageHandler, только мы обрабатываем там callbackquery- сообщения.
Полностью разбирать логику работы с событиями – EventHandler не имеет смысла, уже и так слишком много букав, она понятна по названиям методов и комментариям в коде. И полностью его выкладывать текстом смысла не вижу, там больше 300 строк. Вот ссылка на класс в Github. Тоже самое касается и класса MenuService, где мы создаем наши меню. Про них можно подробно почитать на сайте производителя библиотеки telegram -https://github.com/rubenlagus/TelegramBots/blob/master/TelegramBots.wiki/FAQ.md Либо в справочнике Telegram — https://tlgrm.ru/docs/bots/api Теперь нам осталось самое вкусное. Это класс для обработки сообщений EventService:
и реализацию TimerTask
Да, я прекрасно понимаю, что можно каждые 20 минут проходить по базе и рассылать сообщения, но я в самом начале все написал про это )) Тут еще мы сталкиваемся с жмотством Heroku №1. На бесплатном тарифе Вам дается некие 550 dino, это что-то вроде часов работы вашего приложения в месяц.
На полный месяц работы приложения этого не хватит, а вот если привязать карту, то Вам дается еще 450 dino, что хватает за глаза. Если переживаете за карту, можете привязать какую-то пустую, но чтобы там было 0,6$.. Это проверочная сумма, она просто должна быть на счету. Никаких скрытых списаний не проводится, только если вы сами не смените тариф.
На бесплатном тарифе, есть еще одно небольшое поджмотство, назовем его №1а..Они постоянно перезагружают сервера, или просто присылают команду на перезапуск приложение, в общем оно перезагружается каждый день где-то в полночь по МСК, а бывает и в другое время. От этого все наши процессы в памяти удаляются. Для решения этой проблемы я придумал таблицу EventCash. Перед отправкой события сохраняются в отдельную таблицу:
EventCashEntity eventCashEntity = EventCashEntity.eventTo(calendarUserTime.getTime(), event.getDescription(), event.getUser().getId()); eventCashDAO.save(eventCashEntity);
А после отправления, удаляются:
ApplicationContextProvider – это специальный класс для получения контекста на лету:
Наша приложение готово, и пора нам получить адрес на Heroku для приложения и базы данных. Ваше приложение должно быть выложено на Github. Заходим на Heroku.com Нажимаем Create New App, вводим свое название приложения, выбираем Europe, create app. Все, место для приложения готово.
Если нажметe open App, то браузер перенаправит вас на адрес вашего приложения, это и есть ваш адрес webhook — https://ваше_название.herokuapp.com/ Регистрируйте его в telegram, а в настройках application.properties меняйте telegrambot.webHookPath=https://telegrambotsimpl.herokuapp.com/ на свой server.port=5000 можно удалить или закомментировать. Теперь давайте подключим базу данных. Заходим во вкладку Resources на Heroku, нажимаем: Находим там Heroku Postgres, нажимаем install: Вас перенаправит на страницу кабинета вашей базы данных. Найдите там в Settings/ Там будут все необходимые данные от вашей базы. В application.properties теперь все должно быть вот так:
Замените данные из кабинета на свои: В поле jdbc:postgresql:ec2-54-247-158-179.eu-west-1.compute.amazonaws.com:5432/d2um26le5notq?ssl=truesslfactory=org.postgresql.ssl.NonValidatingFactory нужно заменить выделенное жирным шрифтом на соответствующие данные из кабинета (Host, Database) Поля username, password не трудно догадаться. Теперь нам нужно создать таблицы в базе, я это делал из IDEA. Пригодится наш скрипт для создания базы.
Добавляем базу данных как это было написано Выше: Поле Host, User, Password, Database берем из кабинета. Поле URl – это наше поле spring.datasource.url до знака вопроса.
Заходим во вкладку Advanced, там должно быть так: Если Вы все сделали правильно, то после нажатия на test, будет зелененькая галочка. Нажимаем ОК. Нажимаем правой кнопкой на нашу базу и выбираем Jump to query console.
Копируйте туда наш script, и нажимайте на execute. База должна создаться. Вам доступны 10 000 строк нахаляву! Все готово для Deploy. Переходим в наше приложение на Heroku в раздел Deploy.
Выбираем там раздел Github: Привязываем свой репозиторий к Heroku. Теперь Ваши ветки будут видны. Не забудьте сделать push Ваших последних изменений в .properties. Ниже выбираете ветку, которая будет загружаться, и нажимаем Deploy branch.
Если все сделано верно, то Вам будет сообщено, что приложение успешно развернуто. Не забудьте включить Automatic deploys from.. Чтобы Ваше приложение запускалось автоматически. Кстати говоря, когда Вы будете делать push изменений на GitHub, heroku будет автоматически перезапускать приложение.
Осторожно к этому относитесь, заведите отдельную ветку для издевательств, а основную используйте только для рабочего приложения. Теперь Жмотство №2! Заключается во всем известном минусе бесплатного тарифа на heroku. При отсутствии поступающих сообщений приложение переходит в режим standby, и после поступления сообщение будет довольно длительное время запускаться, что не приятно.
Для этого существует простое решение — https://uptimerobot.com/ И нет, примочки с пингом Google не помогут, вообще не знаю откуда эта инфа взялась, я гуглил этот вопрос, и уже лет 10 как не работает эта тема точно, если вообще работала. Данное приложение будет на установленное вами время отсылать HEAD-запросы на указанный вами адрес и в случае, если оно не отвечает, присылать сообщение на email.
Разобраться не составит Вам трудности, там мало кнопок, чтобы запутаться )) Поздравляю!! Если я ничего не забыл и Вы были внимательны, то у Вас собственное приложение, работающее на халяву и никогда не падающее. Перед Вами открывается возможность для издевательств и экспериментов. В любом случае я готов отвечать на вопросы и приму любую критику! Код: https://github.com/papoff8295/webHookBotForHabr Использованные материалы: https://tlgrm.ru/docs/bots/api — о ботах. https://en.wikibooks.org/wiki/Java_Persistence — об отношениях в базах данных. https://stackoverflow.com/questions/11432498/how-to-call-a-thread-to-run-on-specific-time-in-java — класс Time и TimerTask https://www.youtube.com/watch?v=CUDgSbaYGx4 – как выложить код на Github https://github.com/rubenlagus/TelegramBots — библиотека telegram и куча полезного про это.
Источник: javarush.com