← Назад к вопросам

Какая погода в твоем городе?

1.0 Junior🔥 31 комментариев
#Soft Skills и карьера

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Работа с погодными данными в Java приложениях

Хотя вопрос звучит неоднозначно, я расскажу, как Java Developer может работать с получением информации о погоде из внешних API.

1. Получение данных о погоде через REST API

Мост часто используются публичные API для получения информации о погоде:

import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class WeatherService {
    private static final String OPENWEATHER_API = 
        "https://api.openweathermap.org/data/2.5/weather";
    
    private final RestTemplate restTemplate;
    private final String apiKey;
    
    public WeatherService(RestTemplate restTemplate, String apiKey) {
        this.restTemplate = restTemplate;
        this.apiKey = apiKey;
    }
    
    public String getWeather(String city) {
        String url = String.format(
            "%s?q=%s&appid=%s&units=metric",
            OPENWEATHER_API, city, apiKey
        );
        
        try {
            String response = restTemplate.getForObject(url, String.class);
            return parseWeather(response);
        } catch (Exception e) {
            return "Не удалось получить данные о погоде";
        }
    }
    
    private String parseWeather(String response) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(response);
        
        String city = root.get("name").asText();
        double temperature = root.path("main").get("temp").asDouble();
        String description = root.path("weather").get(0).get("description").asText();
        
        return String.format(
            "Город: %s%nТемпература: %.1f°C%nОписание: %s",
            city, temperature, description
        );
    }
}

2. Использование WebClient (реактивный подход)

import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Service
public class ReactiveWeatherService {
    private final WebClient webClient;
    
    public ReactiveWeatherService(WebClient.Builder builder) {
        this.webClient = builder
            .baseUrl("https://api.openweathermap.org/data/2.5")
            .build();
    }
    
    public Mono<WeatherData> getWeatherAsync(String city, String apiKey) {
        return webClient.get()
            .uri("/weather?q={city}&appid={apiKey}&units=metric",
                city, apiKey)
            .retrieve()
            .bodyToMono(WeatherData.class)
            .onErrorMap(e -> new WeatherServiceException(
                "Failed to get weather: " + e.getMessage(), e
            ));
    }
}

public class WeatherData {
    private String name;
    private MainData main;
    private List<Weather> weather;
    
    static class MainData {
        public double temp;
        public int humidity;
    }
    
    static class Weather {
        public String description;
    }
}

3. Кэширование данных о погоде

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class CachedWeatherService {
    private final RestTemplate restTemplate;
    
    @Cacheable(value = "weather", key = "#city", 
               unless = "#result == null")
    public WeatherData getWeather(String city) {
        // Результат кэшируется на время (по умолчанию)
        String url = "https://api.openweathermap.org/data/2.5/weather" +
                    "?q=" + city + "&appid=YOUR_API_KEY";
        return restTemplate.getForObject(url, WeatherData.class);
    }
}

4. Асинхронное получение погоды

import org.springframework.scheduling.annotation.Async;
import java.util.concurrent.CompletableFuture;

@Service
public class AsyncWeatherService {
    private final RestTemplate restTemplate;
    
    @Async
    public CompletableFuture<WeatherData> getWeatherAsync(String city) {
        try {
            String url = "https://api.openweathermap.org/data/2.5/weather" +
                        "?q=" + city + "&appid=YOUR_API_KEY";
            WeatherData data = restTemplate.getForObject(url, WeatherData.class);
            return CompletableFuture.completedFuture(data);
        } catch (Exception e) {
            return CompletableFuture.failedFuture(e);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // Неблокирующее получение данных
        service.getWeatherAsync("Moscow")
            .thenAccept(weather -> System.out.println(
                "Погода: " + weather.getTemperature()
            ))
            .join();
    }
}

5. Контроллер для получения погоды

@RestController
@RequestMapping("/api/weather")
public class WeatherController {
    private final WeatherService weatherService;
    
    public WeatherController(WeatherService weatherService) {
        this.weatherService = weatherService;
    }
    
    @GetMapping("/{city}")
    public ResponseEntity<WeatherData> getWeather(
        @PathVariable String city
    ) {
        try {
            WeatherData data = weatherService.getWeather(city);
            return ResponseEntity.ok(data);
        } catch (Exception e) {
            return ResponseEntity.status(404)
                .body(null);
        }
    }
    
    @GetMapping("/{city}/forecast")
    public ResponseEntity<List<WeatherData>> getForecast(
        @PathVariable String city,
        @RequestParam(defaultValue = "5") int days
    ) {
        List<WeatherData> forecast = weatherService.getForecast(city, days);
        return ResponseEntity.ok(forecast);
    }
}

6. Error Handling при работе с погодным API

@Service
public class RobustWeatherService {
    private final RestTemplate restTemplate;
    private static final int MAX_RETRIES = 3;
    private static final int TIMEOUT_SECONDS = 5;
    
    public WeatherData getWeatherWithRetry(String city) {
        for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
            try {
                return fetchWeather(city);
            } catch (HttpClientErrorException.NotFound e) {
                throw new CityNotFoundException("City not found: " + city);
            } catch (HttpServerErrorException e) {
                if (attempt == MAX_RETRIES) {
                    throw new WeatherServiceException(
                        "API unavailable after " + MAX_RETRIES + " retries", e
                    );
                }
                try {
                    Thread.sleep(1000 * attempt);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new WeatherServiceException("Request interrupted", ie);
                }
            }
        }
        throw new WeatherServiceException("Failed to get weather");
    }
    
    private WeatherData fetchWeather(String city) {
        String url = "https://api.openweathermap.org/data/2.5/weather" +
                    "?q=" + city + "&appid=YOUR_API_KEY";
        return restTemplate.getForObject(url, WeatherData.class);
    }
}

7. Тестирование WeatherService с MockRestServiceServer

@ExtendWith(MockitoExtension.class)
public class WeatherServiceTest {
    
    private RestTemplate restTemplate;
    private WeatherService weatherService;
    private MockRestServiceServer mockServer;
    
    @BeforeEach
    public void setup() {
        restTemplate = new RestTemplate();
        mockServer = MockRestServiceServer.createServer(restTemplate);
        weatherService = new WeatherService(restTemplate, "test-key");
    }
    
    @Test
    public void testGetWeatherSuccess() {
        String mockResponse = 
            "{\"name\":\"Moscow\",\"main\":{\"temp\":5.0}}";
        
        mockServer.expect(
            requestTo(org.hamcrest.Matchers.containsString("Moscow"))
        )
        .andRespond(
            withSuccess(mockResponse, MediaType.APPLICATION_JSON)
        );
        
        WeatherData result = weatherService.getWeather("Moscow");
        
        assertEquals("Moscow", result.name);
        mockServer.verify();
    }
}

Best Practices при работе с погодными данными

  • Используй Retry механизм для ненадежных внешних API
  • Кэшируй результаты чтобы не перегружать API
  • Обрабатывай ошибки (город не найден, API недоступна, timeout)
  • Используй асинхронность для неблокирующих запросов
  • Валидируй входные данные (название города не может быть пусто)
  • Логируй запросы и ошибки
  • Тестируй с MockRestServiceServer или WireMock
Какая погода в твоем городе? | PrepBro