שלום לכולם! הנושא של יצירת בוטים עבור טלגרם הוא קצת פרוע, ונכתבו הרבה מדריכים (למשל, זה ) . לכן, מוטב שנבחן מקרוב את העבודה עם ממשק API של צד שלישי, מכיוון שזו מיומנות קריטית עבור כל מפתח אינטרנט. אני אגיד מיד שהאפליקציה לא התכוונה לספק את התחזית הפונקציונלית והשימושית ביותר; אין טעם להתחרות באתרי מזג אוויר; היה חשוב ללמוד כיצד לעבוד עם חיבורים מרוחקים וניתוח נתונים באמצעות Java. אז בואו נגלה מה אנחנו צריכים קודם. האפליקציה שלנו מורכבת בעיקרה משלושה חלקים לוגיים:
- קבל הודעה מהמשתמש
- לעבד את ההודעה, ואם היא פקודה חוקית, להכין נתונים לתגובה. במקרה שלנו, הכינו תחזית מזג אוויר אם המשתמש נכנס לעיר הנכונה
- לשלוח מידע מוכן למשתמש בצ'אט
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
אתה יכול לראות איך נראית התגובה לבקשה כזו בדפדפן, כבר גילינו שלמעשה אתה רק צריך לעקוב אחר הקישור הנכון והשרת יספק את הנתונים הדרושים. כל מה שנותר הוא ללמוד כיצד לעשות זאת באמצעות Java. בקשת GET פשוטה ב-Java נראית כך:
//создаём строку со ссылкой на нужную page,
//я тут её склеиваю из заранее определённых констант, меняя только сам город
String urlString = API_CALL_TEMPLATE + city + API_KEY_TEMPLATE;
//создаём an object который будет содержать ссылку
URL urlObject = new URL(urlString);
//создаём соединение, используя an object
HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
//выбираем тип requestа (GET)
connection.setRequestMethod("GET");
//тут мы указываем, данные о себе, что мы можем принять всё то,
//что примет и любой современный браузер
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
//В начало ответа server всегда вставляет число, по которому можно судить, прошло ли всё хорошо.
//200 - значит OK
int responseCode = connection.getResponseCode();
//на несуществующий город or город с опечаткой, server выдаст code ответа 404,
//бросаем на него исключение, чтобы обработать на уровне повыше и предложить
//пользователю ввести город заново
if (responseCode == 404) {
throw new IllegalArgumentException();
}
// создаём поток, вычитываем все строки, и склеиваем в одну большую строку,
//которую будем потом обрабатывать в других методах
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
אם הבקשה הייתה נכונה והשרת היה זמין, נקבל דף נתונים בו מעורבב מידע שימושי עם מידע שאין בו צורך כעת. כדי לחלץ בנוחות את הנתונים הדרושים מ-JSON ו-XML, נכתבו טונות של ספריות עבור Java כדי שיתאימו לכל טעם. מכיוון שהעדפתי את JSON, בחרתי בספרייה מאוד פופולרית בשם Jackson כדי לעבד אותה. אגב, זה נלמד קצת ב-JavaRush בכמה רמות גבוהות. כדי לעבד כמויות גדולות של נתוני JSON, חשוב להבין את מבנה המסמך. אתרים מועילים כמו זה באים להצלה . בצד שמאל יש לנו את ה-JSON המקורי, מימין - המובנה: ניתן לראות שהתגובה מורכבת מ-5 אובייקטי JSON ברמה עליונה, 2 מהם מורכבים ומהווים צמתים לענפים הבאים. הנתונים שאנו מעוניינים בהם מאוחסנים בצומת הרשימה . הרשימה הפנימית היא מערך של 38 קווי JSON, כל אחד מתאר את מזג האוויר בזמן מסוים. כלומר, זה מעין מבנה דמוי עץ, שבו יש שורש, ענפים, זרדים ואפילו עלים :) ובצמתים מתבצעת ההסתעפות. למרבה המזל, ג'קסון יכול לייצג כל JSON חוקי כעץ. לפיכך, לדעת את שם התכונה שאנו צריכים (לדוגמה, טמפרטורת האוויר), ובאיזו רמה של העץ היא ממוקמת, קבלתה לא תהיה בעיה גדולה. ראשית, חילצתי את כל השורות ממערך ה"רשימה" והוספתי אותן לרשימה נפרדת. בגדול, חתכתי את הגיליון עם הנתונים לחתיכות שכל אחת מהן היא תחזית נפרדת. קל יותר לזכור ולפעול איתם חלקים קטנים.
//JsonNode - это один из узлов в древовидной иерархии, от которого идут ветви
//получаем узел, который называется "list"
JsonNode arrNode = new ObjectMapper().readTree(data).get("list");
//если это действительно массив узлов
if (arrNode.isArray()) {
//выполняем для каждого узла, который содержится в массиве
for (final JsonNode objNode : arrNode) {
//в атрибуте "dt_txt" каждого маленького узла хранилось время прогноза, я отобрал данные за 9 утра и 6 вечера
String forecastTime = objNode.get("dt_txt").toString();
if (forecastTime.contains("09:00") || forecastTime.contains("18:00")) {
weatherList.add(objNode.toString());
}
}
}
אז קיבלנו רשימה של מחרוזות, שבהן כל שורה מייצגת דוח מזג אוויר של JSON בזמן מסוים. כל מה שנותר הוא לחלץ את מה שאתה רוצה ולעצב אותו. אם יש לנו שורה כזו:
"main":{"temp":261.45,"temp_min":259.086,"temp_max":261.45,"pressure":1023.48,"sea_level":1045.39,"grnd_level":1023.48,"humidity":79,"temp_kf":2.37}
אז זהו צומת שנקרא "ראשי". כדי לקבל ממנו נתונים כלשהם, למשל פני הים, מספיק הקוד הבא:
ObjectMapper objectMapper = new ObjectMapper();
//line - это наша JSON-строка
mainNode = objectMapper.readTree(line).get("main");
String seaLevel = mainNode.get("sea_level");
ג'קסון מאפשר לך לייצג מיד נתונים בפורמט מספרי:
double seaLevel = mainNode.get("sea_level").asDouble();
כעת נוכל לחלץ כל נתון מהתחזית, וכל שנותר הוא להדביק אותו כרצוי ולשלוח למשתמש בטלגרם. קוד המקור המלא נמצא ב- github שלי , אבל אתה יכול לנסות את הבוט בפעולה באמצעות הקישור , או על ידי מציאת @denifoBot בחיפוש הטלגרם. יש לכתוב את שם העיר בתעתיק לטיני, למשל "קייב" או "מוסקבה". תודה, אם הגעת עד הסוף, אני מקבל ביקורת סבירה, שכן אני רק לומד ומפתח פרויקטים פשוטים ב-GitHub כדי להתחרות עם כישרונות רעבים מהעיר שלי :) ביי כולם! נ.ב אני מאמין שאולי יש כאן שגיאות הקלדה, אז את יכולה לשלוח הכל בהודעה פרטית, או בתגובה אם את ממש כועסת :)
GO TO FULL VERSION