Chào mọi người! Chủ đề tạo bot cho Telegram có phần hơi nhàm chán và rất nhiều hướng dẫn đã được viết (ví dụ: hướng dẫn này ) . Do đó, tốt hơn hết chúng ta nên xem xét kỹ hơn khi làm việc với một số API của bên thứ ba, vì đây là một kỹ năng quan trọng đối với bất kỳ nhà phát triển web nào. Tôi sẽ nói ngay rằng ứng dụng này không nhằm mục đích cung cấp dự báo hữu ích và hữu ích nhất; không có ích gì khi cạnh tranh với các trang web thời tiết; điều quan trọng là phải học cách làm việc với các kết nối từ xa và phân tích dữ liệu bằng Java. Vì vậy, hãy tìm hiểu những gì chúng ta cần trước tiên. Ứng dụng của chúng tôi về cơ bản bao gồm ba phần hợp lý:
- chấp nhận tin nhắn từ người dùng
- xử lý thông báo và nếu đó là lệnh hợp lệ, hãy chuẩn bị dữ liệu cho phản hồi. Trong trường hợp của chúng tôi, hãy chuẩn bị dự báo thời tiết nếu người dùng vào đúng thành phố
- gửi thông tin sẵn sàng cho người dùng trong trò chuyện
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
Bạn có thể xem phản hồi đối với yêu cầu như vậy trông như thế nào trong trình duyệt. Trên thực tế, chúng tôi đã phát hiện ra rằng bạn chỉ cần nhấp vào liên kết chính xác và máy chủ sẽ cung cấp dữ liệu cần thiết. Tất cả những gì còn lại là học cách thực hiện việc này bằng Java. Một yêu cầu GET đơn giản trong Java trông như thế này:
//создаём строку со ссылкой на нужную 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();
Nếu yêu cầu đúng và máy chủ khả dụng, chúng tôi sẽ nhận được một bảng dữ liệu trong đó thông tin hữu ích được trộn lẫn với thông tin hiện không cần thiết. Để trích xuất dữ liệu cần thiết từ JSON và XML một cách thuận tiện, rất nhiều thư viện đã được viết cho Java để phù hợp với mọi sở thích. Vì tôi thích JSON hơn nên tôi đã chọn một thư viện rất phổ biến tên là Jackson để xử lý nó. Nhân tiện, nó được nghiên cứu một chút về JavaRush ở một số cấp độ cao. Để xử lý lượng lớn dữ liệu JSON, điều quan trọng là phải hiểu cấu trúc của tài liệu. Các trang web hữu ích như thế này sẽ ra tay giải cứu . Bên trái chúng ta có JSON gốc, bên phải - JSON có cấu trúc: Có thể thấy phản hồi bao gồm 5 đối tượng JSON cấp cao nhất, trong đó có 2 đối tượng phức tạp và là các nút cho các nhánh sau. Dữ liệu chúng ta quan tâm được lưu trữ trong nút danh sách . Danh sách bên trong là một mảng gồm 38 dòng JSON, mỗi dòng mô tả thời tiết tại một thời điểm nhất định. Nghĩa là, nó là một loại cấu trúc giống như cây, trong đó có rễ, cành, cành và thậm chí cả lá :) Và tại các nút, quá trình phân nhánh diễn ra. May mắn thay, Jackson có thể biểu diễn bất kỳ JSON hợp lệ nào dưới dạng cây. Do đó, biết tên của thuộc tính chúng ta cần (ví dụ: nhiệt độ không khí) và nó nằm ở cấp độ nào của cây, việc lấy nó sẽ không gặp nhiều vấn đề. Đầu tiên, tôi trích xuất tất cả các dòng từ mảng "danh sách" và thêm chúng vào một danh sách riêng. Nói một cách đại khái, tôi cắt tờ dữ liệu thành nhiều phần, mỗi phần là một dự báo riêng biệt. Các bộ phận nhỏ dễ ghi nhớ và thao tác hơn.
//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());
}
}
}
Điều này cung cấp cho chúng ta một danh sách các chuỗi, trong đó mỗi chuỗi biểu thị một báo cáo JSON về thời tiết tại một thời điểm nhất định. Tất cả những gì còn lại là trích xuất những gì bạn muốn và định dạng nó. Nếu chúng ta có một dòng như thế này:
"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}
thì đây là nút được gọi là "chính". Để lấy bất kỳ dữ liệu nào từ nó, ví dụ như mực nước biển, đoạn mã sau là đủ:
ObjectMapper objectMapper = new ObjectMapper();
//line - это наша JSON-строка
mainNode = objectMapper.readTree(line).get("main");
String seaLevel = mainNode.get("sea_level");
Jackson cho phép bạn biểu diễn ngay dữ liệu ở định dạng số:
double seaLevel = mainNode.get("sea_level").asDouble();
Bây giờ chúng tôi có thể trích xuất bất kỳ dữ liệu nào từ dự báo và tất cả những gì còn lại là dán nó lại với nhau như mong muốn và gửi cho người dùng trong Telegram. Mã nguồn đầy đủ có trên github của tôi , nhưng bạn có thể thử hoạt động của bot bằng liên kết hoặc bằng cách tìm @denifoBot trong tìm kiếm Telegram. Tên của thành phố phải được viết bằng phiên âm Latinh, ví dụ "Kyiv" hoặc "Moscow". Cảm ơn bạn, nếu bạn đã làm đến cùng, tôi chấp nhận những lời chỉ trích hợp lý, vì tôi chỉ đang học và phát triển các dự án đơn giản trên GitHub để cạnh tranh với những tài năng đang khao khát từ thành phố của mình :) Tạm biệt mọi người! Tái bút Tôi tin rằng có thể có lỗi chính tả ở đây, vì vậy bạn có thể gửi mọi thứ trong tin nhắn riêng tư hoặc trong bình luận nếu bạn thực sự tức giận :)
GO TO FULL VERSION