{"id":387176,"date":"2024-06-29T07:10:20","date_gmt":"2024-06-29T07:10:20","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=387176"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T07:10:20","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=387176","title":{"rendered":"<span>\u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u0431\u043e\u0442 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u043f\u043e\u0433\u043e\u0434\u044b \u043d\u0430 Java Spring<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0431\u043e\u0442\u0430 \u0434\u043b\u044f \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API. \u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/78b\/f3e\/6a1\/78bf3e6a1b0807b2534c402278bb0ed0.jpg\" width=\"649\" height=\"1280\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/78b\/f3e\/6a1\/78bf3e6a1b0807b2534c402278bb0ed0.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0431\u043e\u0442\u0430 \u0432 Telegram \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430<\/h2>\n<p>\u0422\u0443\u0442 \u0432\u0441\u0451 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <a href=\"https:\/\/t.me\/botfather\" rel=\"noopener noreferrer nofollow\">@BotFather<\/a> \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0441\u0451 \u0441\u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e81\/382\/be4\/e81382be4652ff2b106740ffb13babfa.JPG\" width=\"716\" height=\"490\"\/><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0431\u043e\u0442\u0430.<\/p>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0432 openweather \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/h2>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0441\u0430\u0439\u0442 <a href=\"https:\/\/openweathermap.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/openweathermap.org\/<\/a> \u0438 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e, \u043a\u043b\u044e\u0447 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 MyAPI keys. \u041f\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u043c\u0443 \u0442\u0430\u0440\u0438\u0444\u0443 \u0432\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0434\u043e 60 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0432 \u043c\u0438\u043d\u0443\u0442\u0443 \u0438 \u0434\u043e 1 000 000 \u0432 \u043c\u0435\u0441\u044f\u0446.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7b6\/b97\/be5\/7b6b97be5096bb29c841e3a234a2fdcc.JPG\" width=\"594\" height=\"142\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0448 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0433\u043e\u0434\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d API \u0441\u0441\u044b\u043b\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 &#8212; <a href=\"http:\/\/api.openweathermap.org\/data\/2.5\/weather?q=%7Bcity%7D&amp;appid=3eeb478c0c035168d643da8d2147d871&amp;units=metric&amp;lang=ru\" rel=\"noopener noreferrer nofollow\">http:\/\/api.openweathermap.org\/data\/2.5\/weather?q={city}&amp;appid={key}&amp;units=metric&amp;lang=ru<\/a> , \u0433\u0434\u0435 units=metric \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0435\u0434\u0438\u043d\u0438\u0446\u0443 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u0432 \u0446\u0435\u043b\u044c\u0441\u0438\u044f\u0445. <\/p>\n<p>\u041e \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445 API \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 Spring Boot \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/start.spring.io\/\" rel=\"noopener noreferrer nofollow\">https:\/\/start.spring.io\/<\/a>, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 IntelliJ IDEA, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 Spring Boot \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>pom.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;dependencies>      &lt;!--\u0414\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f MongoDB-->         &lt;dependency>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-starter-data-mongodb&lt;\/artifactId>         &lt;\/dependency>    &lt;!--\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 Java \u043a\u043e\u0434\u0430-->         &lt;dependency>             &lt;groupId>org.projectlombok&lt;\/groupId>             &lt;artifactId>lombok&lt;\/artifactId>             &lt;optional>true&lt;\/optional>         &lt;\/dependency>            &lt;!--\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API-->         &lt;dependency>             &lt;groupId>org.telegram&lt;\/groupId>             &lt;artifactId>telegrambots&lt;\/artifactId>             &lt;version>5.2.0&lt;\/version>         &lt;\/dependency>      &lt;!--\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u044d\u043c\u043e\u0434\u0436\u0438-->         &lt;dependency>             &lt;groupId>com.vdurmont&lt;\/groupId>             &lt;artifactId>emoji-java&lt;\/artifactId>             &lt;version>5.1.1&lt;\/version>         &lt;\/dependency>      &lt;dependency>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-starter-web&lt;\/artifactId>         &lt;\/dependency>     &lt;\/dependencies><\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u0448 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c MongoDB \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0430\u0442\u043e\u0432.<\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u043c):<\/p>\n<details class=\"spoiler\">\n<summary>BotConfig &#8212; \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor @Document(collection = \"bot_config\") public class BotConfig {     @Id     private BigInteger id;    \/\/\u0438\u043c\u044f \u0431\u043e\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438     private String name;    \/\/\u0442\u043e\u043a\u0435\u043d     private String accessToken;    \/\/http:\/\/api.openweathermap.org\/data\/2.5\/weather?q={city}&amp;appid=\u0412\u0410\u0428_\u041a\u041b\u042e\u0427&amp;units=metric&amp;lang=ru     private String nowWeatherApiTemp;    \/\/\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u043d\u0438\u0436\u0435   \/\/https:\/\/api.telegram.org\/bot{token}\/answerCallbackQuery?callback_query_id={id}     private String telegramCallbackAnswerTemp;      private List&lt;Command> commands; }  @Getter @Setter @NoArgsConstructor public class Command {     private String name;    \/\/ \/command     private String description;  \/\/  bla bla bla }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ChatConfig &#8212; \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0447\u0430\u0442\u0430\u0445 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor @RequiredArgsConstructor @Document(collection = \"chats_config\") public class ChatConfig {     @Id     private BigInteger id;      @NonNull     private Long chatId;      @NonNull     @Field(targetType = FieldType.STRING)     private BotState botState;        \/\/\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     private String city; }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0442\u0440\u0438 enum:<\/p>\n<details class=\"spoiler\">\n<summary>BotState &#8212; \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum BotState {     DEFAULT,SEARCH_NOW,SEARCH_PREDICT,NOW,PREDICT,SET_CITY }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>KeyboardType &#8212; \u0413\u0440\u0443\u043f\u043f\u044b \u043a\u043d\u043e\u043f\u043e\u043a \u0432 \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u0447\u0430\u0442\u0435, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum KeyboardType {     CITY_CHOOSE }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>MainCommand &#8212; \u041a\u043e\u043c\u0430\u043d\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 DEFAULT<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum MainCommand {     START,HELP,CITY,SETCITY,NOW,CANCEL }<\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 API Openweather<\/h2>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432<\/p>\n<details class=\"spoiler\">\n<summary>BotConfigService &#8212; \u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class BotConfigService {     @Autowired    \/\/\u043f\u0443\u0441\u0442\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 MongoRepository&lt;BotConfig, BigInteger>     private BotConfigRepo botConfigRepo;       public String getTelegramCallbackAnswerTemp(){         return this.botConfigRepo.findAll().get(0).getTelegramCallbackAnswerTemp();     }      public String getNowApiTemp(){         return this.botConfigRepo.findAll().get(0).getNowWeatherApiTemp();     }      public List&lt;Command> getAllCommands(){         return botConfigRepo.findAll().get(0).getCommands();     }      public String getBotUsername(){         return botConfigRepo.findAll().get(0).getName();     }      public String getBotAccessToken(){         return botConfigRepo.findAll().get(0).getAccessToken();     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ChatConfigRepo \u0438 ChatConfigService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public interface ChatConfigRepo extends MongoRepository&lt;ChatConfig, BigInteger> {     ChatConfig findAllByChatId(Long chatId);     void deleteByChatId(Long chatId); }   @Service public class ChatConfigService {     @Autowired     private ChatConfigRepo chatConfigRepo;      public boolean isChatInit(Long chatId){         return chatConfigRepo.findAllByChatId(chatId) != null;     }    \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0447\u0430\u0442\u0430     public void initChat(Long chatId){         chatConfigRepo.save(new ChatConfig(chatId, BotState.DEFAULT));     }      public void deleteChat(Long chatId){         chatConfigRepo.deleteByChatId(chatId);     }      public void setBotState(Long chatId,BotState botState){         ChatConfig chatConfig = chatConfigRepo.findAllByChatId(chatId);         chatConfig.setBotState(botState);         chatConfigRepo.save(chatConfig);     }      public BotState getBotState(Long chatId){         return chatConfigRepo.findAllByChatId(chatId).getBotState();     }      public void setCity(Long chatId,String city){         ChatConfig chatConfig = chatConfigRepo.findAllByChatId(chatId);         chatConfig.setCity(city);         chatConfigRepo.save(chatConfig);     }      public String getCity(Long chatId){         return chatConfigRepo.findAllByChatId(chatId).getCity();     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API \u043f\u043e\u0433\u043e\u0434\u044b. \u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u0432\u0435\u0442 \u0432\u0438\u0434\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>current weather json response<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{     \"coord\": {         \"lon\": 37.6156,         \"lat\": 55.7522     },     \"weather\": [         {             \"id\": 500,             \"main\": \"Rain\",             \"description\": \"\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u043e\u0436\u0434\u044c\",             \"icon\": \"10n\"         }     ],     \"base\": \"stations\",     \"main\": {         \"temp\": 13.78,         \"feels_like\": 13.69,         \"temp_min\": 12.37,         \"temp_max\": 14.24,         \"pressure\": 1013,         \"humidity\": 95,         \"sea_level\": 1013,         \"grnd_level\": 995     },     \"visibility\": 10000,     \"wind\": {         \"speed\": 3.52,         \"deg\": 43,         \"gust\": 9.4     },     \"rain\": {         \"1h\": 0.22     },     \"clouds\": {         \"all\": 100     },     \"dt\": 1623359195,     \"sys\": {         \"type\": 2,         \"id\": 2000314,         \"country\": \"RU\",         \"sunrise\": 1623372350,         \"sunset\": 1623435164     },     \"timezone\": 10800,     \"id\": 524901,     \"name\": \"\u041c\u043e\u0441\u043a\u0432\u0430\",     \"cod\": 200 }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043b\u0435\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e: weather.main, weather.description, main.temp, main.feels_like. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>WeatherNow<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor public class WeatherNow {     private List&lt;Weather> weather;     private Main main; }  @Getter @Setter @NoArgsConstructor public class Weather {     private String main;     private String description; }  @Getter @Setter @NoArgsConstructor public class Main {     private Integer temp;      @JsonProperty(\"feels_like\")     private Integer feelsLike; }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441, \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 API, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u043d\u0435\u0433\u043e<\/p>\n<details class=\"spoiler\">\n<summary>WeatherRestMap<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class WeatherRestMap {     @Autowired     private RestTemplate restTemplate;     @Autowired     private BotConfigService botConfigService;  \/\/\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0433\u043e\u0434\u044b     public WeatherNow getNowWeather(String city){         try {             return restTemplate.getForObject(botConfigService.getNowApiTemp()             .replace(\"{city}\",city),              WeatherNow.class);         }catch (Exception e){             e.printStackTrace();             return null;         }     }  \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u043e\u0440\u043e\u0434\u0430     public boolean isCity(String city) throws IOException {          URL weatherApiUrl = new URL(botConfigService.getNowApiTemp().replace(\"{city}\",city));                  HttpURLConnection weatherApiConnection = (HttpURLConnection)weatherApiUrl.openConnection();         weatherApiConnection.setRequestMethod(\"GET\");         weatherApiConnection.connect();         return weatherApiConnection.getResponseCode() == HttpURLConnection.HTTP_OK;     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>WeatherService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class WeatherService {     @Autowired     private WeatherRestMap weatherRestMap;      public boolean isCity(String city) throws IOException {         return weatherRestMap.isCity(city);     }      public WeatherNow getCurrentWeather(String city){         return weatherRestMap.getNowWeather(city);     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e \u0441 Telegram API<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 TelegramLongPollingBot \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 WeatherBot<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class WeatherBot extends TelegramLongPollingBot {     @Autowired     private BotConfigService botConfigService;     @Autowired     private WeatherBotFacade weatherBotFacade;      @Override     public String getBotUsername() {         return botConfigService.getBotUsername();     }      @Override     public String getBotToken() {         return botConfigService.getBotAccessToken();     }         @SneakyThrows \/\/\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 Exceptions     @Override     public void onUpdateReceived(Update update) {         weatherBotFacade.handleUpdate(update);     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041c\u0435\u0442\u043e\u0434 onUpdateReceived \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441 Telegram API \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0430\u043f\u0434\u0435\u0439\u0442\u044b, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0435\u0435 \u0431\u043e\u0442\u0443, \u0442\u0430\u043a \u0438 \u043a\u0430\u043a\u043e\u0435-\u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u0447\u0430\u0442\u0435 \u0441 \u0431\u043e\u0442\u043e\u043c (\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0447\u0430\u0442\u0430 \u0438.\u0442.\u0434.)<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 BotInit<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class BotInit {     @Autowired     private WeatherBot weatherBot;          \/\/\u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e     @EventListener({ApplicationReadyEvent.class})     public void init() throws TelegramApiException {         TelegramBotsApi telegramBotsApi = new TelegramBotsApi(           DefaultBotSession.class);         try {             telegramBotsApi.registerBot(weatherBot);         } catch (TelegramApiRequestException e) {             e.printStackTrace();         }     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430 WeatherBotFacade, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e \u0441 Telegram API, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 &#8212; \u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043e\u0442 \u0431\u043e\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>MessageGenerator<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class MessageGenerator {     @Autowired     private BotConfigService botConfigService;     @Autowired     private WeatherService weatherService;      private String message;      public String generateStartMessage(String name){         return EmojiParser.parseToUnicode(\"\u041f\u0440\u0438\u0432\u0435\u0442, \" + name + \" :wave: \\n\u0427\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043d\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f - \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \/help\");     }      public String generateHelpMessage(){         message = \"\";         message = \":sunny: \u0412\u043e\u0442 \u043c\u043e\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b :sunny:\\n\\n\";         botConfigService.getAllCommands()                 .forEach(command -> {                     message = message + command.getName() + \" - \" + command.getDescription() + \"\\n\";                 });         return EmojiParser.parseToUnicode(message);     }      public String generateSuccessCancel(){         return EmojiParser.parseToUnicode(\":white_check_mark: \u0410\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0430\");     }      public String generateSuccessSetCity(String city){         return EmojiParser.parseToUnicode(\":white_check_mark: \u041d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 - \" + city);     }      public String generateErrorCity(){         return EmojiParser.parseToUnicode(\":x: \u0422\u0430\u043a\u043e\u0433\u043e \u0433\u043e\u0440\u043e\u0434\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\");     }      public String generateSuccessGetCity(String city){         return EmojiParser.parseToUnicode(\":cityscape: \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 - \" + city);     }      public String generateErrorGetCity(){         return EmojiParser.parseToUnicode(\":x: \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 \u043d\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\");     }      public String generateCurrentWeather(String city){         WeatherNow weatherNow = weatherService.getCurrentWeather(city);         return EmojiParser.parseToUnicode(\"\u0422\u0435\u043a\u0443\u0449\u0430\u044f \u043f\u043e\u0433\u043e\u0434\u0430\\n\\n\" +                 \"\u0412 \u0433\u043e\u0440\u043e\u0434\u0435 \" + city + \" \" + weatherNow.getWeather().get(0).getDescription() + \"\\n\" +                 \":thermometer: \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430: \" + weatherNow.getMain().getTemp() + \"\u00b0C, \u043e\u0449\u0443\u0449\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \" + weatherNow.getMain().getFeelsLike() + \"\u00b0C\");     } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0438\u043a\u043e\u043d\u043e\u043a, \u043a\u043e\u0434 \u0432\u0438\u0434\u0430 :icon: \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u044d\u043c\u043e\u0434\u0436\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/emojipedia.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/emojipedia.org\/<\/a><\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u0445 \u043e\u0442 \u0431\u043e\u0442\u0430<\/p>\n<details class=\"spoiler\">\n<summary>KeyboardService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class KeyboardService {     @Autowired     private ChatConfigService chatConfigService;      private final InlineKeyboardMarkup keyboard = new InlineKeyboardMarkup();       public InlineKeyboardMarkup setChooseCityKeyboard(Long chatId){         List&lt;InlineKeyboardButton> keyboardRow = new ArrayList&lt;>();         InlineKeyboardButton button1 = new InlineKeyboardButton();               \/\/\u0442\u0435\u043a\u0441\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435       button1.setText(chatConfigService.getCity(chatId));              \/\/\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442         button1.setCallbackData(getCurrentCityNowButton(chatConfigService                                                         .getCity(chatId)));          InlineKeyboardButton button2 = new InlineKeyboardButton();         button2.setText(\"\u0414\u0440\u0443\u0433\u043e\u0439\");         button2.setCallbackData(getChooseCityNowButtonData());          keyboardRow.add(button1);         keyboardRow.add(button2);         keyboard.setKeyboard(Arrays.asList(keyboardRow));          return keyboard;     }      public String getChooseCityNowButtonData(){         return \"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0433\u043e\u0440\u043e\u0434\";     }      public String getCurrentCityNowButton(String city){         return \"\u0421\u0435\u0439\u0447\u0430\u0441 \" + city;     } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041a\u043d\u043e\u043f\u043a\u0438 \u0441 CallbackData \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043e\u043f\u043b\u0430\u0442\u044b, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Telegram API, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c callbackAnswer, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043f\u043e\u043b\u0435 callback_query_id. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043c\u0435\u0442\u043e\u0434\u0435 \u0438 \u0435\u0433\u043e \u043f\u043e\u043b\u044f\u0445 &#8212; <a href=\"https:\/\/core.telegram.org\/bots\/api#answercallbackquery\" rel=\"noopener noreferrer nofollow\">https:\/\/core.telegram.org\/bots\/api#answercallbackquery<\/a><\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435 \u0432\u0435\u0440\u043d\u0443\u0442\u044c callbackAnswer, \u0442\u043e \u0443 \u043a\u043d\u043e\u043f\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u0430  (\u043e\u043a\u043e\u043b\u043e 15 \u0441\u0435\u043a\u0443\u043d\u0434), \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0432 \u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043d\u043e\u043f\u043a\u0438<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1c1\/dcf\/479\/1c1dcf4791dbdcff46667b8aa11a8d67.JPG\" width=\"151\" height=\"73\"\/><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f callbackAnswer \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0434\u0438\u043d\u043e\u0447\u043d\u044b\u0439 HTTP \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 &#8212; <a href=\"https:\/\/api.telegram.org\/bot%7Btoken%7D\/answerCallbackQuery?callback_query_id=%7Bid%7D\" rel=\"noopener noreferrer nofollow\">https:\/\/api.telegram.org\/bot{token}\/answerCallbackQuery?callback_query_id={id}<\/a><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 CallbackAnswer<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class CallbackAnswer {     @Autowired     private BotConfigService botConfigService;      public void callbackAnswer(String callbackId) throws IOException, InterruptedException {         HttpClient telegramApiClient = HttpClient.newHttpClient();         HttpRequest telegramCallbackAnswerReq = HttpRequest.newBuilder(URI                             .create(botConfigService                 .getTelegramCallbackAnswerTemp()                 .replace(\"{token}\",botConfigService.getBotAccessToken())                 .replace(\"{id}\",callbackId)))                     .GET().build();          telegramApiClient.send(telegramCallbackAnswerReq, HttpResponse.BodyHandlers                                .ofString());     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0436\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443 WeatherBotFacade<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u043e\u0442\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>void sendMessage<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">private Long setChatIdToMessageBuilder(Update update, SendMessage.SendMessageBuilder messageBuilder){         Long chatId = null;         if (update.hasMessage()) {             chatId = update.getMessage().getChatId();             messageBuilder.chatId(update.getMessage().getChatId().toString());         } else if (update.hasChannelPost()) {             chatId = update.getChannelPost().getChatId();             messageBuilder.chatId(update.getChannelPost().getChatId().toString());         }else if (update.hasCallbackQuery()){             chatId = update.getCallbackQuery().getMessage().getChatId();             messageBuilder.chatId(update.getCallbackQuery().getMessage().getChatId().toString());         }         return chatId;     }  private void sendMessage(Update update,String messageText){         SendMessage.SendMessageBuilder messageBuilder = SendMessage.builder();          Long chatId = setChatIdToMessageBuilder(update,messageBuilder);          messageBuilder.text(messageText);          try {             weatherBot.execute(messageBuilder.build());         }catch (TelegramApiException telegramApiException){             telegramApiException.printStackTrace();         }     }      private void sendMessage(Update update, String messageText, KeyboardType keyboardType) {         SendMessage.SendMessageBuilder messageBuilder = SendMessage.builder();          Long chatId = setChatIdToMessageBuilder(update, messageBuilder);          messageBuilder.text(messageText);          switch (keyboardType) {             case CITY_CHOOSE: {               \/\/\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0438, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435                 messageBuilder.replyMarkup(keyboardService.setChooseCityKeyboard(chatId));                 break;             }         }          try {             weatherBot.execute(messageBuilder.build());         }catch (TelegramApiException telegramApiException){             telegramApiException.printStackTrace();         }     }  <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0430\u043f\u0434\u0435\u0439\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 onUpdateReceived \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>void handleUpdate<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public void handleUpdate(Update update) throws IOException, InterruptedException {         String messageText;         Long chatId;         String userFirstName = \"\";    \/\/\u0435\u0441\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e \u0432 \u043b\u0441 \u0431\u043e\u0442\u0443         if (update.hasMessage()) {             chatId = update.getMessage().getChatId();             messageText = update.getMessage().getText().toUpperCase(Locale.ROOT).replace(\"\/\",\"\");             userFirstName = update.getMessage().getChat().getFirstName();         }    \/\/\u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u0448\u043b\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u043a\u043d\u043e\u043f\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438 \u0432\u044b\u0448\u0435         else if (update.hasCallbackQuery()){             callbackAnswer.callbackAnswer(update.getCallbackQuery().getId());              chatId = update.getCallbackQuery().getMessage().getChatId();             messageText = update.getCallbackQuery().getData().toUpperCase(Locale.ROOT);             sendMessage(update,update.getCallbackQuery().getData());              if (messageText.equals(keyboardService.getChooseCityNowButtonData().toUpperCase(Locale.ROOT))){                 chatConfigService.setBotState(chatId,BotState.SEARCH_NOW);                 return;             }              else if (messageText.equals(keyboardService.getCurrentCityNowButton(chatConfigService.getCity(chatId)).toUpperCase(Locale.ROOT))){                 chatConfigService.setBotState(chatId,BotState.NOW);             }         }    \/\/\u0435\u0441\u043b\u0438 \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0441\u044f \u043a \u0447\u0430\u0442\u0443 \u0438\u043b\u0438 \u043f\u043e\u043a\u0438\u043d\u0443\u043b \u0435\u0433\u043e         else if (update.hasMyChatMember()) {           \/\/\u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0447\u0430\u0442\u0435 \u0438\u0437 \u0431\u0434, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043a\u0438\u043d\u0443\u043b \u0447\u0430\u0442 \u0441 \u0431\u043e\u0442\u043e\u043c             if (update.getMyChatMember().getNewChatMember().getStatus().equals(\"kicked\")){                 chatConfigService.deleteChat(update.getMyChatMember().getChat().getId());             }              return;         }else {              return;         }    \/\/\u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u043e \u0447\u0430\u0442\u0435 \u0432 \u0431\u0434 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435          if (!chatConfigService.isChatInit(chatId)){             chatConfigService.initChat(chatId);             sendMessage(update, messageGenerator.generateStartMessage(userFirstName));         }else{           \/\/\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u043e\u0442\u0430 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0447\u0430\u0442\u0430             handleBotState(update,chatId,messageText,userFirstName);         }     }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041d\u0443 \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u043e\u0442\u0430 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0430\u0442\u0430 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>void handleBotState<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">private void handleBotState(Update update,Long chatId,String messageText,String userFirstName) throws IOException {         BotState botState = chatConfigService.getBotState(chatId);    \/\/ \/start - \u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435         if (messageText.equals(MainCommand.START.name())) {             chatConfigService.setBotState(chatId,BotState.DEFAULT);             sendMessage(update,messageGenerator.generateStartMessage(userFirstName));             return;         }    \/\/ \/cancel \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0431\u043e\u0442\u0430 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 DEFAULT (\u043e\u0442\u043c\u0435\u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b)         if (messageText.equals(MainCommand.CANCEL.name())){             if (botState == BotState.DEFAULT){                 sendMessage(update,\"\u041d\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u044f\");             }else {                 chatConfigService.setBotState(chatId,BotState.DEFAULT);                 sendMessage(update,messageGenerator.generateSuccessCancel());                 return;             }         }          switch (botState) {             case DEFAULT: {                \/\/ \/help - \u0421\u043f\u0438\u0441\u043e\u043a \u043a\u043e\u043c\u0430\u043d\u0434                 if (messageText.equals(MainCommand.HELP.name())) {                     sendMessage(update, messageGenerator.generateHelpMessage());                 }                \/\/ \/setcity - \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0433\u043e\u0440\u043e\u0434\u0430                 else if (messageText.equals(MainCommand.SETCITY.name())) {                     chatConfigService.setBotState(chatId, BotState.SET_CITY);                     sendMessage(update, \"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434\");                 }                \/\/ \/city - \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 \u0434\u043b\u044f \u0447\u0430\u0442\u0430                  else if (messageText.equals(MainCommand.CITY.name())) {                     if (chatConfigService.getCity(chatId) != null &amp;&amp; !chatConfigService.getCity(chatId).equals(\"\")) sendMessage(update, messageGenerator.generateSuccessGetCity(chatConfigService.getCity(chatId)));                     else sendMessage(update, messageGenerator.generateErrorGetCity());                 }                \/\/ \/now - \u0423\u0437\u043d\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u043f\u043e\u0433\u043e\u0434\u0443                 else if (messageText.equals(MainCommand.NOW.name())) {                     chatConfigService.setBotState(chatId, BotState.NOW);                     sendMessage(update, \"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0433\u043e\u0440\u043e\u0434\", KeyboardType.CITY_CHOOSE);                 }                  break;             }              case SET_CITY: {                \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 - \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0433\u043e\u0440\u043e\u0434                 if (weatherService.isCity(messageText.toLowerCase(Locale.ROOT))) {                     chatConfigService.setCity(chatId, messageText.charAt(0)+messageText.substring(1).toLowerCase(Locale.ROOT));                     chatConfigService.setBotState(chatId, BotState.DEFAULT);                     sendMessage(update, messageGenerator.generateSuccessSetCity(chatConfigService.getCity(chatId)));                 }                  else sendMessage(update, messageGenerator.generateErrorCity());                  break;             }              case NOW: {                \/\/ \u0435\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434                 if (messageText.equals(keyboardService.getChooseCityNowButtonData().toUpperCase(Locale.ROOT)))                 {                     chatConfigService.setBotState(chatId,BotState.SEARCH_NOW);                 }                \/\/ \u043f\u043e\u0433\u043e\u0434\u0430 \u0434\u043b\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0433\u043e\u0440\u043e\u0434\u0430                 else {                     chatConfigService.setBotState(chatId,BotState.DEFAULT);                     sendMessage(update,messageGenerator.generateCurrentWeather(chatConfigService.getCity(chatId)));                 }                 break;             }              case SEARCH_NOW: {               \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0433\u043e\u0440\u043e\u0434\u0430                 if (!weatherService.isCity(messageText)){                     sendMessage(update,messageGenerator.generateErrorCity());                 }                \/\/ \u043f\u043e\u0433\u043e\u0434\u0430 \u0434\u043b\u044f \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u0433\u043e \u0433\u043e\u0440\u043e\u0434\u0430                 else {                     sendMessage(update,messageGenerator.generateCurrentWeather(messageText.charAt(0) + messageText.substring(1).toLowerCase(Locale.ROOT)));                     chatConfigService.setBotState(chatId,BotState.DEFAULT);                 }                  break;             }         }     }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a\u043b\u0430\u0441\u0441\u0430 WeatherBotFacade:<\/p>\n<details class=\"spoiler\">\n<summary>WeatherBotFacade<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class WeatherBotFacade {     @Autowired     private ChatConfigService chatConfigService;     @Autowired     private MessageGenerator messageGenerator;     @Autowired     private WeatherService weatherService;     @Autowired     private KeyboardService keyboardService;     @Autowired     private WeatherBot weatherBot;     @Autowired     private CallbackAnswer callbackAnswer;       public void handleUpdate(Update update) throws IOException, InterruptedException {         String messageText;         Long chatId;         String userFirstName = \"\";          if (update.hasMessage()) {             chatId = update.getMessage().getChatId();             messageText = update.getMessage().getText().toUpperCase(Locale.ROOT).replace(\"\/\",\"\");             userFirstName = update.getMessage().getChat().getFirstName();         }          else if (update.hasChannelPost()){             chatId = update.getChannelPost().getChatId();             messageText = update.getChannelPost().getText().toUpperCase(Locale.ROOT).replace(\"\/\",\"\");             userFirstName = update.getChannelPost().getChat().getFirstName();         }          else if (update.hasCallbackQuery()){             callbackAnswer.callbackAnswer(update.getCallbackQuery().getId());              chatId = update.getCallbackQuery().getMessage().getChatId();             messageText = update.getCallbackQuery().getData().toUpperCase(Locale.ROOT);             sendMessage(update,update.getCallbackQuery().getData());              if (messageText.equals(keyboardService.getChooseCityNowButtonData().toUpperCase(Locale.ROOT))){                 chatConfigService.setBotState(chatId,BotState.SEARCH_NOW);                 return;             }              else if (messageText.equals(keyboardService.getCurrentCityNowButton(chatConfigService.getCity(chatId)).toUpperCase(Locale.ROOT))){                 chatConfigService.setBotState(chatId,BotState.NOW);             }         }          else if (update.hasMyChatMember()) {             if (update.getMyChatMember().getNewChatMember().getStatus().equals(\"kicked\")){                 chatConfigService.deleteChat(update.getMyChatMember().getChat().getId());             }              return;         }else {              return;         }          if (!chatConfigService.isChatInit(chatId)){             chatConfigService.initChat(chatId);             sendMessage(update, messageGenerator.generateStartMessage(userFirstName));         }else{             handleBotState(update,chatId,messageText,userFirstName);         }     }       private Long setChatIdToMessageBuilder(Update update, SendMessage.SendMessageBuilder messageBuilder){         Long chatId = null;         if (update.hasMessage()) {             chatId = update.getMessage().getChatId();             messageBuilder.chatId(update.getMessage().getChatId().toString());         } else if (update.hasChannelPost()) {             chatId = update.getChannelPost().getChatId();             messageBuilder.chatId(update.getChannelPost().getChatId().toString());         }else if (update.hasCallbackQuery()){             chatId = update.getCallbackQuery().getMessage().getChatId();             messageBuilder.chatId(update.getCallbackQuery().getMessage().getChatId().toString());         }         return chatId;     }      private void sendMessage(Update update,String messageText){         SendMessage.SendMessageBuilder messageBuilder = SendMessage.builder();          Long chatId = setChatIdToMessageBuilder(update,messageBuilder);          messageBuilder.text(messageText);          try {             weatherBot.execute(messageBuilder.build());         }catch (TelegramApiException telegramApiException){             telegramApiException.printStackTrace();         }     }      private void sendMessage(Update update, String messageText, KeyboardType keyboardType) {         SendMessage.SendMessageBuilder messageBuilder = SendMessage.builder();          Long chatId = setChatIdToMessageBuilder(update, messageBuilder);          messageBuilder.text(messageText);          switch (keyboardType) {             case CITY_CHOOSE: {                 messageBuilder.replyMarkup(keyboardService.setChooseCityKeyboard(chatId));                 break;             }         }          try {             weatherBot.execute(messageBuilder.build());         }catch (TelegramApiException telegramApiException){             telegramApiException.printStackTrace();         }     }      private void handleBotState(Update update,Long chatId,String messageText,String userFirstName) throws IOException {         BotState botState = chatConfigService.getBotState(chatId);          if (messageText.equals(MainCommand.START.name())) {             chatConfigService.setBotState(chatId,BotState.DEFAULT);             sendMessage(update,messageGenerator.generateStartMessage(userFirstName));             return;         }          if (messageText.equals(MainCommand.CANCEL.name())){             if (botState == BotState.DEFAULT){                 sendMessage(update,\"\u041d\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u044f\");             }else {                 chatConfigService.setBotState(chatId,BotState.DEFAULT);                 sendMessage(update,messageGenerator.generateSuccessCancel());                 return;             }         }          switch (botState) {             case DEFAULT: {                  if (messageText.equals(MainCommand.HELP.name())) {                     sendMessage(update, messageGenerator.generateHelpMessage());                 }                  else if (messageText.equals(MainCommand.SETCITY.name())) {                     chatConfigService.setBotState(chatId, BotState.SET_CITY);                     sendMessage(update, \"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434\");                 }                  else if (messageText.equals(MainCommand.CITY.name())) {                     if (chatConfigService.getCity(chatId) != null &amp;&amp; !chatConfigService.getCity(chatId).equals(\"\")) sendMessage(update, messageGenerator.generateSuccessGetCity(chatConfigService.getCity(chatId)));                     else sendMessage(update, messageGenerator.generateErrorGetCity());                 }                  else if (messageText.equals(MainCommand.NOW.name())) {                     chatConfigService.setBotState(chatId, BotState.NOW);                     sendMessage(update, \"\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0433\u043e\u0440\u043e\u0434\", KeyboardType.CITY_CHOOSE);                 }                  break;             }              case SET_CITY: {                  if (weatherService.isCity(messageText.toLowerCase(Locale.ROOT))) {                     chatConfigService.setCity(chatId, messageText.charAt(0)+messageText.substring(1).toLowerCase(Locale.ROOT));                     chatConfigService.setBotState(chatId, BotState.DEFAULT);                     sendMessage(update, messageGenerator.generateSuccessSetCity(chatConfigService.getCity(chatId)));                 }                  else sendMessage(update, messageGenerator.generateErrorCity());                  break;             }              case NOW: {                  if (messageText.equals(keyboardService.getChooseCityNowButtonData().toUpperCase(Locale.ROOT)))                 {                     chatConfigService.setBotState(chatId,BotState.SEARCH_NOW);                 }                  else {                     chatConfigService.setBotState(chatId,BotState.DEFAULT);                     sendMessage(update,messageGenerator.generateCurrentWeather(chatConfigService.getCity(chatId)));                 }                 break;             }              case SEARCH_NOW: {                 if (!weatherService.isCity(messageText)){                     sendMessage(update,messageGenerator.generateErrorCity());                 }                  else {                     sendMessage(update,messageGenerator.generateCurrentWeather(messageText.charAt(0) + messageText.substring(1).toLowerCase(Locale.ROOT)));                     chatConfigService.setBotState(chatId,BotState.DEFAULT);                 }                  break;             }         }     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/571762\/\"> https:\/\/habr.com\/ru\/articles\/571762\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435, \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0431\u043e\u0442\u0430 \u0434\u043b\u044f \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API. \u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0431\u043e\u0442\u0430 \u0432 Telegram \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430<\/h2>\n<p>\u0422\u0443\u0442 \u0432\u0441\u0451 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <a href=\"https:\/\/t.me\/botfather\" rel=\"noopener noreferrer nofollow\">@BotFather<\/a> \u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0441\u0451 \u0441\u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0431\u043e\u0442\u0430.<\/p>\n<h2>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0432 openweather \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/h2>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u0441\u0430\u0439\u0442 <a href=\"https:\/\/openweathermap.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/openweathermap.org\/<\/a> \u0438 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e, \u043a\u043b\u044e\u0447 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 MyAPI keys. \u041f\u043e \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u043c\u0443 \u0442\u0430\u0440\u0438\u0444\u0443 \u0432\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0434\u043e 60 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0432 \u043c\u0438\u043d\u0443\u0442\u0443 \u0438 \u0434\u043e 1 000 000 \u0432 \u043c\u0435\u0441\u044f\u0446.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0448 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0433\u043e\u0434\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0448\u0430\u0431\u043b\u043e\u043d API \u0441\u0441\u044b\u043b\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 &#8212; <a href=\"http:\/\/api.openweathermap.org\/data\/2.5\/weather?q=%7Bcity%7D&amp;appid=3eeb478c0c035168d643da8d2147d871&amp;units=metric&amp;lang=ru\" rel=\"noopener noreferrer nofollow\">http:\/\/api.openweathermap.org\/data\/2.5\/weather?q={city}&amp;appid={key}&amp;units=metric&amp;lang=ru<\/a> , \u0433\u0434\u0435 units=metric \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0435\u0434\u0438\u043d\u0438\u0446\u0443 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b \u0432 \u0446\u0435\u043b\u044c\u0441\u0438\u044f\u0445. <\/p>\n<p>\u041e \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445 API \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 Spring Boot \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/start.spring.io\/\" rel=\"noopener noreferrer nofollow\">https:\/\/start.spring.io\/<\/a>, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 IntelliJ IDEA, \u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 Spring Boot \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>pom.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;dependencies>      &lt;!--\u0414\u0440\u0430\u0439\u0432\u0435\u0440 \u0434\u043b\u044f MongoDB-->         &lt;dependency>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-starter-data-mongodb&lt;\/artifactId>         &lt;\/dependency>    &lt;!--\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 Java \u043a\u043e\u0434\u0430-->         &lt;dependency>             &lt;groupId>org.projectlombok&lt;\/groupId>             &lt;artifactId>lombok&lt;\/artifactId>             &lt;optional>true&lt;\/optional>         &lt;\/dependency>            &lt;!--\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API-->         &lt;dependency>             &lt;groupId>org.telegram&lt;\/groupId>             &lt;artifactId>telegrambots&lt;\/artifactId>             &lt;version>5.2.0&lt;\/version>         &lt;\/dependency>      &lt;!--\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u044d\u043c\u043e\u0434\u0436\u0438-->         &lt;dependency>             &lt;groupId>com.vdurmont&lt;\/groupId>             &lt;artifactId>emoji-java&lt;\/artifactId>             &lt;version>5.1.1&lt;\/version>         &lt;\/dependency>      &lt;dependency>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-starter-web&lt;\/artifactId>         &lt;\/dependency>     &lt;\/dependencies><\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u0448 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c MongoDB \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0447\u0430\u0442\u043e\u0432.<\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u043c):<\/p>\n<details class=\"spoiler\">\n<summary>BotConfig &#8212; \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor @Document(collection = \"bot_config\") public class BotConfig {     @Id     private BigInteger id;    \/\/\u0438\u043c\u044f \u0431\u043e\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438     private String name;    \/\/\u0442\u043e\u043a\u0435\u043d     private String accessToken;    \/\/http:\/\/api.openweathermap.org\/data\/2.5\/weather?q={city}&amp;appid=\u0412\u0410\u0428_\u041a\u041b\u042e\u0427&amp;units=metric&amp;lang=ru     private String nowWeatherApiTemp;    \/\/\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u043d\u0438\u0436\u0435   \/\/https:\/\/api.telegram.org\/bot{token}\/answerCallbackQuery?callback_query_id={id}     private String telegramCallbackAnswerTemp;      private List&lt;Command> commands; }  @Getter @Setter @NoArgsConstructor public class Command {     private String name;    \/\/ \/command     private String description;  \/\/  bla bla bla }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ChatConfig &#8212; \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0447\u0430\u0442\u0430\u0445 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor @RequiredArgsConstructor @Document(collection = \"chats_config\") public class ChatConfig {     @Id     private BigInteger id;      @NonNull     private Long chatId;      @NonNull     @Field(targetType = FieldType.STRING)     private BotState botState;        \/\/\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0433\u043e\u0440\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f     private String city; }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0442\u0440\u0438 enum:<\/p>\n<details class=\"spoiler\">\n<summary>BotState &#8212; \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum BotState {     DEFAULT,SEARCH_NOW,SEARCH_PREDICT,NOW,PREDICT,SET_CITY }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>KeyboardType &#8212; \u0413\u0440\u0443\u043f\u043f\u044b \u043a\u043d\u043e\u043f\u043e\u043a \u0432 \u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u0447\u0430\u0442\u0435, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum KeyboardType {     CITY_CHOOSE }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>MainCommand &#8212; \u041a\u043e\u043c\u0430\u043d\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u043e\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 DEFAULT<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum MainCommand {     START,HELP,CITY,SETCITY,NOW,CANCEL }<\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 API Openweather<\/h2>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432<\/p>\n<details class=\"spoiler\">\n<summary>BotConfigService &#8212; \u0421\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u0431\u043e\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class BotConfigService {     @Autowired    \/\/\u043f\u0443\u0441\u0442\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 MongoRepository&lt;BotConfig, BigInteger>     private BotConfigRepo botConfigRepo;       public String getTelegramCallbackAnswerTemp(){         return this.botConfigRepo.findAll().get(0).getTelegramCallbackAnswerTemp();     }      public String getNowApiTemp(){         return this.botConfigRepo.findAll().get(0).getNowWeatherApiTemp();     }      public List&lt;Command> getAllCommands(){         return botConfigRepo.findAll().get(0).getCommands();     }      public String getBotUsername(){         return botConfigRepo.findAll().get(0).getName();     }      public String getBotAccessToken(){         return botConfigRepo.findAll().get(0).getAccessToken();     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ChatConfigRepo \u0438 ChatConfigService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public interface ChatConfigRepo extends MongoRepository&lt;ChatConfig, BigInteger> {     ChatConfig findAllByChatId(Long chatId);     void deleteByChatId(Long chatId); }   @Service public class ChatConfigService {     @Autowired     private ChatConfigRepo chatConfigRepo;      public boolean isChatInit(Long chatId){         return chatConfigRepo.findAllByChatId(chatId) != null;     }    \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0447\u0430\u0442\u0430     public void initChat(Long chatId){         chatConfigRepo.save(new ChatConfig(chatId, BotState.DEFAULT));     }      public void deleteChat(Long chatId){         chatConfigRepo.deleteByChatId(chatId);     }      public void setBotState(Long chatId,BotState botState){         ChatConfig chatConfig = chatConfigRepo.findAllByChatId(chatId);         chatConfig.setBotState(botState);         chatConfigRepo.save(chatConfig);     }      public BotState getBotState(Long chatId){         return chatConfigRepo.findAllByChatId(chatId).getBotState();     }      public void setCity(Long chatId,String city){         ChatConfig chatConfig = chatConfigRepo.findAllByChatId(chatId);         chatConfig.setCity(city);         chatConfigRepo.save(chatConfig);     }      public String getCity(Long chatId){         return chatConfigRepo.findAllByChatId(chatId).getCity();     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API \u043f\u043e\u0433\u043e\u0434\u044b. \u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043e\u0442\u0432\u0435\u0442 \u0432\u0438\u0434\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>current weather json response<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{     \"coord\": {         \"lon\": 37.6156,         \"lat\": 55.7522     },     \"weather\": [         {             \"id\": 500,             \"main\": \"Rain\",             \"description\": \"\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u043e\u0436\u0434\u044c\",             \"icon\": \"10n\"         }     ],     \"base\": \"stations\",     \"main\": {         \"temp\": 13.78,         \"feels_like\": 13.69,         \"temp_min\": 12.37,         \"temp_max\": 14.24,         \"pressure\": 1013,         \"humidity\": 95,         \"sea_level\": 1013,         \"grnd_level\": 995     },     \"visibility\": 10000,     \"wind\": {         \"speed\": 3.52,         \"deg\": 43,         \"gust\": 9.4     },     \"rain\": {         \"1h\": 0.22     },     \"clouds\": {         \"all\": 100     },     \"dt\": 1623359195,     \"sys\": {         \"type\": 2,         \"id\": 2000314,         \"country\": \"RU\",         \"sunrise\": 1623372350,         \"sunset\": 1623435164     },     \"timezone\": 10800,     \"id\": 524901,     \"name\": \"\u041c\u043e\u0441\u043a\u0432\u0430\",     \"cod\": 200 }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043b\u0435\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e: weather.main, weather.description, main.temp, main.feels_like. <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>WeatherNow<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor public class WeatherNow {     private List&lt;Weather> weather;     private Main main; }  @Getter @Setter @NoArgsConstructor public class Weather {     private String main;     private String description; }  @Getter @Setter @NoArgsConstructor public class Main {     private Integer temp;      @JsonProperty(\"feels_like\")     private Integer feelsLike; }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441, \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 API, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u043d\u0435\u0433\u043e<\/p>\n<details class=\"spoiler\">\n<summary>WeatherRestMap<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class WeatherRestMap {     @Autowired     private RestTemplate restTemplate;     @Autowired     private BotConfigService botConfigService;  \/\/\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0433\u043e\u0434\u044b     public WeatherNow getNowWeather(String city){         try {             return restTemplate.getForObject(botConfigService.getNowApiTemp()             .replace(\"{city}\",city),              WeatherNow.class);         }catch (Exception e){             e.printStackTrace();             return null;         }     }  \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u043e\u0440\u043e\u0434\u0430     public boolean isCity(String city) throws IOException {          URL weatherApiUrl = new URL(botConfigService.getNowApiTemp().replace(\"{city}\",city));                  HttpURLConnection weatherApiConnection = (HttpURLConnection)weatherApiUrl.openConnection();         weatherApiConnection.setRequestMethod(\"GET\");         weatherApiConnection.connect();         return weatherApiConnection.getResponseCode() == HttpURLConnection.HTTP_OK;     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>WeatherService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service public class WeatherService {     @Autowired     private WeatherRestMap weatherRestMap;      public boolean isCity(String city) throws IOException {         return weatherRestMap.isCity(city);     }      public WeatherNow getCurrentWeather(String city){         return weatherRestMap.getNowWeather(city);     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e \u0441 Telegram API<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 TelegramLongPollingBot \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043b\u0430\u0441\u0441 WeatherBot<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component public class WeatherBot extends TelegramLongPollingBot {     @Autowired     private BotConfigService botConfigService;     @Autowired     private WeatherBotFacade weatherBotFacade;      @Override     public String getBotUsername() {         return botConfigService.getBotUsername();     }      @Override     public String getBotToken() {         return botConfigService.getBotAccessToken();     }         @SneakyThrows<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-387176","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/387176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=387176"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/387176\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=387176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=387176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=387176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}