jinpengyong
2021-11-02 bc85f620ec6bc7bdbe4c95fc227e1ee71119a9b9
省内排名,日综指计算任务
5 files added
6 files modified
350 ■■■■■ changed files
screen-api/src/main/java/com/moral/api/controller/AqiController.java 16 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/entity/CityAqiDaily.java 45 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/mapper/CityAqiDailyMapper.java 16 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/service/CityAqiDailyService.java 16 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/service/CityAqiService.java 17 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/service/impl/CityAqiDailyServiceImpl.java 20 ●●●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/service/impl/CityAqiServiceImpl.java 147 ●●●●● patch | view | raw | blame | history
screen-api/src/main/resources/mapper/CityAqiDailyMapper.xml 12 ●●●●● patch | view | raw | blame | history
screen-common/src/main/java/com/moral/util/ComprehensiveIndexUtils.java 53 ●●●● patch | view | raw | blame | history
screen-job/src/main/java/com/moral/api/service/impl/CityAqiDailyServiceImpl.java 6 ●●●●● patch | view | raw | blame | history
screen-job/src/main/java/com/moral/api/task/AqiInsertTask.java 2 ●●● patch | view | raw | blame | history
screen-api/src/main/java/com/moral/api/controller/AqiController.java
@@ -5,6 +5,7 @@
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -34,7 +35,7 @@
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "regionCode", value = "区号", required = true, paramType = "query", dataType = "String")
    })
    public ResultMessage MeasuredCompareForecast(HttpServletRequest request) {
    public ResultMessage measuredCompareForecast(HttpServletRequest request) {
        Map<String, Object> params = WebUtils.getParametersStartingWith(request, null);
        if (!params.containsKey("regionCode") || !params.containsKey("time")) {
            return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg());
@@ -68,4 +69,17 @@
        Map<String, Object> stringObjectMap = cityAqiService.query24HoursAqiByRegionCode(regionCode);
        return ResultMessage.ok(stringObjectMap);
    }
    @GetMapping("provincialRanking")
    @ApiOperation(value = "省内排名", notes = "省内排名")
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "organizationId", value = "组织id", required = true, paramType = "query", dataType = "Integer")
    })
    public ResultMessage provincialRanking(Integer organizationId) {
        if (ObjectUtils.isEmpty(organizationId)) {
            return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg());
        }
        Map<String, Object> response = cityAqiService.provincialRanking(organizationId);
        return ResultMessage.ok(response);
    }
}
screen-api/src/main/java/com/moral/api/entity/CityAqiDaily.java
New file
@@ -0,0 +1,45 @@
package com.moral.api.entity;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * <p>
 * 城市aqi日数据表
 * </p>
 *
 * @author moral
 * @since 2021-11-01
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class CityAqiDaily extends Model<CityAqiDaily> {
    private static final long serialVersionUID = 1L;
    /**
     * 城市id
     */
    private Integer cityCode;
    /**
     * 时间
     */
    private Date time;
    /**
     * 数据
     */
    private String value;
    @Override
    protected Serializable pkVal() {
        return null;
    }
}
screen-api/src/main/java/com/moral/api/mapper/CityAqiDailyMapper.java
New file
@@ -0,0 +1,16 @@
package com.moral.api.mapper;
import com.moral.api.entity.CityAqiDaily;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
 * <p>
 * 城市aqi日数据表 Mapper 接口
 * </p>
 *
 * @author moral
 * @since 2021-11-01
 */
public interface CityAqiDailyMapper extends BaseMapper<CityAqiDaily> {
}
screen-api/src/main/java/com/moral/api/service/CityAqiDailyService.java
New file
@@ -0,0 +1,16 @@
package com.moral.api.service;
import com.moral.api.entity.CityAqiDaily;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * 城市aqi日数据表 服务类
 * </p>
 *
 * @author moral
 * @since 2021-11-01
 */
public interface CityAqiDailyService extends IService<CityAqiDaily> {
}
screen-api/src/main/java/com/moral/api/service/CityAqiService.java
@@ -20,13 +20,16 @@
    List<Map<String, Object>> measuredCompareForecastOfO3(Map<String, Object> params);
    /**
    * @Description: 根据地区码查询aqi以及6参
            * @Param: [regionCode]
            * @return: java.util.Map<java.lang.String,java.lang.Object>
            * @Author: 陈凯裕
            * @Date: 2021/10/28
            */
    Map<String,Object> queryCityAqiByRegionCode(Integer regionCode);
     * @Description: 根据地区码查询aqi以及6参
     * @Param: [regionCode]
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @Author: 陈凯裕
     * @Date: 2021/10/28
     */
    Map<String, Object> queryCityAqiByRegionCode(Integer regionCode);
    //省内排名
    Map<String, Object> provincialRanking(Integer organizationId);
    /**
    * @Description: 根据地区码查询24小时的aqi
screen-api/src/main/java/com/moral/api/service/impl/CityAqiDailyServiceImpl.java
New file
@@ -0,0 +1,20 @@
package com.moral.api.service.impl;
import com.moral.api.entity.CityAqiDaily;
import com.moral.api.mapper.CityAqiDailyMapper;
import com.moral.api.service.CityAqiDailyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 城市aqi日数据表 服务实现类
 * </p>
 *
 * @author moral
 * @since 2021-11-01
 */
@Service
public class CityAqiDailyServiceImpl extends ServiceImpl<CityAqiDailyMapper, CityAqiDaily> implements CityAqiDailyService {
}
screen-api/src/main/java/com/moral/api/service/impl/CityAqiServiceImpl.java
@@ -4,13 +4,20 @@
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.moral.api.entity.CityAqi;
import com.moral.api.entity.CityAqiDaily;
import com.moral.api.entity.Forecast;
import com.moral.api.entity.Organization;
import com.moral.api.entity.SysArea;
import com.moral.api.mapper.CityAqiMapper;
import com.moral.api.mapper.ForecastMapper;
import com.moral.api.service.CityAqiDailyService;
import com.moral.api.service.CityAqiService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moral.api.service.OrganizationService;
import com.moral.api.service.SysAreaService;
import com.moral.constant.RedisConstants;
import com.moral.util.AQIUtils;
import com.moral.util.AmendUtils;
import com.moral.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +26,7 @@
import org.springframework.util.ObjectUtils;
import java.util.*;
import java.util.stream.DoubleStream;
/**
 * <p>
@@ -39,6 +47,15 @@
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrganizationService organizationService;
    @Autowired
    private SysAreaService sysAreaService;
    @Autowired
    private CityAqiDailyService cityAqiDailyService;
    @Override
    public List<Map<String, Object>> measuredCompareForecastOfO3(Map<String, Object> params) {
@@ -180,4 +197,134 @@
        redisTemplate.opsForHash().put(RedisConstants.CITY_AQI, regionCode, value);
        return JSON.parseObject(value, Map.class);
    }
    @Override
    public Map<String, Object> provincialRanking(Integer organizationId) {
        //结果集
        Map<String, Object> result = new HashMap<>();
        Date now = new Date();
        //昨日
        Date yesterday = DateUtils.dataToTimeStampTime(DateUtils.getDateOfDay(now, -1), DateUtils.yyyy_MM_dd_EN);
        String dateString = DateUtils.dateToDateString(yesterday, DateUtils.yyyy_MM_dd_HH_mm_ss_EN);
        //获取省,市code
        Organization organization = organizationService.getById(organizationId);
        Integer provinceCode = organization.getProvinceCode();
        Integer cityCode = organization.getCityCode();
        //获取省内所有city_code
        QueryWrapper<SysArea> wrapper = new QueryWrapper<>();
        wrapper.select("area_code").eq("parent_code", provinceCode);
        List<Object> cityCodes = sysAreaService.listObjs(wrapper);
        List<Map<String, Object>> ranks = new ArrayList<>();
        for (Object code : cityCodes) {
            Map<String, Object> rankMap = new HashMap<>();
            rankMap.put("cityCode", code);
            QueryWrapper<CityAqiDaily> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("value").eq("city_code", code).eq("time", dateString);
            //1.昨日数据
            CityAqiDaily one = cityAqiDailyService.getOne(queryWrapper);
            if (!ObjectUtils.isEmpty(one)) {
                String value = one.getValue();
                Map<String, Object> valueMap = JSONObject.parseObject(value, Map.class);
                rankMap.put("aqi", valueMap.get("aqi"));
            }
            //2.本月累计综合指数计算,截止到昨日
            queryWrapper.clear();
            //开始时间:本月1号,结束时间:昨日
            Date start = DateUtils.addMonths(DateUtils.getFirstDayOfLastMonth(), 1);
            queryWrapper.select("value").eq("city_code", code).ge("time", start).le("time", yesterday);
            List<CityAqiDaily> listMonth = cityAqiDailyService.list(queryWrapper);
            OptionalDouble averageMonth = listMonth.parallelStream().flatMapToDouble(v -> {
                Map<String, Object> dataValue = JSONObject.parseObject(v.getValue(), Map.class);
                Double compositeIndex = Double.parseDouble(dataValue.get("compositeIndex").toString());
                return DoubleStream.of(compositeIndex);
            }).average();
            if (averageMonth.isPresent()) {
                //银行家算法修约
                double compositeIndexAvgMonth = AmendUtils.sciCal(averageMonth.getAsDouble(), 2);
                rankMap.put("compositeIndexMonth", compositeIndexAvgMonth);
            }
            //3.本年累计综合指数计算,截止到昨日
            queryWrapper.clear();
            //开始时间:本年1.1号,结束时间:昨日
            String yearStart = DateUtils.dateToDateString(now, DateUtils.yyyy);
            queryWrapper.select("value").eq("city_code", code).ge("time", yearStart).le("time", yesterday);
            List<CityAqiDaily> listYear = cityAqiDailyService.list(queryWrapper);
            OptionalDouble averageYear = listYear.parallelStream().flatMapToDouble(v -> {
                Map<String, Object> dataValue = JSONObject.parseObject(v.getValue(), Map.class);
                Double compositeIndex = Double.parseDouble(dataValue.get("compositeIndex").toString());
                return DoubleStream.of(compositeIndex);
            }).average();
            if (averageYear.isPresent()) {
                //银行家算法修约
                double compositeIndexAvgYear = AmendUtils.sciCal(averageYear.getAsDouble(), 2);
                rankMap.put("compositeIndexYear", compositeIndexAvgYear);
            }
            ranks.add(rankMap);
        }
        //日排名,按aqi排序
        ranks.removeIf(o -> o.get("aqi") == null);
        sortByField(ranks, "aqi");
        //日排名结果
        Map<String, Object> dayMap = rankByField(ranks, cityCode, "aqi", cityCodes.size());
        dayMap.put("aqi", dayMap.remove("value"));
        result.put("day", dayMap);
        //月排名,按累计综指排
        ranks.removeIf(o -> o.get("compositeIndexMonth") == null);
        sortByField(ranks, "compositeIndexMonth");
        //月排名结果
        Map<String, Object> monthMap = rankByField(ranks, cityCode, "compositeIndexMonth", cityCodes.size());
        monthMap.put("compositeIndex", monthMap.remove("value"));
        result.put("month", monthMap);
        //年排名,按累计综指排
        sortByField(ranks, "compositeIndexYear");
        //年排名结果
        sortByField(ranks, "compositeIndexYear");
        Map<String, Object> yearMap = rankByField(ranks, cityCode, "compositeIndexYear", cityCodes.size());
        yearMap.put("compositeIndex", yearMap.remove("value"));
        result.put("year", yearMap);
        return result;
    }
    //按某字段排序
    private void sortByField(List<Map<String, Object>> list, String sortField) {
        list.sort((o1, o2) -> {
            double v1 = Double.parseDouble(o1.get(sortField).toString());
            double v2 = Double.parseDouble(o2.get(sortField).toString());
            if (v1 > v2) {
                return -1;
            } else if (v1 < v2) {
                return 1;
            }
            return 0;
        });
    }
    //排名
    private Map<String, Object> rankByField(List<Map<String, Object>> list, Integer cityCode, String rankField, Integer size) {
        Map<String, Object> result = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> map = list.get(i);
            if (cityCode == (int) map.get("cityCode")) {
                int rank = i + 1;
                result.put("rank", rank + "/" + size);
                Object value = map.get(rankField);
                result.put("value", value);
                break;
            }
        }
        return result;
    }
}
screen-api/src/main/resources/mapper/CityAqiDailyMapper.xml
New file
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.moral.api.mapper.CityAqiDailyMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.moral.api.entity.CityAqiDaily">
        <result column="city_code" property="cityCode"/>
        <result column="time" property="time"/>
        <result column="value" property="value"/>
    </resultMap>
</mapper>
screen-common/src/main/java/com/moral/util/ComprehensiveIndexUtils.java
@@ -45,12 +45,12 @@
        Double ICO = CCO / SCO;
        Double IO3 = CO3 / SO3;
        //计算综合指数
        Double comprehensiveIndex = MathUtils.add(ISO2,INO2);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex,IPM25);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex,IPM10);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex,ICO);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex,IO3);
        comprehensiveIndex = AmendUtils.sciCal(comprehensiveIndex,2);
        Double comprehensiveIndex = MathUtils.add(ISO2, INO2);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IPM25);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IPM10);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, ICO);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IO3);
        comprehensiveIndex = AmendUtils.sciCal(comprehensiveIndex, 2);
        return comprehensiveIndex;
    }
@@ -58,7 +58,7 @@
     * @Description: 计算各因子浓度值
     * SO2 NO2 PM10 PM2.5为月均浓度,CO取日均值的第九十五百分位,O3取日最大八小时值的第九十百分位
     * @Param: [datas]
     * @return: java.util.Map<java.lang.String   ,   java.lang.Object>
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @Author: 陈凯裕
     * @Date: 2021/9/27
     */
@@ -162,4 +162,43 @@
        return result;
    }
    /**
     * @Description: 获取日综合指数,参数为日六参数据
     * @Param: [data]
     * @return: Double
     */
    public static Double dailyData(Map<String, Object> data) {
        if (data == null)
            return null;
        Double CPM25 = (Double) data.get("pm2_5");
        Double CPM10 = (Double) data.get("pm10");
        Double CSO2 = (Double) data.get("so2");
        Double CNO2 = (Double) data.get("no2");
        Double CCO = (Double) data.get("co");
        Double CO3 = (Double) data.get("o3");
        //S开头为污染物年均值二级标准(当污染物是CO时,采用日均值二级标准。当污染是O3时,采用八小时均值二级标准)
        //数据来源GB 3095-2012
        Double SSO2 = 60d;
        Double SNO2 = 40d;
        Double SPM25 = 35d;
        Double SPM10 = 70d;
        Double SCO = 4d;
        Double SO3 = 160d;
        //计算污染物单项指数
        Double ISO2 = CSO2 / SSO2;
        Double INO2 = CNO2 / SNO2;
        Double IPM25 = CPM25 / SPM25;
        Double IPM10 = CPM10 / SPM10;
        Double ICO = CCO / SCO;
        Double IO3 = CO3 / SO3;
        //计算综合指数
        Double comprehensiveIndex = MathUtils.add(ISO2, INO2);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IPM25);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IPM10);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, ICO);
        comprehensiveIndex = MathUtils.add(comprehensiveIndex, IO3);
        comprehensiveIndex = AmendUtils.sciCal(comprehensiveIndex, 2);
        return comprehensiveIndex;
    }
}
screen-job/src/main/java/com/moral/api/service/impl/CityAqiDailyServiceImpl.java
@@ -9,6 +9,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moral.api.service.CityAqiService;
import com.moral.util.AmendUtils;
import com.moral.util.ComprehensiveIndexUtils;
import com.moral.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -101,6 +102,11 @@
                    jsonMap.put(sensor, sciCal);
                }
            });
            //日综合指数计算
            Double compositeIndex = ComprehensiveIndexUtils.dailyData(jsonMap);
            jsonMap.put("compositeIndex", compositeIndex);
            cityAqiDaily.setValue(JSONObject.toJSONString(jsonMap));
            cityAqiDailyMapper.insert(cityAqiDaily);
        });
screen-job/src/main/java/com/moral/api/task/AqiInsertTask.java
@@ -46,7 +46,7 @@
        return ReturnT.SUCCESS;
    }
    //撑城市aqi日数据统计
    //城市aqi日数据统计
    @XxlJob("insertCityAqiDaily")
    public ReturnT insertCityAqiDaily(){
        try {