package com.zhgd.xmgl.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.http.HttpException; import cn.hutool.http.HttpUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gexin.fastjson.JSON; import com.gexin.fastjson.JSONObject; import com.zhgd.redis.lock.RedisRepository; import com.zhgd.xmgl.modules.basicdata.entity.SystemAreas; import com.zhgd.xmgl.modules.basicdata.entity.SystemCities; import com.zhgd.xmgl.modules.basicdata.mapper.SystemAreasMapper; import com.zhgd.xmgl.modules.basicdata.mapper.SystemCitiesMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; /** * @program: wisdomSite * @description: 空气质量分析AQI * @author: Mr.Peng * @create: 2020-09-28 09:56 **/ @Slf4j @Component public class AqiUtil { private static SystemCitiesMapper systemCitiesMapper; private static SystemAreasMapper systemAreasMapper; private static RedisRepository redisRepository; public static String SYSTEM_CITIES_KEY = "SYSTEM_CITIES"; public static String WEATHER_DATA = "WEATHER_DATA:"; private static String tianqiUrl; private static String tianqiAppid; private static String tianqiAppsecret; /** * 天气质量 */ public static String WEATHER_QUALITY = "WEATHER_QUALITY:"; public static String WEATHER_LIVE = "WEATHER_LIVE:"; @Value("${tianqiUrl}") public void setTianqiUrl(String tianqiUrl) { AqiUtil.tianqiUrl = tianqiUrl; } @Value("${tianqiAppid}") public void setTianqiAppid(String tianqiAppid) { AqiUtil.tianqiAppid = tianqiAppid; } @Value("${tianqiAppsecret}") public void setTianqiAppsecret(String tianqiAppsecret) { AqiUtil.tianqiAppsecret = tianqiAppsecret; } @Autowired public void setSystemCitiesMapper(SystemCitiesMapper systemCitiesMapper) { AqiUtil.systemCitiesMapper = systemCitiesMapper; } @Autowired public void setSystemAreasMapper(SystemAreasMapper systemAreasMapper) { AqiUtil.systemAreasMapper = systemAreasMapper; } @Autowired public void setRedisRepository(RedisRepository redisRepository) { AqiUtil.redisRepository = redisRepository; } /** * 计算aqi值对应的等级 * * @param aqi * @return */ public static int getPollutionDegree(Double aqi) { int pollutionDegree = 1; if (aqi <= 50) { pollutionDegree = 1; } else if (aqi > 50 && aqi <= 100) { pollutionDegree = 2; } else if (aqi > 100 && aqi <= 150) { pollutionDegree = 3; } else if (aqi > 150 && aqi <= 200) { pollutionDegree = 4; } else if (aqi > 200 && aqi <= 300) { pollutionDegree = 5; } else if (aqi > 300) { pollutionDegree = 6; } return pollutionDegree; } /** * @param @param pollutionDegree * @param @return * @return String @throws * @Title: getDegree * @Description: 计算aqi值对应的等级 */ public static String getDegree(int pollutionDegree) { if (pollutionDegree == 1) { return "优"; } else if (pollutionDegree == 2) { return "良"; } else if (pollutionDegree == 3) { return "轻度污染"; } else if (pollutionDegree == 4) { return "中度污染"; } else if (pollutionDegree == 5) { return "重度污染"; } else if (pollutionDegree == 6) { return "严重污染"; } return "数据错误"; } /** * 计算每种污染物项目 P的空气质量分指数 * * @param cp 污染物项目P的质量浓度 * @param r 污染物项目P所在数组中的行号 * @return */ public static double countPerIaqi(double cp, int r) { double bph = 0; // 与 cp相近的污染物浓度限值的高位值 double bpl = 0; // 与 cp相近的污染物浓度限值的低位值 double iaqih = 0; // 与 bph对应的空气质量分指数 double iaqil = 0; // 与 bpl对应的空气质量分指数 double iaqip = 0; // 当前污染物项目P的空气质量分指数 // 空气质量分指数及对应的污染物项目浓度限值 int[][] aqiArr = {{0, 50, 100, 150, 200, 300, 400, 500}, {0, 35, 75, 115, 150, 250, 350, 500}, {0, 50, 150, 250, 350, 420, 500, 600}, {0, 2, 4, 14, 24, 36, 48, 60}, {0, 40, 80, 180, 280, 565, 750, 940}, {0, 160, 200, 300, 400, 800, 1000, 1200}, {0, 50, 150, 475, 800, 1600, 2100, 2620}, {0, 100, 160, 215, 265, 800}}; double min = aqiArr[r][0]; int index = aqiArr[r].length - 1; double max = aqiArr[r][index]; if (cp <= min || cp >= max) { return 0; } else { // 对每种污染物的bph、bpl、iaqih、iaqil进行赋值 for (int i = r; i < r + 1; i++) { for (int j = 0; j < aqiArr[0].length; j++) { if (cp < aqiArr[i][j]) { bph = aqiArr[i][j]; bpl = aqiArr[i][j - 1]; iaqih = aqiArr[0][j]; iaqil = aqiArr[0][j - 1]; break; } } } // 计算污染物项目 P的空气质量分指数 iaqip = (iaqih - iaqil) / (bph - bpl) * (cp - bpl) + iaqil; BigDecimal bg = new BigDecimal(Math.ceil(iaqip)); return bg.setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue(); } } public static double getPm10IAQI(double pmte) { if (pmte > 0) { long round = Math.round(pmte); return countPerIaqi(round, 2); } return 0; } public static double getPm25IAQI(double pmtw) { if (pmtw > 0) { long round = Math.round(pmtw); return countPerIaqi(round, 1); } return 0; } /** * 根据城市查询天气 * * @param areaCode * @return */ public static Double getWeatherInfo(String areaCode) { String key = WEATHER_QUALITY + areaCode; Object ro = redisRepository.get(key); if (ro != null) { return (Double) ro; } //空气指数 Double air = null; try { Map param = new HashMap<>(16); param.put("appid", tianqiAppid); param.put("appsecret", tianqiAppsecret); List systemAreas = systemAreasMapper.selectList(new LambdaQueryWrapper() .eq(SystemAreas::getAreaid, areaCode)); if (CollUtil.isNotEmpty(systemAreas)) { param.put("cityid", systemAreas.get(0).getWeathercityid()); } String urlString = tianqiUrl + "/free/day"; log.info("tianqi:url:{},param:{}", urlString, JSON.toJSONString(param)); String result = HttpUtil.get(urlString, param, 5000); log.info("tianqi:rs:{}", result); if (result != null && result.length() > 0) { JSONObject obj = JSONObject.parseObject(result); if (obj != null && obj.getString("air") != null) { air = Double.valueOf(obj.getString("air")); } } } catch (Exception e) { log.error("error:", e); } if (air == null) { air = 80d; } redisRepository.set(key, air, 60 * 60L); return air; } /** * 实况天气 * * @param cityCode cityid * @return */ public static Object getLiveWeatherInfo(String cityCode) { List systemCities = redisRepository.getOrSet(SYSTEM_CITIES_KEY, () -> systemCitiesMapper.selectList(null), 60 * 60L); String key = WEATHER_LIVE + cityCode; Object ro = redisRepository.get(key); if (ro != null) { return (HashMap) ro; } Map cityIdMap = systemCities.stream().collect(Collectors.toMap(e -> e.getCityid(), Function.identity(), (o, o2) -> o)); HashMap result = null; try { Map param = new HashMap<>(16); param.put("appid", tianqiAppid); param.put("appsecret", tianqiAppsecret); String cityId = Optional.ofNullable(cityIdMap.get(cityCode)).map(e -> e.getWeathercityid()).orElse(null); if (StringUtils.isNotBlank(cityId)) { param.put("cityid", cityId); } String urlString = tianqiUrl + "/free/day"; log.info("tianqi:url:{},param:{}", urlString, JSON.toJSONString(param)); String rs = HttpUtil.get(urlString, param, 5000); log.info("tianqi:rs:{}", rs); result = JSON.parseObject(rs, HashMap.class); } catch (Exception e) { log.error("error:", e); } redisRepository.set(key, result, 60 * 60L); return result; } public static String getWeatherData(String cityid) { String result = ""; try { result = redisRepository.getOrSet(WEATHER_DATA + cityid, () -> { Map param = new HashMap<>(16); param.put("unescape", "1"); param.put("appid", tianqiAppid); param.put("appsecret", tianqiAppsecret); if (StringUtils.isNotEmpty(cityid)) { param.put("cityid", cityid); } String r = HttpUtil.get(tianqiUrl + "/free/week", param); log.info("tianqi-getWeatherData:rs:{}", r); JSONObject jsonObject = JSONObject.parseObject(r); com.gexin.fastjson.JSONArray sevenDataArr = jsonObject.getJSONArray("data"); for (Object o : sevenDataArr) { JSONObject jo = (JSONObject) o; jo.put("cityid", jsonObject.get("cityid")); jo.put("city", jsonObject.get("city")); jo.put("cityEn", jsonObject.get("cityEn")); jo.put("country", jsonObject.get("country")); jo.put("countryEn", jsonObject.get("countryEn")); jo.put("update_time", jsonObject.get("update_time")); jo.put("tem1", jo.get("tem_day")); jo.put("tem2", jo.get("tem_night")); jo.put("day", jo.get("date")); } r = JSON.toJSONString(sevenDataArr); log.info(r); return r; }, 60 * 60L); } catch (Exception e) { log.error("error:", e); result = "[{\"date\":\"2023-12-11\",\"tem_day\":\"29\",\"tem2\":\"20\",\"tem1\":\"29\",\"city\":\"深圳\",\"tem_night\":\"20\",\"cityid\":\"101280601\",\"wea\":\"多云\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yun\",\"win_speed\":\"<3级\",\"win\":\"无持续风向\",\"day\":\"2023-12-11\"},{\"date\":\"2023-12-12\",\"tem_day\":\"27\",\"tem2\":\"20\",\"tem1\":\"27\",\"city\":\"深圳\",\"tem_night\":\"20\",\"cityid\":\"101280601\",\"wea\":\"多云转阴\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yun\",\"win_speed\":\"<3级转3-4级\",\"win\":\"无持续风向\",\"day\":\"2023-12-12\"},{\"date\":\"2023-12-13\",\"tem_day\":\"25\",\"tem2\":\"20\",\"tem1\":\"25\",\"city\":\"深圳\",\"tem_night\":\"20\",\"cityid\":\"101280601\",\"wea\":\"多云\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yun\",\"win_speed\":\"3-4级转<3级\",\"win\":\"东风\",\"day\":\"2023-12-13\"},{\"date\":\"2023-12-14\",\"tem_day\":\"26\",\"tem2\":\"23\",\"tem1\":\"26\",\"city\":\"深圳\",\"tem_night\":\"23\",\"cityid\":\"101280601\",\"wea\":\"阴\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yin\",\"win_speed\":\"3-4级转<3级\",\"win\":\"东风\",\"day\":\"2023-12-14\"},{\"date\":\"2023-12-15\",\"tem_day\":\"28\",\"tem2\":\"16\",\"tem1\":\"28\",\"city\":\"深圳\",\"tem_night\":\"16\",\"cityid\":\"101280601\",\"wea\":\"多云转阴\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yun\",\"win_speed\":\"<3级\",\"win\":\"无持续风向\",\"day\":\"2023-12-15\"},{\"date\":\"2023-12-16\",\"tem_day\":\"25\",\"tem2\":\"11\",\"tem1\":\"25\",\"city\":\"深圳\",\"tem_night\":\"11\",\"cityid\":\"101280601\",\"wea\":\"阴\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yin\",\"win_speed\":\"3-4级\",\"win\":\"东北风\",\"day\":\"2023-12-16\"},{\"date\":\"2023-12-17\",\"tem_day\":\"15\",\"tem2\":\"10\",\"tem1\":\"15\",\"city\":\"深圳\",\"tem_night\":\"10\",\"cityid\":\"101280601\",\"wea\":\"小雨\",\"update_time\":\"2023-12-11 10:47:17\",\"wea_img\":\"yu\",\"win_speed\":\"3-4级\",\"win\":\"北风\",\"day\":\"2023-12-17\"}]"; } return result; } /** * 获取风速等级 * * @param windSpeed * @return */ public static String getWindSpeedLevel(Double windSpeed) { //风级 名称 风速(m/s) (km/h) 陆地地面物象 //0 无风 0.0-0.2 <1 静,烟直上 //1 软风 0.3-1.5 1-5 烟示风向 //2 轻风 1.6-3.3 6-11 感觉有风 //3 微风 3.4-5.4 12-19 旌旗展开 //4 和风 5.5-7.9 20-28 吹起尘土 //5 清风 8.0-10.7 29-38 小树摇摆 //6 强风 10.8-13.8 39-49 电线有声 //7 劲风(疾风) 13.9-17.1 50-61 步行困难 //8 大风 17.2-20.7 62-74 折毁树枝 //9 烈风 20.8-24.4 75-88 小损房屋 //10 狂风 24.5-28.4 89-102 拔起树木 //11 暴风 28.5-32.6 103-117 损毁重大 //12 台风(一级飓风) 32.7-36.9 117-134 摧毁极大 //13 台风(一级飓风) 37.0-41.4 134-149 //14 强台风(二级飓风) 41.5-46.1 150-166 //15 强台风(三级飓风) 46.2-50.9 167-183 //16 超强台风(三级飓风) 51.0-56.0 184-201 //17 超强台风(四级飓风) 56.1-61.2 202-220 //17+ 超强台风(四级飓风) ≥61.3 ≥221 //超级台风(五级飓风) ≥250 if (windSpeed == null) { return null; } if (windSpeed >= 0 && windSpeed < 0.3) { return "0级"; } else if (windSpeed >= 0.3 && windSpeed < 1.6) { return "1级"; } else if (windSpeed >= 1.6 && windSpeed < 3.4) { return "2级"; } else if (windSpeed >= 3.4 && windSpeed < 5.5) { return "3级"; } else if (windSpeed >= 5.5 && windSpeed < 8) { return "4级"; } else if (windSpeed >= 8 && windSpeed < 10.8) { return "5级"; } else if (windSpeed >= 10.8 && windSpeed < 13.9) { return "6级"; } else if (windSpeed >= 13.9 && windSpeed < 17.2) { return "7级"; } else if (windSpeed >= 17.2 && windSpeed < 20.8) { return "8级"; } else if (windSpeed >= 20.8 && windSpeed < 24.5) { return "9级"; } else if (windSpeed >= 24.5 && windSpeed < 28.5) { return "10级"; } else if (windSpeed >= 28.5 && windSpeed < 32.7) { return "11级"; } else if (windSpeed >= 32.7 && windSpeed < 37) { return "12级"; } else if (windSpeed >= 37 && windSpeed < 41.5) { return "13级"; } else if (windSpeed >= 41.5 && windSpeed < 46.2) { return "14级"; } else if (windSpeed >= 46.2 && windSpeed < 51) { return "15级"; } else if (windSpeed >= 51 && windSpeed < 56.1) { return "16级"; } else if (windSpeed >= 56.1 && windSpeed < 61.3) { return "17级"; } else if (windSpeed >= 61.3) { return "17+级"; } return null; } public static void main(String[] args) { /*double temp=getPm25IAQI(85d); log.info(temp); log.info(getDegree(getPollutionDegree(temp)));级*/ //log.info(getWeatherInfo("110100")); //log.info(getWeatherData("110100")); //System.out.println(getWeatherInfo("11")); //log.info(getDegree(getPollutionDegree(39d))); try { String result = HttpUtil.get("https://v0.yiketianqi.com/free/day", 1000); } catch (HttpException e) { log.error("error:", e); } System.out.println(123); } }