DEV Community

Prasanth
Prasanth

Posted on

Building a Weather Application with Spring Boot and OpenWeatherMap API

  • Build a simple Weather App using Spring Boot, the OpenWeatherMap API, and Thymeleaf as the front-end template engine. Users can enter a city name, and the application will fetch and display current weather details.
  1. To get Api and APIKeys from “https://home.openweathermap.org/“
  2. After signup/login
  3. Get APIKey from “https://home.openweathermap.org/api_keys“
  4. Get APIURL: “https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}“

example:-

https://api.openweathermap.org/data/2.5/weather?q=Thiruvallur&appid=93c30d18b6d15d780cc94b291984ad88

Weather Response:

  • you get response in JSON data format

Note:-

  • JSON response came from API call , now we need return the response to now created project.

  • Now we want to read to json data ,but we do not know how to write program , Don worry we need to add dependencies , that one is Jackason DataBind (Jackson Databind is a Java library that allows you to easily convert (bind) JSON data to Java objects and vice versa.)

Main Use of Jackson Databind:-

  • Read JSON => Java Object (Deserialization)
  • Write Java Object => JSON (Serialization)

Link:-

https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.19.2

  • copy dependencies and paste to you pom.xml

  • one website (you app or website) can get data from another website (open weather) using public ApI, This is Apis work.

1. Overall Project Flow

Request-Response Flow:-

User => Enters City in Form (HTML) => Controller => Service => OpenWeatherMap API
<= Response => Data sent to View via Model => Weather Displayed on Web Page

2.WeatherResponse.java (Model Layer)

Purpose: maps the Api Response to java objects using jackson.

Contains:

  • name = city name
  • main = temperature, humidity, etc.
  • weather[] = an array of weather descriptions @JsonIgnoreProperties(ignoreUnknown = true) , ensure that any unnecesary Json fields.
package com.example.demo; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; // we need particular JSON data another data ignore @JsonIgnoreProperties(ignoreUnknown = true) public class WeatherResponse { // only need those response from like https://api.openweathermap.org/data/2.5/weather?q=Thiruvallur&appid=93c30d18b6d15d780cc94b291984ad88 public String getName() { return name; } public void setName(String name) { this.name = name; } public Main getMain() { return main; } public void setMain(Main main) { this.main = main; } public Weather[] getWeather() { return weather; } public void setWeather(Weather[] weather) { this.weather = weather; } private String name ; private Main main ; // Main class private Weather[] weather; // weather class for array } // we want to use this response this class only that why private (like one time usage) and that why we create above the class's in same class class Main { private double temp; private int humidity; private int sea_level; private int pressure ; public double getTemp() { return temp; } public void setTemp(double temp) { this.temp = temp; } public int getHumidity() { return humidity; } public void setHumidity(int humidity) { this.humidity = humidity; } public int getSea_level() { return sea_level; } public void setSea_level(int sea_level) { this.sea_level = sea_level; } public int getPressure() { return pressure; } public void setPressure(int pressure) { this.pressure = pressure; } public int getGrnd_level() { return grnd_level; } public void setGrnd_level(int grnd_level) { this.grnd_level = grnd_level; } private int grnd_level; } class Weather { private String description; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } } // now we done json object convert to java object 
Enter fullscreen mode Exit fullscreen mode

3.WeatherController.java (Controller Layer)

  • Controller handles the web API request.
  • Calls the service to get weather data.
  • Sends the data to the view using Model. model.addAttribute("weather", weatherResponse);
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class WeatherController { @Autowired private WeatherService weatherService; @GetMapping("/") public String display() { return "weather"; } // now to create src/main/resource create weather.html under templates @GetMapping("/weather") public String show_weather_details(@RequestParam String city , Model model) { // @RequestParam get data from the URL /* Example: If URL is http://localhost:8080/weather?city=Chennai * Then city will have the value "Chennai" It reads the ?city=Chennai part from the URL. * Model model * it is used to store data that you want to send to the HTML(Thymleaf) page * like Model is used to store and pass data from the controller to the view (HTML * */ /* now Below this thing , to implement to code to service class. * Api key ,we already defined application properties. * City * APIURL * weather responce * */ WeatherResponse weatherResponse = weatherService.getWeather(city); // 7 model.addAttribute("weather", weatherResponse); return "weather" ; } } 
Enter fullscreen mode Exit fullscreen mode

** 4. WeatherService.java (Service Layer)**

  • Purpose: Make the Rest Api call to OpenWeathermap using RestTemplate.

Uses:
return restTemplate.getForObject(APIURL, WeatherResponse.class, city, apiKey);

  • Uses @Value("${weather.api.key}") to inject the API key from application.properties
package com.example.demo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class WeatherService { // Api key ,we already defined application properties @Value("${weather.api.key}") // get the value in application properties private String apiKey; // * APIURL private final String APIURL = "https://api.openweathermap.org/data/2.5/weather?q={city}&appid={apiKey}"; public WeatherResponse getWeather (String city) { RestTemplate restTemplate = new RestTemplate(); return restTemplate.getForObject(APIURL,WeatherResponse.class,city,apiKey); // 5 // * weather response //How to API Response data (Like weather data) get into to browser page (htmlpage ), That one is RestTemplate . // Now we return APIURL,WeatherResponce.class(pojo class) ,city,apiKey with used to RestTemplate , to WeatherResponce class . // now we connect to controller and response class go to controller class } } 
Enter fullscreen mode Exit fullscreen mode

5.Apllication properties
weather.api.key=YOUR_API_KEY_HERE

6.weather.html (View Layer - Thymeleaf)

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Weather App</title> <style> body { font-family: Arial, sans-serif; background: linear-gradient(to right, #83a4d4, #b6fbff); color: #333; padding: 20px; text-align: center; } .weather-box { background-color: white; border-radius: 10px; padding: 30px; max-width: 400px; margin: 30px auto; box-shadow: 0 0 10px rgba(0,0,0,0.2); } input[type="text"] { padding: 10px; width: 60%; border: 1px solid #ccc; border-radius: 5px; margin-top: 20px; } button { padding: 10px 20px; border: none; background-color: #007BFF; color: white; border-radius: 5px; margin-left: 10px; cursor: pointer; } button:hover { background-color: #0056b3; } .info { margin-top: 20px; } .error { color: red; } </style> </head> <body> <h1>🌦 Weather Application</h1> <form action="/weather" method="get"> <input type="text" name="city" placeholder="Enter city name" required> <button type="submit">Search</button> </form> <!-- Weather Result Section --> <div class="weather-box" th:if="${weather != null}"> <h2 th:text="${weather.name}">City Name</h2> <p class="info">🌡 Temperature: <span th:text="${weather.main.temp}"></span> °C</p> <p class="info">💧 Humidity: <span th:text="${weather.main.humidity}"></span>%</p> <p class="info">🌤 Condition: <span th:text="${weather.weather[0].description}"></span></p> </div> <!-- Show message if weather not found or city not entered --> <div th:if="${weather == null}"> <p class="error">No weather data available. Please enter a valid city.</p> </div> </body> </html> <!-- when you submit that button it trigger the weather action , now back to controller class --> 
Enter fullscreen mode Exit fullscreen mode

Final Results:-

Top comments (0)