Hi all! The topic of creating bots for Telegram is somewhat beaten up, 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, as this is a critical skill for any web developer. I must say right away that the application did not aim to provide the most functional and useful forecast, it makes no sense to compete with weather sites, it was important to learn how to work with remote connections and data parsing using Java. So, let's first find out what we need. Our application, in fact, consists of three logical parts:
- accept message from user
- process the message, and if it's a valid command, prepare the data for a response. In our case, prepare a weather forecast if the user has entered a valid city
- send the finished information to the user in the chat
https://api.openweathermap.org/data/2.5/forecast?q=(город)&APPID=(уникальный токен, полученный при регистрации)
You can see how the response to such a request looks in the browsertyts We have already found out that, in fact, you just need to follow the correct link and the server will return the necessary data. It remains to learn how to do it 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'd end up with a sheet of data that mixes useful information with information that isn't needed right now. To conveniently extract the necessary data from JSON and XML, tons of libraries have been written for Java for 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 on CodeGym at some high levels. To process large amounts of JSON data, it is important to understand the structure of the document. Useful sites like this come to the rescue . On the left we have the original JSON, on the right - structured: 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 strings, each describing the weather at a particular time. That is, it is such a tree-like structure, where there is a root, branches, twigs and even leaves :) And at the nodes, the branching takes place. Fortunately, 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, getting it will not be any particular problem. To begin with, I extracted all the lines from the "list" array and added them to a separate list. Roughly speaking, I cut the data sheet into pieces, each of which is a separate forecast. Small parts are easier to keep in mind and operate on them.
//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 string is a JSON summary of the weather at a specific time. It remains to extract the desired and format. 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, it's 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 numerical format:
double seaLevel = mainNode.get("sea_level").asDouble();
Now we can extract any data from the forecast, and all that remains is to glue them together as we wish and send them to the user in Telegram. The full source code is on my github , but you can try the bot in action by following 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 have mastered it to the end, I accept reasonable criticism, as I am just learning and developing simple projects on github 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 personal, well, or in a comment if you are really very angry :)
GO TO FULL VERSION