diff --git a/src/main/java/com/southern/power/grid/dao/RegionalWeatherDataMapper.java b/src/main/java/com/southern/power/grid/dao/RegionalWeatherDataMapper.java index a1adca8..3f94d12 100644 --- a/src/main/java/com/southern/power/grid/dao/RegionalWeatherDataMapper.java +++ b/src/main/java/com/southern/power/grid/dao/RegionalWeatherDataMapper.java @@ -3,7 +3,43 @@ package com.southern.power.grid.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.southern.power.grid.entity.RegionalWeatherData; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; @Mapper public interface RegionalWeatherDataMapper extends BaseMapper { + /** + * 插入一条区域气象数据记录 + * @param record 实体对象 + * @return 影响行数 + */ + int insert(RegionalWeatherData record); + + /** + * 根据主键ID查询 + * @param id 主键ID + * @return 实体对象 + */ + RegionalWeatherData selectByPrimaryKey(Long id); + + /** + * 根据地区编码和资料时次查询 + * @param orgCode 地区编码 + * @param dataTime 资料时次 + * @return 实体列表 + */ + List selectByOrgCodeAndDataTime(@Param("orgCode") String orgCode, @Param("dataTime") String dataTime); + + /** + * 根据条件动态查询 + * @param params 查询参数Map,支持: + * orgCode(精确匹配) + * dataTime(精确匹配) + * startCreateTime(创建时间起始,格式 yyyy-MM-dd HH:mm:ss) + * endCreateTime(创建时间结束) + * @return 实体列表 + */ + List selectByCondition(Map params); } diff --git a/src/main/java/com/southern/power/grid/entity/ExcelHourlyOutageRowDTO.java b/src/main/java/com/southern/power/grid/entity/ExcelHourlyOutageRowDTO.java deleted file mode 100644 index dd65ab0..0000000 --- a/src/main/java/com/southern/power/grid/entity/ExcelHourlyOutageRowDTO.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.southern.power.grid.entity; - -import lombok.Data; - -import java.time.LocalDateTime; - -@Data -public class ExcelHourlyOutageRowDTO { - /** 资料时次,对应分时表的 data_time */ - private LocalDateTime dataTime; - - /** Excel 中体现的南网省/地市局/区县局(用于映射) */ - private String nwProvince; - private String nwCity; - private String nwDistrict; - - /** 停电影响用户数等业务字段(示例) */ - private Integer userCount; - private Integer outageState; - private Integer outageType; - - // ... 根据你的 Excel 列补全 - - // getter/setter -} diff --git a/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java b/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java deleted file mode 100644 index e4db385..0000000 --- a/src/main/java/com/southern/power/grid/entity/HourlyStatisticDTO.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.southern.power.grid.entity; - -import lombok.Data; -import java.util.List; - -/** - * 分时统计结果DTO - */ -@Data -public class HourlyStatisticDTO { - private List timePoints; // 时间点列表,格式:yyyy-MM-dd HH:00:00 - private List userCounts; // 停电影响用户数 - private List precipitations; // 小时降水量 - private List avgTemperatures; // 平均气温 - private List maxTemperatures; // 最高气温 - private List minTemperatures; // 最低气温 - private List maxWindSpeeds; // 极大风速 -} diff --git a/src/main/java/com/southern/power/grid/entity/WeatherAreaDataDTO.java b/src/main/java/com/southern/power/grid/entity/WeatherAreaDataDTO.java deleted file mode 100644 index f7a53d2..0000000 --- a/src/main/java/com/southern/power/grid/entity/WeatherAreaDataDTO.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.southern.power.grid.entity; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 站点气象数据 - * - * @author: LIUZHIMING - * @date: 2026/3/17 - **/ -@Data -public class WeatherAreaDataDTO { - String districtCode; - private LocalDateTime dataTime; - - // 平均气温 - private String temperature; - // 小时最高气温 - private String hourlyMaxTemperature; - // 小时最低气温 - private String hourlyMinTemperature; - // 小时降雨量 - private Double hourlyPrecipitation; - // 日累计降雨量 - private String dailyPrecipitation; - // 小时内极大风速 - private String extremeWindSpeedHourly; -} diff --git a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java index 95dee20..fb75883 100644 --- a/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java +++ b/src/main/java/com/southern/power/grid/service/impl/HourlyOutageExcelProcessService.java @@ -1,15 +1,14 @@ package com.southern.power.grid.service.impl; -import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.southern.power.grid.dao.DnerHourlyPowerOutageEventMapper; import com.southern.power.grid.dao.NwSiteAreaConfigurationMapper; +import com.southern.power.grid.dao.RegionalWeatherDataMapper; import com.southern.power.grid.dao.WeatherSiteAreaConfigurationMapper; import com.southern.power.grid.entity.DataExcelEntity; import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent; import com.southern.power.grid.entity.NwSiteAreaConfiguration; -import com.southern.power.grid.entity.WeatherDataDTO; +import com.southern.power.grid.entity.RegionalWeatherData; import com.southern.power.grid.entity.WeatherSiteAreaConfiguration; -import com.southern.power.grid.service.WeatherDataService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -17,6 +16,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -32,11 +32,15 @@ public class HourlyOutageExcelProcessService { private WeatherSiteAreaConfigurationMapper weatherSiteAreaConfigurationMapper; @Resource - private WeatherDataService weatherDataService; + private RegionalWeatherDataMapper regionalWeatherDataMapper; @Resource private DnerHourlyPowerOutageEventMapper dnerHourlyPowerOutageEventMapper; + private static final Float lengthOutage = 60F; + + // 定义时间格式器(建议定义为静态常量,避免重复创建) + private static final DateTimeFormatter DATA_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** * 南网区域配置 * key = nw_province + "|" + nw_city + "|" + nw_district ;value = district_code @@ -61,10 +65,16 @@ public class HourlyOutageExcelProcessService { // 2. 加载气象区划配置表 loadWeatherAreaConfig(); - List toInsert = new ArrayList<>(); + // 使用 Map 存储待插入实体,Key 为 districtCode + "|" + dataTime + Map toInsertMap = new HashMap<>(); // 3 & 4. 循环处理 Excel 行 for (DataExcelEntity row : excelRows) { + if(row.getLengthOutage() weatherAreas = weatherAreaMap.get(districtCode); - if (weatherAreas == null) { - // 找不到对应气象站 - log.info("weatherAreas is null! {}", districtCode); - continue; - } - List stationIds = new ArrayList<>(); - for (WeatherSiteAreaConfiguration weatherArea : weatherAreas) { - String stationId = weatherArea.getStationId(); - if (StringUtils.isNotEmpty(stationId) && !stationIds.contains(stationId)) { - stationIds.add(stationId); - } - } - - // 3.3 通过 stationId + 时间,统一取8天气象数据(内部做缓存) - LocalDateTime dataTime = row.getStartTime(); - List weatherData = weatherDataService.getWeatherData(stationIds, dataTime); + // 3.2 获取区域时段内气象数据 + List regionalWeatherDataList = + regionalWeatherDataMapper.selectByOrgCodeAndDataTime(districtCode, DB_DATETIME_STR.format(row.getStartTime())); // 3.4 组装分时停电事件实体 - for (WeatherDataDTO weatherDataDTO : weatherData) { - DnerHourlyPowerOutageEvent entity = buildHourlyEvent(row, districtCode, weatherDataDTO); - toInsert.add(entity); + for (RegionalWeatherData regionalWeatherData : regionalWeatherDataList) { + LocalDateTime dataDateTime; + try { + dataDateTime = LocalDateTime.parse(regionalWeatherData.getDataTime(), DATA_TIME_FORMATTER); + } catch (DateTimeParseException e) { + log.warn("解析 dataTime 失败: {}", regionalWeatherData.getDataTime()); + continue; + } + if (row.getStartTime().isBefore(dataDateTime) && dataDateTime.isBefore(row.getEndTime())) { + String key = districtCode + "|" + regionalWeatherData.getDataTime(); + // 检查 Map 中是否已存在相同组合键 + DnerHourlyPowerOutageEvent existing = toInsertMap.get(key); + if (existing == null) { + // 不存在,创建新实体并放入 Map + DnerHourlyPowerOutageEvent entity = buildHourlyEvent(row, districtCode, regionalWeatherData); + toInsertMap.put(key, entity); + } else { + // 已存在,执行累加逻辑 + accumulateEvent(existing, row); + } + } } } - if (!toInsert.isEmpty()) { - // 4. 批量入库 + if (!toInsertMap.isEmpty()) { + // 将 Map 中的 values 转为 List 进行批量插入 + List toInsert = new ArrayList<>(toInsertMap.values()); dnerHourlyPowerOutageEventMapper.batchInsert(toInsert); } } + /** + * 累加已存在实体的字段 + * @param existing 已存在的实体 + * @param row 当前 Excel 行数据 + */ + private void accumulateEvent(DnerHourlyPowerOutageEvent existing, DataExcelEntity row) { + existing.setUserCount(row.getUserCount() + existing.getUserCount()); + } + /** * 加载南网区划配置 * **/ @@ -155,31 +177,31 @@ public class HourlyOutageExcelProcessService { private DnerHourlyPowerOutageEvent buildHourlyEvent(DataExcelEntity row, String districtCode, - WeatherDataDTO weatherData) { - DnerHourlyPowerOutageEvent e = new DnerHourlyPowerOutageEvent(); - e.setOrgCode(districtCode); + RegionalWeatherData regionalWeatherData) { + DnerHourlyPowerOutageEvent event = new DnerHourlyPowerOutageEvent(); + event.setOrgCode(districtCode); // 时间转成字符串,入库到 data_time if (row.getStartTime() != null) { - e.setDataTime(row.getStartTime().format(DB_DATETIME_STR)); + event.setDataTime(regionalWeatherData.getDataTime()); } // Excel 本身的业务字段 - e.setUserCount(row.getUserCount()); - e.setOutageState(row.getOutageState()); - e.setOutageType(row.getOutageType()); + event.setUserCount(row.getUserCount()); + event.setOutageState(row.getOutageState()); + event.setOutageType(row.getOutageType()); // 气象字段(如不存在数据可以为 null) - if (weatherData != null) { - e.setTemperature(weatherData.getTemperature()); - e.setHourlyMaxTemperature(weatherData.getHourlyMaxTemperature()); - e.setHourlyMinTemperature(weatherData.getHourlyMinTemperature()); -// e.setHourlyPrecipitation(weatherData.getHourlyPrecipitation()); - e.setDailyPrecipitation(weatherData.getDailyPrecipitation()); - e.setExtremeWindSpeedHourly(weatherData.getExtremeWindSpeedHourly()); + if (regionalWeatherData != null) { + event.setTemperature(regionalWeatherData.getTemperature()); + event.setHourlyMaxTemperature(regionalWeatherData.getHourlyMaxTemperature()); + event.setHourlyMinTemperature(regionalWeatherData.getHourlyMinTemperature()); + event.setHourlyPrecipitation(regionalWeatherData.getHourlyPrecipitation()); + event.setDailyPrecipitation(regionalWeatherData.getDailyPrecipitation()); + event.setExtremeWindSpeedHourly(regionalWeatherData.getExtremeWindSpeedHourly()); } // create_by/update_by 可根据当前登录用户等进行填充 - return e; + return event; } } diff --git a/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java b/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java deleted file mode 100644 index eeef9c6..0000000 --- a/src/main/java/com/southern/power/grid/service/impl/HourlyStatisticService.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.southern.power.grid.service.impl; - -import com.southern.power.grid.dao.DnerHourlyPowerOutageEventMapper; -import com.southern.power.grid.dao.NwSiteAreaConfigurationMapper; -import com.southern.power.grid.dao.WeatherSiteAreaConfigurationMapper; -import com.southern.power.grid.entity.DnerHourlyPowerOutageEvent; -import com.southern.power.grid.entity.HourlyStatisticDTO; -import com.southern.power.grid.entity.NwSiteAreaConfiguration; -import com.southern.power.grid.entity.WeatherDataDTO; -import com.southern.power.grid.entity.WeatherSiteAreaConfiguration; -import com.southern.power.grid.service.WeatherDataService; -import com.southern.power.grid.utils.TimeUtil; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -@Service -public class HourlyStatisticService { - - @Resource - private NwSiteAreaConfigurationMapper nwSiteAreaConfigurationMapper; - - @Resource - private WeatherSiteAreaConfigurationMapper weatherSiteAreaConfigurationMapper; - - @Resource - private WeatherDataService weatherDataService; - - @Resource - private DnerHourlyPowerOutageEventMapper dnerHourlyPowerOutageEventMapper; - - private static final DateTimeFormatter TIME_POINT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00"); - - /** - * 获取分时统计全量数据(包含所有指标) - * @param areaType 区域类型:province-省,city-市,county-县 - * @param areaCode 区域编码(省/市/县编码,县为org_code) - * @param startTime 开始时间(包含) - * @param endTime 结束时间(包含) - * @return 分时统计结果 - */ - public HourlyStatisticDTO getHourlyStatistics(String areaType, String areaCode, - LocalDateTime startTime, LocalDateTime endTime) { - // 1. 生成时间点列表(整点) - List timePoints = generateTimePoints(startTime, endTime); - if (timePoints.isEmpty()) { - return new HourlyStatisticDTO(); - } - - // 2. 根据区域类型获取需要统计的区县编码列表 - List districtCodes = getDistrictCodesByArea(areaType, areaCode); - if (districtCodes.isEmpty()) { - return new HourlyStatisticDTO(); - } - - // 3. 分别计算各指标 - HourlyStatisticDTO result = new HourlyStatisticDTO(); - result.setTimePoints(timePoints.stream().map(t -> t.format(TIME_POINT_FORMATTER)).collect(Collectors.toList())); - - // 3.1 停电用户数(直接查分时停电事件表) - Map userCountMap = calculateUserCount(districtCodes, timePoints); - result.setUserCounts(fillList(timePoints, userCountMap, 0L)); - - // 3.2 降水量(需要多站点平均) - Map precipMap = calculatePrecipitation(districtCodes, timePoints); - result.setPrecipitations(fillList(timePoints, precipMap, 0.0)); - - // 3.3 气温(平均/最高/最低) - TemperatureResult tempResult = calculateTemperature(districtCodes, timePoints); - result.setAvgTemperatures(fillList(timePoints, tempResult.getAvgMap(), 0.0)); - result.setMaxTemperatures(fillList(timePoints, tempResult.getMaxMap(), 0.0)); - result.setMinTemperatures(fillList(timePoints, tempResult.getMinMap(), 0.0)); - - // 3.4 风速(极大值) - Map windMap = calculateWindSpeed(districtCodes, timePoints); - result.setMaxWindSpeeds(fillList(timePoints, windMap, 0.0)); - - return result; - } - - /** - * 生成整点时间序列(从startTime的整点开始,到endTime的整点结束,包含首尾) - */ - private List generateTimePoints(LocalDateTime start, LocalDateTime end) { - List points = new ArrayList<>(); - LocalDateTime current = start.withMinute(0).withSecond(0).withNano(0); - LocalDateTime endPoint = end.withMinute(0).withSecond(0).withNano(0); - while (!current.isAfter(endPoint)) { - points.add(current); - current = current.plusHours(1); - } - return points; - } - - /** - * 根据区域类型获取所有需要统计的区县编码列表 - */ - private List getDistrictCodesByArea(String areaType, String areaCode) { - if ("county".equalsIgnoreCase(areaType)) { - return Collections.singletonList(areaCode); - } - - // 查询南网配置表,根据省/市编码获取所有区县编码 - List list; - if ("province".equalsIgnoreCase(areaType)) { - list = new ArrayList<>();// nwSiteAreaConfigurationMapper.selectByProvince(areaCode); - } else if ("city".equalsIgnoreCase(areaType)) { - list = new ArrayList<>(); // nwSiteAreaConfigurationMapper.selectByCity(areaCode); - } else { - return Collections.emptyList(); - } - - if (CollectionUtils.isEmpty(list)) { - return Collections.emptyList(); - } - return list.stream() - .map(NwSiteAreaConfiguration::getDistrictCode) - .filter(Objects::nonNull) - .distinct() - .collect(Collectors.toList()); - } - - // ===================== 停电用户数统计 ===================== - private Map calculateUserCount(List districtCodes, List timePoints) { - // 查询所有区县在时间范围内的停电事件记录 - List events = dnerHourlyPowerOutageEventMapper.selectByDistrictsAndTime( - districtCodes, timePoints.get(0), timePoints.get(timePoints.size() - 1).plusHours(1)); - - // 按区县和整点时刻聚合user_count - Map result = new HashMap<>(); - for (LocalDateTime tp : timePoints) { - result.put(tp, 0L); - } - - if (CollectionUtils.isEmpty(events)) { - return result; - } - - // 注意:data_time是停电开始时间,需按照“停电开始时间 > 整点时刻”的规则计入该整点 - // 但我们表中没有结束时间,无法精确统计“正在停电中”,此处采用简化规则:按开始时间所在小时计入 - // 若未来表添加end_time字段,可修改为更精确的逻辑 - for (DnerHourlyPowerOutageEvent event : events) { - if (event.getDataTime() == null) continue; - LocalDateTime start = TimeUtil.parseToLocalDateTime(event.getDataTime()); // 需要工具类解析字符串 - if (start == null) continue; - - // 找到大于start的最小整点(即start所在的下一个整点) - LocalDateTime targetHour = start.withMinute(0).withSecond(0).withNano(0).plusHours(1); - if (result.containsKey(targetHour)) { - result.merge(targetHour, event.getUserCount() == null ? 0L : event.getUserCount().longValue(), Long::sum); - } - } - - return result; - } - - // ===================== 降水量统计(多站平均) ===================== - private Map calculatePrecipitation(List districtCodes, List timePoints) { - // 1. 获取所有区县关联的气象站ID - List stationIds = getStationIdsByDistricts(districtCodes); - if (stationIds.isEmpty()) { - return emptyMap(timePoints); - } - - // 2. 批量获取所有站点的气象数据(按小时) - Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); - - // 3. 按小时计算各县平均降水量 - // 由于降水量县级规则是“国家站+区域站平均”,但我们有所有站的数据,需要先计算各县的平均值,再汇总 - // 简化:直接对所有站的数据按小时取平均(因为最终市级还需要再平均,最终结果等价于所有站的平均) - // 但需求要求县级统计时是县级内平均,市级统计时是各县平均再平均,因此必须按县分组先计算平均值 - // 此处我们实现为:先按县分组,每个小时取该县所有站的降水量平均值,得到各县小时降水量;然后所有县的小时降水量再平均(市级)或直接使用(县级) - // 但本方法返回值是总体结果,需要在调用前已经确定是县级还是市级,但调用时districtCodes已经是一个集合,方法需要返回这个集合整体的平均降水量。 - // 因此:对每个小时,计算所有区县在该小时的平均降水量(即先计算每个县内所有站的平均,再对这些县的平均取平均) - return calculateAverageByDistrict(stationDataMap, districtCodes, timePoints, - WeatherDataDTO::getHourlyPrecipitation); - } - - // ===================== 气温统计 ===================== - private TemperatureResult calculateTemperature(List districtCodes, List timePoints) { - // 1. 获取所有区县关联的气象站ID - List stationIds = getStationIdsByDistricts(districtCodes); - if (stationIds.isEmpty()) { - return new TemperatureResult(emptyMap(timePoints), emptyMap(timePoints), emptyMap(timePoints)); - } - - // 2. 获取所有站点的气象数据 - Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); - - // 3. 分别计算平均、最高、最低 - Map avgMap = calculateAverageByDistrict(stationDataMap, districtCodes, timePoints, - d -> parseDouble(d.getTemperature())); - Map maxMap = calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, - d -> parseDouble(d.getHourlyMaxTemperature()), true); - Map minMap = calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, - d -> parseDouble(d.getHourlyMinTemperature()), false); - - return new TemperatureResult(avgMap, maxMap, minMap); - } - - // ===================== 风速统计(极大值) ===================== - private Map calculateWindSpeed(List districtCodes, List timePoints) { - List stationIds = getStationIdsByDistricts(districtCodes); - if (stationIds.isEmpty()) { - return emptyMap(timePoints); - } - - Map> stationDataMap = batchFetchWeatherData(stationIds, timePoints); - - // 风速规则:先取各县内所有站的最大值,再取所有县的最大值(市级) - return calculateExtremeByDistrict(stationDataMap, districtCodes, timePoints, - d -> parseDouble(d.getExtremeWindSpeedHourly()), true); - } - - // ===================== 通用辅助方法 ===================== - - /** - * 根据区县编码列表获取所有气象站ID(去重) - */ - private List getStationIdsByDistricts(List districtCodes) { - if (CollectionUtils.isEmpty(districtCodes)) { - return Collections.emptyList(); - } - List configs = new ArrayList<>(); // new weatherSiteAreaConfigurationMapper.selectByDistrictCodes(districtCodes); - if (CollectionUtils.isEmpty(configs)) { - return Collections.emptyList(); - } - return configs.stream() - .map(WeatherSiteAreaConfiguration::getStationId) - .filter(Objects::nonNull) - .distinct() - .collect(Collectors.toList()); - } - - /** - * 批量获取多个站点在多个时间点的气象数据 - * @return Map> - */ - private Map> batchFetchWeatherData(List stationIds, - List timePoints) { - Map> result = new HashMap<>(); - for (String stationId : stationIds) { - Map stationHourly = new HashMap<>(); - for (LocalDateTime hour : timePoints) { -// WeatherDataDTO data = weatherDataService.getWeatherData(stationIds, hour); -// if (data != null) { -// stationHourly.put(hour, data); -// } - } - result.put(stationId, stationHourly); - } - return result; - } - - /** - * 计算按县平均后的指标(先求每个县内所有站的平均,再对各县平均取平均) - * @param stationDataMap 站点原始数据 - * @param districtCodes 区县列表 - * @param timePoints 时间点 - * @param valueExtractor 从WeatherDataDTO提取数值的函数 - * @return 每个小时的平均值 - */ - private Map calculateAverageByDistrict(Map> stationDataMap, - List districtCodes, - List timePoints, - Function valueExtractor) { - // 1. 建立区县 -> 站点ID列表的映射 - Map> districtStationMap = getDistrictStationMap(districtCodes); - - Map result = new HashMap<>(); - for (LocalDateTime hour : timePoints) { - List districtAverages = new ArrayList<>(); - for (String districtCode : districtCodes) { - List stations = districtStationMap.getOrDefault(districtCode, Collections.emptyList()); - List values = new ArrayList<>(); - for (String stationId : stations) { - WeatherDataDTO data = stationDataMap.getOrDefault(stationId, Collections.emptyMap()).get(hour); - Double val = valueExtractor.apply(data); - if (val != null) { - values.add(val); - } - } - if (!values.isEmpty()) { - double avg = values.stream().mapToDouble(Double::doubleValue).average().orElse(0.0); - districtAverages.add(avg); - } - } - // 所有县的平均再平均 - if (!districtAverages.isEmpty()) { - double overallAvg = districtAverages.stream().mapToDouble(Double::doubleValue).average().orElse(0.0); - result.put(hour, overallAvg); - } else { - result.put(hour, 0.0); - } - } - return result; - } - - /** - * 计算按县极值后的总体极值(先求每个县内所有站的极值,再取所有县的极值) - * @param isMax true-最大值,false-最小值 - */ - private Map calculateExtremeByDistrict(Map> stationDataMap, - List districtCodes, - List timePoints, - Function valueExtractor, - boolean isMax) { - Map> districtStationMap = getDistrictStationMap(districtCodes); - - Map result = new HashMap<>(); - for (LocalDateTime hour : timePoints) { - List districtExtremes = new ArrayList<>(); - for (String districtCode : districtCodes) { - List stations = districtStationMap.getOrDefault(districtCode, Collections.emptyList()); - Double extreme = null; - for (String stationId : stations) { - WeatherDataDTO data = stationDataMap.getOrDefault(stationId, Collections.emptyMap()).get(hour); - Double val = valueExtractor.apply(data); - if (val != null) { - if (extreme == null) { - extreme = val; - } else if (isMax) { - extreme = Math.max(extreme, val); - } else { - extreme = Math.min(extreme, val); - } - } - } - if (extreme != null) { - districtExtremes.add(extreme); - } - } - // 取所有县极值的极值 - if (!districtExtremes.isEmpty()) { - double overall = isMax ? - districtExtremes.stream().mapToDouble(Double::doubleValue).max().orElse(0.0) : - districtExtremes.stream().mapToDouble(Double::doubleValue).min().orElse(0.0); - result.put(hour, overall); - } else { - result.put(hour, 0.0); - } - } - return result; - } - - /** - * 获取区县到站点ID列表的映射 - */ - private Map> getDistrictStationMap(List districtCodes) { - List configs = new ArrayList<>(); // weatherSiteAreaConfigurationMapper.selectByDistrictCodes(districtCodes); - if (CollectionUtils.isEmpty(configs)) { - return Collections.emptyMap(); - } - return configs.stream() - .filter(c -> c.getStationId() != null) - .collect(Collectors.groupingBy(WeatherSiteAreaConfiguration::getDistrictCode, - Collectors.mapping(WeatherSiteAreaConfiguration::getStationId, Collectors.toList()))); - } - - /** - * 填充列表,确保每个时间点都有值 - */ - private List fillList(List timePoints, Map map, T defaultValue) { - List list = new ArrayList<>(); - for (LocalDateTime tp : timePoints) { - list.add(map.getOrDefault(tp, defaultValue)); - } - return list; - } - - private Map emptyMap(List timePoints) { - Map map = new HashMap<>(); - for (LocalDateTime tp : timePoints) { - map.put(tp, 0.0); - } - return map; - } - - private Double parseDouble(String str) { - try { - return str == null ? null : Double.parseDouble(str); - } catch (NumberFormatException e) { - return null; - } - } - - // 内部类,用于返回气温的三个Map - private static class TemperatureResult { - private final Map avgMap; - private final Map maxMap; - private final Map minMap; - - public TemperatureResult(Map avgMap, - Map maxMap, - Map minMap) { - this.avgMap = avgMap; - this.maxMap = maxMap; - this.minMap = minMap; - } - - public Map getAvgMap() { return avgMap; } - public Map getMaxMap() { return maxMap; } - public Map getMinMap() { return minMap; } - } -} \ No newline at end of file diff --git a/src/main/resources/mapper/RegionalWeatherDataMapper.xml b/src/main/resources/mapper/RegionalWeatherDataMapper.xml index b400625..4b84d69 100644 --- a/src/main/resources/mapper/RegionalWeatherDataMapper.xml +++ b/src/main/resources/mapper/RegionalWeatherDataMapper.xml @@ -4,5 +4,82 @@ + + + + + + + + + + + + + + + + + id, org_code, data_time, hourly_precipitation, daily_precipitation, temperature, + hourly_max_temperature, hourly_min_temperature, extreme_wind_speed_hourly, + create_by, create_time, update_by, update_time + + + + + INSERT INTO regional_weather_data ( + org_code, data_time, hourly_precipitation, daily_precipitation, + temperature, hourly_max_temperature, hourly_min_temperature, + extreme_wind_speed_hourly, create_by, update_by + ) VALUES ( + #{orgCode, jdbcType=VARCHAR}, + #{dataTime, jdbcType=VARCHAR}, + #{hourlyPrecipitation, jdbcType=VARCHAR}, + #{dailyPrecipitation, jdbcType=VARCHAR}, + #{temperature, jdbcType=VARCHAR}, + #{hourlyMaxTemperature, jdbcType=VARCHAR}, + #{hourlyMinTemperature, jdbcType=VARCHAR}, + #{extremeWindSpeedHourly, jdbcType=VARCHAR}, + #{createBy, jdbcType=VARCHAR}, + #{updateBy, jdbcType=VARCHAR} + ) + + + + + + + + + + \ No newline at end of file