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
@@ -27,6 +27,9 @@ * @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
@@ -160,6 +160,45 @@ } }); 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 {