Комментарии (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