| package com.moral.api.service.impl; | 
|   | 
| import com.alibaba.fastjson.JSONObject; | 
| import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 
| import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; | 
| import com.moral.api.entity.CityAqiDaily; | 
| import com.moral.api.entity.CityAqiMonthly; | 
| import com.moral.api.mapper.CityAqiMonthlyMapper; | 
| import com.moral.api.service.CityAqiDailyService; | 
| import com.moral.api.service.CityAqiMonthlyService; | 
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | 
| import com.moral.constant.Constants; | 
| import com.moral.util.AmendUtils; | 
| import com.moral.util.ComprehensiveIndexUtils; | 
| import com.moral.util.DateUtils; | 
|   | 
| import org.springframework.beans.factory.annotation.Autowired; | 
| import org.springframework.stereotype.Service; | 
| import org.springframework.util.ObjectUtils; | 
|   | 
| import java.text.DecimalFormat; | 
| import java.util.ArrayList; | 
| import java.util.Arrays; | 
| import java.util.Date; | 
| import java.util.HashMap; | 
| import java.util.List; | 
| import java.util.Map; | 
| import java.util.OptionalDouble; | 
| import java.util.stream.Collectors; | 
| import java.util.stream.DoubleStream; | 
|   | 
| /** | 
|  * <p> | 
|  * 城市aqi月数据表 服务实现类 | 
|  * </p> | 
|  * | 
|  * @author moral | 
|  * @since 2021-11-04 | 
|  */ | 
| @Service | 
| public class CityAqiMonthlyServiceImpl extends ServiceImpl<CityAqiMonthlyMapper, CityAqiMonthly> implements CityAqiMonthlyService { | 
|   | 
|     @Autowired | 
|     private CityAqiMonthlyMapper cityAqiMonthlyMapper; | 
|   | 
|     @Autowired | 
|     private CityAqiDailyService cityAqiDailyService; | 
|   | 
|     @Override | 
|     public void insertCityAqiMonthly() { | 
|         //需要均值计算的因子 | 
|         List<String> sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2"); | 
|   | 
|         //开始时间,上月1号 | 
|         Date start = DateUtils.getFirstDayOfLastMonth(); | 
|         //上上月 | 
|         Date lastLastMonth = DateUtils.addMonths(start, -1); | 
|         //结束时间,本月1号 | 
|         Date end = DateUtils.addMonths(start, 1); | 
|   | 
|         //如果是1号,先删除上月数据再统计 | 
|         //不是1号,统计的是本月累计值,先删除本月数据 | 
|         int day = DateUtils.getDay(new Date()); | 
|         UpdateWrapper<CityAqiMonthly> cityAqiMonthlyUpdateWrapper = new UpdateWrapper<>(); | 
|         if (day == 1) { | 
|             cityAqiMonthlyUpdateWrapper.eq("time", start); | 
|         } else { | 
|             start = end; | 
|             end = DateUtils.addMonths(start, 1); | 
|             lastLastMonth = DateUtils.addMonths(start, -1); | 
|             cityAqiMonthlyUpdateWrapper.eq("time", start); | 
|         } | 
|         cityAqiMonthlyMapper.delete(cityAqiMonthlyUpdateWrapper); | 
|   | 
|   | 
|         //获取所有城市aqi小时数据 | 
|         QueryWrapper<CityAqiDaily> wrapper = new QueryWrapper<>(); | 
|         wrapper.select("city_code", "time", "value") | 
|                 .ge("time", start) | 
|                 .lt("time", end); | 
|         List<Map<String, Object>> monthlyData = cityAqiDailyService.listMaps(wrapper); | 
|   | 
|         if (monthlyData.size() == 0) { | 
|             return; | 
|         } | 
|         //按city_code分组 | 
|         Map<Integer, List<Map<String, Object>>> data = monthlyData.stream() | 
|                 .collect(Collectors.groupingBy(o ->Integer.parseInt(o.get("city_code").toString()) )); | 
|   | 
|         //获取上月数据,本月综指同上月对比 | 
|         QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>(); | 
|         queryWrapper.select("city_code", "value") | 
|                 .eq("time", lastLastMonth); | 
|         //获取上月数据 | 
|         List<CityAqiMonthly> lastCityAqiMonthlyList = cityAqiMonthlyMapper.selectList(queryWrapper); | 
|         Map<Integer, CityAqiMonthly> lastMonthData = new HashMap<>(); | 
|         for (CityAqiMonthly cityAqiMonthly : lastCityAqiMonthlyList) { | 
|             lastMonthData.put(cityAqiMonthly.getCityCode(), cityAqiMonthly); | 
|         } | 
|   | 
|   | 
|         //获取去年本月数据 | 
|         Date thisMonthOfLastYear = DateUtils.addYears(start, -1); | 
|         queryWrapper.clear(); | 
|         queryWrapper.select("city_code", "value") | 
|                 .eq("time", thisMonthOfLastYear); | 
|         List<CityAqiMonthly> thisMonthOfLastYearList = cityAqiMonthlyMapper.selectList(queryWrapper); | 
|         Map<Integer, CityAqiMonthly> thisMonthOfLastYearData = new HashMap<>(); | 
|         for (CityAqiMonthly cityAqiMonthly : thisMonthOfLastYearList) { | 
|             thisMonthOfLastYearData.put(cityAqiMonthly.getCityCode(), cityAqiMonthly); | 
|         } | 
|   | 
|   | 
|         List<CityAqiMonthly> cityAqiMonthlyList = new ArrayList<>(); | 
|   | 
|         Date finalStart = start; | 
|         data.forEach((cityCode, value) -> { | 
|             CityAqiMonthly cityAqiMonthly = new CityAqiMonthly(); | 
|             Map<String, Object> jsonMap = new HashMap<>(); | 
|             cityAqiMonthly.setCityCode(cityCode); | 
|             cityAqiMonthly.setTime(finalStart); | 
|   | 
|             Map<String, Object> params = new HashMap<>(); | 
|             List<Map<String, Object>> temp = new ArrayList<>(); | 
|             for (Map<String, Object> map : value) { | 
|                 Map<String, Object> sensorsValue = JSONObject.parseObject(map.get("value").toString(), Map.class); | 
|                 Map<String, Object> tempMap = new HashMap<>(); | 
|                 tempMap.put(Constants.SENSOR_CODE_CO, sensorsValue.get("CO")); | 
|                 tempMap.put(Constants.SENSOR_CODE_O3, sensorsValue.get("O3")); | 
|                 Map<String, Object> hashMap = new HashMap<>(); | 
|                 hashMap.put("value", JSONObject.toJSONString(tempMap)); | 
|                 temp.add(hashMap); | 
|             } | 
|             params.put("data", temp); | 
|             //1. CO 95百分位计算并修约 | 
|             Map<String, Object> coAvgOfWeekOrMonth = AmendUtils.getCOAvgOfWeekOrMonth(params); | 
|             if (!ObjectUtils.isEmpty(coAvgOfWeekOrMonth)) { | 
|                 jsonMap.put("CO", coAvgOfWeekOrMonth.get(Constants.SENSOR_CODE_CO)); | 
|             } | 
|   | 
|             //2. O3 90百分位计算并修约 | 
|             Map<String, Object> o3AvgOfWeekOrMonth = AmendUtils.getO3AvgOfWeekOrMonth(params); | 
|             if (!ObjectUtils.isEmpty(o3AvgOfWeekOrMonth)) { | 
|                 jsonMap.put("O3", o3AvgOfWeekOrMonth.get(Constants.SENSOR_CODE_O3)); | 
|             } | 
|   | 
|             sensors.forEach(sensor -> { | 
|                 OptionalDouble optionalDouble = value.stream().flatMapToDouble(v -> { | 
|                     Map<String, Object> dataValue = JSONObject.parseObject((String) v.get("value"), Map.class); | 
|                     double aDouble = Double.parseDouble(dataValue.get(sensor).toString()); | 
|                     return DoubleStream.of(aDouble); | 
|                 }).average(); | 
|                 if (optionalDouble.isPresent()) { | 
|                     //银行家算法修约 | 
|                     jsonMap.put(sensor, AmendUtils.sciCal(optionalDouble.getAsDouble(), 0)); | 
|                 } | 
|             }); | 
|   | 
|             //本月月综指计算 | 
|             Double compositeIndex = ComprehensiveIndexUtils.dailyData(jsonMap); | 
|             jsonMap.put("compositeIndex", compositeIndex); | 
|   | 
|             //本月综指同上月对比(综合指数环比) | 
|             CityAqiMonthly lastCityAqiMonthly = lastMonthData.get(cityCode); | 
|             if (lastCityAqiMonthly != null) { | 
|                 Map<String, Object> map = JSONObject.parseObject(lastCityAqiMonthly.getValue(), Map.class); | 
|                 double lastCompositeIndex = Double.parseDouble(map.get("compositeIndex").toString()); | 
|                 DecimalFormat decimalFormat = new DecimalFormat("0.00%"); | 
|                 String format = decimalFormat.format((compositeIndex - lastCompositeIndex) / lastCompositeIndex); | 
|                 jsonMap.put("monthContrast", format); | 
|             } | 
|   | 
|             //获取去年本月数据,用于计算同比 | 
|             CityAqiMonthly thisMonthOfLastYears = thisMonthOfLastYearData.get(cityCode); | 
|   | 
|             //各因子同比计算 | 
|             Map<String, Object> yearOnYearValue = yearOnYearOfSensor(thisMonthOfLastYears, jsonMap); | 
|             if (yearOnYearValue != null) { | 
|                 jsonMap.putAll(yearOnYearValue); | 
|             } | 
|   | 
|             cityAqiMonthly.setValue(JSONObject.toJSONString(jsonMap)); | 
|             cityAqiMonthlyList.add(cityAqiMonthly); | 
|         }); | 
|         cityAqiMonthlyMapper.insertCityAqiMonthly(cityAqiMonthlyList); | 
|     } | 
|   | 
|   | 
|     /** | 
|      * @param thisMonthOfLastYearData 去年本月数据 | 
|      * @param currentData             当前月该数据 | 
|      */ | 
|     private Map<String, Object> yearOnYearOfSensor(CityAqiMonthly thisMonthOfLastYearData, Map<String, Object> currentData) { | 
|         Map<String, Object> result = null; | 
|         //需要计算同比的因子 | 
|         List<String> sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2", "CO", "O3", "compositeIndex"); | 
|         if (thisMonthOfLastYearData != null) { | 
|             result = new HashMap<>(); | 
|             Map<String, Object> map = JSONObject.parseObject(thisMonthOfLastYearData.getValue(), Map.class); | 
|             for (String sensor : sensors) { | 
|                 //去年本月该因子值 | 
|                 double thisMonthOfLeastYearValue = Double.parseDouble(map.get(sensor).toString()); | 
|                 //当前该因子值 | 
|                 double currentValue = Double.parseDouble(currentData.get(sensor).toString()); | 
|                 DecimalFormat decimalFormat = new DecimalFormat("0.00%"); | 
|                 String format = decimalFormat.format((currentValue - thisMonthOfLeastYearValue) / thisMonthOfLeastYearValue); | 
|                 result.put(sensor + "_yearOnYear", format); | 
|             } | 
|         } | 
|         return result; | 
|     } | 
| } |