package com.ruoyi.device.domain.impl; import com.alibaba.fastjson2.JSON; import com.ruoyi.device.config.DeviceCacheConfig; import com.ruoyi.device.domain.api.IWeatherDomain; import com.ruoyi.device.domain.impl.weather.HttpUtils; import com.ruoyi.device.domain.model.weather.Weather; import com.ruoyi.device.domain.model.weather.WeatherResponse; import com.ruoyi.device.domain.config.WeatherProperties; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; @Component @Slf4j public class WeatherDomainImpl implements IWeatherDomain { @Autowired private WeatherProperties weatherProperties; @Override @Cacheable(value = DeviceCacheConfig.WEATHER_CACHE, key = "#dockerDeviceIotId", unless = "#result == null") public Weather weatherInfo(String lat, String lon, String dockerDeviceIotId) { log.info("开始获取天气信息 - lat: {}, lon: {}", lat, lon); String host = weatherProperties.getHost(); String path = weatherProperties.getPath(); String method = "POST"; Map headers = new HashMap<>(); headers.put("Authorization", "APPCODE " + weatherProperties.getAppcode()); headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); Map querys = new HashMap<>(); Map bodys = new HashMap<>(); bodys.put("lat", lat); bodys.put("lon", lon); bodys.put("token", weatherProperties.getToken()); log.info("天气API配置 - host: {}, path: {}, token: {}", host, path, weatherProperties.getToken()); Weather weather = new Weather(); try { HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys); String json = EntityUtils.toString(response.getEntity()); log.info("天气API原始响应 - json: {}", json); WeatherResponse weatherResponse = JSON.parseObject(json, WeatherResponse.class); log.info("天气API解析结果 - weatherResponse: {}, code: {}", weatherResponse != null ? "not null" : "null", weatherResponse != null ? weatherResponse.getCode() : "N/A"); if (weatherResponse != null && weatherResponse.getCode() == 0) { String windLevel = weatherResponse.getData().getCondition().getWindLevel(); weather.setWindSpeed(convertWindLevelToSpeed(windLevel)); weather.setEnvironmentTemperature(Double.valueOf(weatherResponse.getData().getCondition().getTemp())); weather.setEnvironmentHumidity(Double.valueOf(weatherResponse.getData().getCondition().getHumidity())); String conditionId = weatherResponse.getData().getCondition().getConditionId(); weather.setRainfall(convertConditionIdToRainfall(conditionId)); log.info("天气数据解析成功 - windSpeed: {}, temp: {}, humidity: {}, rainfall: {}", weather.getWindSpeed(), weather.getEnvironmentTemperature(), weather.getEnvironmentHumidity(), weather.getRainfall()); } else { log.warn("天气API返回异常 - weatherResponse: {}, code: {}", JSON.toJSONString(weatherResponse), weatherResponse != null ? weatherResponse.getCode() : "null"); } log.info("lat {} log {} weather {}", lat, lon, JSON.toJSONString(weather)); return weather; } catch (Exception e) { log.error("获取天气信息异常 - lat: {}, lon: {}", lat, lon, e); return null; } } /** * 根据天气状况ID转换为降雨量等级 * @param conditionId 天气状况ID * @return 降雨量等级:0-无雨,1-小雨/小雪,2-中雨/中雪,3-大雨/大雪 */ private static Double convertConditionIdToRainfall(String conditionId) { if (conditionId == null || conditionId.isEmpty()) { return 0.0; // 默认无雨 } try { int id = Integer.parseInt(conditionId); // 小雨相关:阵雨、小阵雨、局部阵雨、小雨、小雨夹雪、小到中雨 if (id == 15 || id == 16 || id == 17 || id == 18 || id == 19 || id == 20 || id == 21 || id == 22 || id == 51 || id == 52 || id == 66 || id == 86 || id == 91) { return 1.0; // 小雨 } // 小雪相关:阵雪、小阵雪、小雪、小到中雪 if (id == 24 || id == 25 || id == 58 || id == 59 || id == 71 || id == 72 || id == 73 || id == 94) { return 1.0; // 小雪 } // 中雨相关:中雨、中到大雨 if (id == 53 || id == 67 || id == 92) { return 2.0; // 中雨 } // 中雪相关:中雪 if (id == 60 || id == 61) { return 2.0; // 中雪 } // 大雨相关:强阵雨、大雨、暴雨、大暴雨、特大暴雨、大到暴雨 if (id == 23 || id == 54 || id == 55 || id == 56 || id == 57 || id == 68 || id == 69 || id == 70 || id == 93) { return 3.0; // 大雨 } // 大雪相关:大雪、暴雪 if (id == 62 || id == 63 || id == 74 || id == 75 || id == 76) { return 3.0; // 大雪 } // 雷雨相关:雷阵雨、雷电、雷暴、雷阵雨伴有冰雹 if (id == 37 || id == 38 || id == 39 || id == 40 || id == 41 || id == 42 || id == 43 || id == 44 || id == 45 || id == 87 || id == 88 || id == 89 || id == 90 || id == 599) { return 1.0; // 雷阵雨按小雨处理 } // 雨夹雪、冻雨 if (id == 49 || id == 50 || id == 64 || id == 65) { return 1.0; // 雨夹雪按小雨处理 } // 冰雹、冰针、冰粒 if (id == 46 || id == 47 || id == 48) { return 1.0; // 冰雹按小雨处理 } // 雨(通用)、雪(通用) if (id == 78 || id == 77) { return 1.0; // 通用雨/雪按小雨处理 } // 其他情况(晴天、多云、阴天、雾、霾、沙尘等) return 0.0; // 无雨 } catch (NumberFormatException e) { return 0.0; // 解析失败,默认无雨 } } /** * 根据风力等级转换为风速中间值(单位:m/s) * @param windLevel 风力等级 * @return 风速中间值 */ private static Double convertWindLevelToSpeed(String windLevel) { if (windLevel == null || windLevel.isEmpty()) { return 0.1; // 默认无风的中间值 } try { int level = Integer.parseInt(windLevel); switch (level) { case 0: // 0-0.2 m/s return 0.1; case 1: // 0.3-1.5 m/s return 0.9; case 2: // 1.6-3.3 m/s return 2.45; case 3: // 3.4-5.4 m/s return 4.4; case 4: // 5.5-7.9 m/s return 6.7; case 5: // 8-10.7 m/s return 9.35; case 6: // 10.8-13.8 m/s return 12.3; case 7: // 13.9-17.1 m/s return 15.5; case 8: // 17.2-20.7 m/s return 18.95; case 9: // 20.8-24.4 m/s return 22.6; case 10: // 24.5-28.4 m/s return 26.45; case 11: // 28.5-32.6 m/s return 30.55; case 12: // 32.6-999.9 m/s (飓风) return 516.25; // (32.6 + 999.9) / 2 default: return 0.1; // 未知等级,默认无风 } } catch (NumberFormatException e) { return 0.1; // 解析失败,默认无风 } } }