Hi all! The topic of creating bots for Telegrams is somewhat hackneyed, and a lot of guides have been written (for example, this one ). Therefore, we’d better take a closer look at working with some third-party API, since this is a critical skill for any web developer. I’ll say right away that the application did not set out to provide the most functional and useful forecast; there is no point in competing with weather sites; it was important to learn how to work with remote connections and data parsing using Java. So, let's find out what we need first. Our application essentially consists of three logical parts:
- accept message from user
- process the message, and, if it is a valid command, prepare data for the response. In our case, prepare a weather forecast if the user entered the correct city
- send ready information to the user in chat
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
You can see how the response to such a request looks in the browser. We have already found out that, in fact, you just need to follow the correct link and the server will provide the necessary data. All that remains is to learn how to do this using Java. A simple GET request in Java looks like this:
//создаём строку со ссылкой на нужную 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();
If the request was correct and the server was available, we will receive a sheet of data in which useful information is mixed with information that is not needed now. To conveniently extract the necessary data from JSON and XML, tons of libraries have been written for Java to suit every taste. Since I preferred JSON, I chose a very popular library called Jackson to process it. By the way, it is studied a little in JavaRush at some high levels. To process large amounts of JSON data, it is important to understand the structure of the document. Helpful sites like this one come to the rescue . On the left we have the original JSON, on the right - the structured one: It can be seen that the response consists of 5 top-level JSON objects, 2 of which are complex and are nodes for the following branches. The data we are interested in is stored in the list node . Inside list is an array of 38 JSON lines, each describing the weather at a certain time. That is, it is a kind of tree-like structure, where there is a root, branches, twigs and even leaves :) And at the nodes the branching takes place. Luckily, Jackson can represent any valid JSON as a tree. Thus, knowing the name of the attribute we need (for example, air temperature), and at what level of the tree it is located, getting it will not be much of a problem. First, I extracted all the lines from the "list" array and added them to a separate list. Roughly speaking, I cut the sheet with the data into pieces, each of which is a separate forecast. Small parts are easier to keep in mind and operate with.
//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());
}
}
}
So we got a list of strings, in which each line represents a JSON weather report at a certain time. All that remains is to extract what you want and format it. If we have a line like this:
"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}
then this is a node called "main". To get any data from it, for example sea level, the following code is enough:
ObjectMapper objectMapper = new ObjectMapper();
//line - это наша JSON-строка
mainNode = objectMapper.readTree(line).get("main");
String seaLevel = mainNode.get("sea_level");
Jackson allows you to immediately represent data in numeric format:
double seaLevel = mainNode.get("sea_level").asDouble();
Now we can extract any data from the forecast, and all that remains is to glue it together as desired and send it to the user in Telegram. The full source code is on my github , but you can try the bot in action using the link , or by finding @denifoBot in the Telegram search. The name of the city must be written in Latin transliteration, for example "Kyiv" or "Moscow". Thank you, if you made it to the end, I accept reasonable criticism, since I’m just learning and developing simple projects on GitHub in order to compete with hungry talents from my city :) Bye everyone! PS I believe that there may be typos here, so you can send everything in a private message, or in a comment if you are really angry :)
GO TO FULL VERSION