GetWeather.java 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. package com.example.getweather.service;
  2. import cn.hutool.core.date.DateUtil;
  3. import cn.hutool.db.Db;
  4. import cn.hutool.db.Entity;
  5. import cn.hutool.http.HttpUtil;
  6. import cn.hutool.json.JSONArray;
  7. import cn.hutool.json.JSONObject;
  8. import cn.hutool.json.JSONUtil;
  9. import com.example.getweather.entity.DistrictCodeDO;
  10. import com.example.getweather.entity.HeFengDay;
  11. import com.example.getweather.util.WeixinPush;
  12. import com.taosdata.jdbc.TSDBDriver;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.springframework.stereotype.Service;
  15. import org.springframework.validation.annotation.Validated;
  16. import javax.annotation.Resource;
  17. import java.math.BigDecimal;
  18. import java.math.RoundingMode;
  19. import java.sql.Connection;
  20. import java.sql.DriverManager;
  21. import java.sql.Statement;
  22. import java.sql.Timestamp;
  23. import java.text.SimpleDateFormat;
  24. import java.time.Instant;
  25. import java.time.LocalDate;
  26. import java.time.ZonedDateTime;
  27. import java.util.*;
  28. import java.util.stream.Collectors;
  29. @Service
  30. @Validated
  31. @Slf4j
  32. public class GetWeather {
  33. @Resource
  34. private WeixinPush weixinPush;
  35. /**
  36. * 根据风速获取对应风力等级
  37. * 2025-01-09 改为km/h单位
  38. *
  39. * @param speed 风速,单位为 km/h
  40. * @return 风力等级
  41. */
  42. public static int speedLevel(String speed) {
  43. BigDecimal val = new BigDecimal(speed);
  44. //<0.3 无风 0级
  45. if (val.compareTo(new BigDecimal("1")) < 0) {
  46. return 0;
  47. } else if (val.compareTo(new BigDecimal("6")) < 0) {
  48. //0.3-1.6 微风徐徐 1级
  49. return 1;
  50. } else if (val.compareTo(new BigDecimal("12")) < 0) {
  51. //1.6-3.4 清风 2级
  52. return 2;
  53. } else if (val.compareTo(new BigDecimal("20")) < 0) {
  54. //3.4-5.5 树叶摇摆 3级
  55. return 3;
  56. } else if (val.compareTo(new BigDecimal("29")) < 0) {
  57. //5.5-8.0 树枝摇动 4级
  58. return 4;
  59. } else if (val.compareTo(new BigDecimal("39")) < 0) {
  60. //8.0-10.8 风吹折小树 5级
  61. return 5;
  62. } else if (val.compareTo(new BigDecimal("50")) < 0) {
  63. //10.8-13.9 树枝折断 6级
  64. return 6;
  65. } else if (val.compareTo(new BigDecimal("62")) < 0) {
  66. //13.9-17.2 风吹倒树木 7级
  67. return 7;
  68. } else if (val.compareTo(new BigDecimal("75")) < 0) {
  69. //17.2-20.8 风吹断大树 8级
  70. return 8;
  71. } else if (val.compareTo(new BigDecimal("89")) < 0) {
  72. //20.8-24.5 强风 9级
  73. return 9;
  74. } else if (val.compareTo(new BigDecimal("103")) < 0) {
  75. //24.5-28.5 狂风 10级
  76. return 10;
  77. } else if (val.compareTo(new BigDecimal("117")) < 0) {
  78. //28.5-32.7 暴风 11级
  79. return 11;
  80. } else if (val.compareTo(new BigDecimal("134")) < 0) {
  81. //32.7-37.0 大暴风 12级
  82. return 12;
  83. } else if (val.compareTo(new BigDecimal("150")) < 0) {
  84. //37.0-41.5 飓风 13级
  85. return 13;
  86. } else if (val.compareTo(new BigDecimal("167")) < 0) {
  87. //41.5-46.2 强飓风 14级
  88. return 14;
  89. } else if (val.compareTo(new BigDecimal("184")) < 0) {
  90. //46.2-50.9 猛烈飓风 15级
  91. return 15;
  92. } else if (val.compareTo(new BigDecimal("202")) < 0) {
  93. //50.9-56.1 毁灭性飓风 16级
  94. return 16;
  95. } else {
  96. //56.1-61.3 超级飓风 17级
  97. return 17;
  98. }
  99. }
  100. public static Timestamp convertStringToTimestamp(String dateStr) {
  101. LocalDate localDate = LocalDate.parse(dateStr); // 解析 yyyy-MM-dd
  102. return Timestamp.valueOf(localDate.atStartOfDay()); // 转换为当天的开始时间
  103. }
  104. public void download() {
  105. List<String> areaCodes = new ArrayList<>();
  106. List<DistrictCodeDO> districtCodeDOList = new ArrayList<>();
  107. List<DistrictCodeDO> districtCodeDOList1 = new ArrayList<>();
  108. boolean isApiQuotaExhausted = false; // 引入标志变量
  109. String startDate = DateUtil.today();
  110. String endDate = DateUtil.offsetDay(DateUtil.date(), 15).toString("yyyy-MM-dd");
  111. try {
  112. List<Entity> dictList = Db.use().findAll("system_dict_data");
  113. for (Entity entity : dictList) {
  114. String name = entity.getStr("label");
  115. if (name.contains("area_code")) {
  116. String code = entity.getStr("value");
  117. String[] s = code.split(",");
  118. areaCodes = Arrays.asList(s);
  119. }
  120. }
  121. List<Entity> districtCodes = Db.use().findAll("jy_district_code");
  122. for (Entity e : districtCodes) {
  123. DistrictCodeDO districtCodeDO = new DistrictCodeDO();
  124. districtCodeDO.setCode(e.getStr("code"));
  125. districtCodeDO.setName(e.getStr("name"));
  126. districtCodeDO.setLevel(Integer.parseInt(e.getStr("level")));
  127. districtCodeDO.setType(Integer.parseInt(e.getStr("type")));
  128. districtCodeDO.setAbname(e.getStr("abname"));
  129. districtCodeDO.setPid(Integer.parseInt(e.getStr("pid")));
  130. districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  131. districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  132. districtCodeDOList.add(districtCodeDO);
  133. }
  134. List<Entity> districtCodes1 = Db.use().findAll("jy_power_station");
  135. for (Entity e : districtCodes1) {
  136. DistrictCodeDO districtCodeDO = new DistrictCodeDO();
  137. districtCodeDO.setCode(e.getStr("code"));
  138. districtCodeDO.setName(e.getStr("name"));
  139. districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  140. districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  141. districtCodeDOList1.add(districtCodeDO);
  142. }
  143. String jdbcUrl = "jdbc:TAOS://192.168.12.241:29500/etadm_local?user=root&password=taosdata";
  144. Properties connProps = new Properties();
  145. connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
  146. connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
  147. connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
  148. Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
  149. //省份
  150. for (String code : areaCodes) {
  151. //只有甘肃用xmo天气日接口
  152. if (code.equals("620000")) {
  153. if (isApiQuotaExhausted) break; // 检查标志变量
  154. List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
  155. //市
  156. for (DistrictCodeDO d : shiList) {
  157. if (isApiQuotaExhausted) break; // 检查标志变量
  158. List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode())).collect(Collectors.toList());
  159. String xmoUrl;
  160. //xmo综合数据查询
  161. xmoUrl = "https://weather-api.xm-opt.com/v1/forecastDaily?latitude=" + d.getLat() + "&longitude=" + d.getLng() + "&daily=weather_code,temperature_2m_max,rain_sum,wind_speed_10m_max,wind_direction_10m_dominant,shortwave_radiation_sum,temperature_2m_min,precipitation_sum&timezone=Asia%2FShanghai&start_date=" + startDate + "&end_date=" + endDate;
  162. isApiQuotaExhausted = analysisXMO(xmoUrl, d.getCode(), d.getName(), conn); // 传递标志变量
  163. if (isApiQuotaExhausted) break; // 检查标志变量
  164. //区
  165. for (DistrictCodeDO q : quList) {
  166. if (isApiQuotaExhausted) break; // 检查标志变量
  167. xmoUrl = "https://weather-api.xm-opt.com/v1/forecastDaily?latitude=" + q.getLat() + "&longitude=" + q.getLng() + "&daily=weather_code,temperature_2m_max,rain_sum,wind_speed_10m_max,wind_direction_10m_dominant,shortwave_radiation_sum,temperature_2m_min,precipitation_sum&timezone=Asia%2FShanghai&start_date=" + startDate + "&end_date=" + endDate;
  168. isApiQuotaExhausted = analysisXMO(xmoUrl, q.getCode(), q.getName(), conn); // 传递标志变量
  169. if (isApiQuotaExhausted) break; // 检查标志变量
  170. //线程睡5秒 防止请求过快
  171. //花钱了 硬气 不管他
  172. //Thread.sleep(5000);
  173. }
  174. }
  175. //2025-07-18 新增 甘肃库里 powerstation表里场站的经纬度也获取数据, td表的tag是场站编号而不是地区编号
  176. for (DistrictCodeDO d : districtCodeDOList1) {
  177. String xmoUrl = "https://weather-api.xm-opt.com/v1/forecastDaily?latitude=" + d.getLat() + "&longitude=" + d.getLng() + "&daily=weather_code,temperature_2m_max,rain_sum,wind_speed_10m_max,wind_direction_10m_dominant,shortwave_radiation_sum,temperature_2m_min,precipitation_sum&timezone=Asia%2FShanghai&start_date=" + startDate + "&end_date=" + endDate;
  178. if (isApiQuotaExhausted) break; // 检查标志变量
  179. isApiQuotaExhausted = analysisXMO(xmoUrl, d.getCode(), d.getName(), conn); // 传递标志变量
  180. if (isApiQuotaExhausted) break; // 检查标志变量
  181. }
  182. } else {
  183. if (isApiQuotaExhausted) break; // 检查标志变量
  184. List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
  185. //市
  186. for (DistrictCodeDO d : shiList) {
  187. if (isApiQuotaExhausted) break; // 检查标志变量
  188. List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode())).collect(Collectors.toList());
  189. String caiyun;
  190. //彩云综合数据查询
  191. caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
  192. isApiQuotaExhausted = analysis(caiyun, d.getCode(), d.getName(), conn); // 传递标志变量
  193. if (isApiQuotaExhausted) break; // 检查标志变量
  194. //区
  195. for (DistrictCodeDO q : quList) {
  196. if (isApiQuotaExhausted) break; // 检查标志变量
  197. caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
  198. isApiQuotaExhausted = analysis(caiyun, q.getCode(), q.getName(), conn); // 传递标志变量
  199. if (isApiQuotaExhausted) break; // 检查标志变量
  200. //线程睡5秒 防止请求过快
  201. //花钱了 硬气 不管他
  202. //Thread.sleep(5000);
  203. }
  204. }
  205. }
  206. }
  207. conn.close();
  208. String alarm = "电力交易系统在获取日级天气数据时报错, 彩云天气API 额度已用尽";
  209. String description = "接口调用异常";
  210. if (isApiQuotaExhausted) {
  211. //给企业微信发送消息
  212. weixinPush.sendMessageBot(alarm, description);
  213. } else {
  214. alarm = "电力交易系统每日天气数据全部下载完毕";
  215. description = "接口调用成功";
  216. weixinPush.sendMessageBot(alarm, description);
  217. log.info("每日天气数据全部下载完毕");
  218. }
  219. } catch (Exception e) {
  220. e.printStackTrace();
  221. }
  222. }
  223. public boolean analysis(String caiyun, String areaCode, String name, Connection conn) {
  224. log.info("开始下载地区:{} 的天气数据", name);
  225. try {
  226. Statement ps = conn.createStatement();
  227. String caiyunBody = HttpUtil.createGet(caiyun).execute().charset("utf-8").body();
  228. JSONObject caiyunjsonObject = JSONUtil.parseObj(caiyunBody);
  229. if (caiyunjsonObject.toString().contains("API quota is exhausted")) {
  230. return true;
  231. }
  232. JSONObject caiyunResult = JSONUtil.parseObj(caiyunjsonObject.get("result"));
  233. //小时数据 72小时
  234. /*JSONObject hourly = JSONUtil.parseObj(caiyunResult.get("hourly"));
  235. //小时->温度
  236. JSONArray temperature = JSONUtil.parseArray(hourly.get("temperature"));
  237. //小时->辐照度
  238. JSONArray dswrf = JSONUtil.parseArray(hourly.get("dswrf"));
  239. //小时->风速
  240. JSONArray windSpeed = JSONUtil.parseArray(hourly.get("wind"));
  241. //小时->天气标识
  242. JSONArray skyconHour = JSONUtil.parseArray(hourly.get("skycon"));
  243. //小时->湿度
  244. JSONArray humidityHour = JSONUtil.parseArray(hourly.get("humidity"));
  245. //小时->压强
  246. JSONArray pressureHour = JSONUtil.parseArray(hourly.get("pressure"));*/
  247. //日数据 7d
  248. JSONObject daily = JSONUtil.parseObj(caiyunResult.get("daily"));
  249. //日->辐照度
  250. JSONArray dswrfDay = JSONUtil.parseArray(daily.get("dswrf"));
  251. //日->温度
  252. JSONArray temperatureDay = JSONUtil.parseArray(daily.get("temperature"));
  253. //日->风速 8点到20点
  254. JSONArray windSpeed8Day = JSONUtil.parseArray(daily.get("wind_08h_20h"));
  255. //日->风速 20点到32点
  256. JSONArray windSpeed20Day = JSONUtil.parseArray(daily.get("wind_20h_32h"));
  257. //日->天气描述 8点到20点
  258. JSONArray skycon8 = JSONUtil.parseArray(daily.get("skycon_08h_20h"));
  259. //日->天气描述 20点到32点
  260. JSONArray skycon20 = JSONUtil.parseArray(daily.get("skycon_20h_32h"));
  261. //小时数据写入。 时间 风速 辐照度
  262. /*List<HeFengHour> heFengHourList = new ArrayList<>();
  263. if (windSpeed.size() == 72 && dswrf.size() == 72 && temperature.size() == 72) {
  264. for (int i = 0; i < windSpeed.size(); i++) {
  265. String time = ((JSONObject) windSpeed.get(i)).get("datetime").toString();
  266. HeFengHour heFengHour = new HeFengHour();
  267. heFengHour.setTs(getTimestamp(time));
  268. heFengHour.setWindSpeed(new BigDecimal(((JSONObject) windSpeed.get(i)).get("speed").toString()).floatValue());
  269. heFengHour.setWindSpeedM(new BigDecimal(((JSONObject) windSpeed.get(i)).get("speed").toString()).floatValue() * 1000 / 3600);
  270. heFengHour.setWindScale(speedLevel(((JSONObject) windSpeed.get(i)).get("speed").toString()));
  271. heFengHour.setWind360(new BigDecimal(((JSONObject) windSpeed.get(i)).get("direction").toString()).floatValue());
  272. heFengHour.setHumidity(new BigDecimal(((JSONObject) humidityHour.get(i)).get("value").toString()).floatValue());
  273. heFengHour.setPressure(new BigDecimal(((JSONObject) pressureHour.get(i)).get("value").toString()).floatValue());
  274. heFengHour.setText(skycon(((JSONObject) skyconHour.get(i)).get("value").toString()));
  275. heFengHour.setDswrf(new BigDecimal(((JSONObject) dswrf.get(i)).get("value").toString()).floatValue());
  276. heFengHour.setTemp(new BigDecimal(((JSONObject) temperature.get(i)).get("value").toString()).floatValue());
  277. heFengHourList.add(heFengHour);
  278. }
  279. } else {
  280. log.info("{} 的彩云小时数据不足72小时,不入库!", name);
  281. }*/
  282. //日数据写入
  283. List<HeFengDay> heFengDayList = new ArrayList<>();
  284. if (windSpeed8Day.size() == 7 && windSpeed20Day.size() == 7 && skycon8.size() == 7 && skycon20.size() == 7 && dswrfDay.size() == 7 & temperatureDay.size() == 7) {
  285. for (int i = 0; i < windSpeed8Day.size(); i++) {
  286. String time = ((JSONObject) windSpeed8Day.get(i)).get("date").toString();
  287. //白天风速
  288. Map windspeedDay = (Map) ((JSONObject) windSpeed8Day.get(i)).get("avg");
  289. String windspeedDay1 = windspeedDay.get("speed").toString();
  290. //白天风向
  291. String wind360Day1 = windspeedDay.get("direction").toString();
  292. //夜间风速
  293. Map windspeedNight = (Map) ((JSONObject) windSpeed20Day.get(i)).get("avg");
  294. String windspeedNight1 = windspeedNight.get("speed").toString();
  295. String wind360Night1 = windspeedNight.get("direction").toString();
  296. //辐照度
  297. String dswrf1 = ((JSONObject) dswrfDay.get(i)).get("avg").toString();
  298. //白天天气
  299. String skycon = ((JSONObject) skycon8.get(i)).get("value").toString();
  300. //夜间天气
  301. String skyconN = ((JSONObject) skycon20.get(i)).get("value").toString();
  302. //最高温度
  303. String temperatureMax = ((JSONObject) temperatureDay.get(i)).get("max").toString();
  304. //最低温度
  305. String temperatureMin = ((JSONObject) temperatureDay.get(i)).get("min").toString();
  306. HeFengDay heFengDay = new HeFengDay();
  307. heFengDay.setTs(getTimestamp(time));
  308. heFengDay.setWindSpeedDay(new BigDecimal(windspeedDay1).floatValue());
  309. heFengDay.setWindSpeedMDay(new BigDecimal(windspeedDay1).floatValue() * 1000 / 3600);
  310. heFengDay.setWind360Day(new BigDecimal(wind360Day1).floatValue());
  311. heFengDay.setWindScaleDay(speedLevel(windspeedDay1));
  312. heFengDay.setWindSpeedNight(new BigDecimal(windspeedNight1).floatValue());
  313. heFengDay.setWindSpeedMNight(new BigDecimal(windspeedNight1).floatValue() * 1000 / 3600);
  314. heFengDay.setWind360Night(new BigDecimal(wind360Night1).floatValue());
  315. heFengDay.setWindScaleNight(speedLevel(windspeedNight1));
  316. heFengDay.setDswrf(new BigDecimal(dswrf1).floatValue());
  317. heFengDay.setTextDay(skycon(skycon));
  318. heFengDay.setTextNight(skycon(skyconN));
  319. heFengDay.setTempMax(new BigDecimal(temperatureMax).floatValue());
  320. heFengDay.setTempMin(new BigDecimal(temperatureMin).floatValue());
  321. heFengDayList.add(heFengDay);
  322. }
  323. } else {
  324. log.info("{} 的彩云日数据不足7天,不入库!", name);
  325. }
  326. /*for (HeFengHour item : heFengHourList) {
  327. String insertSql = " INSERT INTO hefeng_hour_unit_" + areaCode + " USING hefeng_hour_unit TAGS('" + areaCode + "') values('" + item.getTs() + "', " + item.getTemp() + ", '" + item.getText() + "', '" + item.getWindDir() + "', " + item.getWind360() + ", " + item.getWindSpeed() + ", " + item.getWindScale() + ", " + item.getHumidity() + ", " + item.getCloud() + ", " + item.getPrecip() + ", " + item.getDew() + ", " + item.getPressure() + ", " + item.getDswrf() +", " + item.getWindSpeedM()+ ")";
  328. int affectedRows = ps.executeUpdate(insertSql);
  329. }*/
  330. for (HeFengDay item : heFengDayList) {
  331. String insertSQL = "INSERT INTO hefeng_day_unit_" + areaCode + " USING hefeng_day_unit TAGS('" + areaCode + "') values('" + item.getTs() + "', " + item.getTempMax() + ", " + item.getTempMin() + ", '" + item.getTextDay() + "', '" + item.getTextNight() + "', " + item.getWind360Day() + ", '" + item.getWindDirDay() + "', " + item.getWindScaleDay() + ", " + item.getWindSpeedDay() + ", " + item.getWind360Night() + ", '" + item.getWindDirNight() + "', " + item.getWindScaleNight() + ", " + item.getWindSpeedNight() + ", " + item.getHumidity() + ", " + item.getPrecip() + ", " + item.getPressure() + ", " + item.getDswrf() + ", " + item.getWindSpeedMDay() + ", " + item.getWindSpeedMNight() + ")";
  332. int affectedRows = ps.executeUpdate(insertSQL);
  333. }
  334. if (ps != null)
  335. ps.close();
  336. } catch (Exception e) {
  337. log.error("彩云天气,地区:{} 日天气数据下载失败JSON格式化错误", name);
  338. return true;
  339. }
  340. log.info("彩云天气,地区:{} 日天气数据下载完成", name);
  341. return false;
  342. }
  343. public boolean analysisXMO(String xmoUrl, String areaCode, String name, Connection conn) {
  344. log.info("开始下载地区:{} 的天气数据", name);
  345. try {
  346. Statement ps = conn.createStatement();
  347. String body = HttpUtil.createGet(xmoUrl).header("apikey", "c615a8f6-f5dd-4a81-86fe-db2a42862c15").execute().charset("utf-8").body();
  348. //String body = HttpUtil.createGet(xmoUrl).header("apikey", "51bcabf8-3a5e-41e9-8bf2-b7676936cb22").execute().charset("utf-8").body();
  349. JSONObject jsonObject = JSONUtil.parseObj(body);
  350. //log.info("获取到的数据为:{}", body);
  351. if (jsonObject.toString().contains("API call limit has been reached")) {
  352. return true;
  353. }
  354. //日数据 7d
  355. JSONObject daily = JSONUtil.parseObj(jsonObject.get("daily"));
  356. //日期
  357. JSONArray date = JSONUtil.parseArray(daily.get("time"));
  358. //日->辐照度
  359. JSONArray dswrfDay = JSONUtil.parseArray(daily.get("shortwave_radiation_sum"));
  360. //日->风速
  361. JSONArray windSpeedDay = JSONUtil.parseArray(daily.get("wind_speed_10m_max"));
  362. //雨量
  363. JSONArray precip = JSONUtil.parseArray(daily.get("rain_sum"));
  364. //2m温度
  365. JSONArray temp = JSONUtil.parseArray(daily.get("temperature_2m_max"));
  366. JSONArray tempMin = JSONUtil.parseArray(daily.get("temperature_2m_min"));
  367. JSONArray precipitationSum = JSONUtil.parseArray(daily.get("precipitation_sum"));
  368. //10米风向
  369. JSONArray direction = JSONUtil.parseArray(daily.get("wind_direction_10m_dominant"));
  370. //天气代码
  371. JSONArray code = JSONUtil.parseArray(daily.get("weather_code"));
  372. //日数据写入
  373. List<HeFengDay> heFengDayList = new ArrayList<>();
  374. if (date.size() == 16) {
  375. for (int i = 0; i < date.size(); i++) {
  376. String time = date.get(i).toString();
  377. HeFengDay heFengDay = new HeFengDay();
  378. heFengDay.setTs(convertStringToTimestamp(time));
  379. heFengDay.setWindSpeedDay(windSpeedDay.get(i).toString().equals("null") ? -0.99f : new BigDecimal(windSpeedDay.get(i).toString()).floatValue());
  380. heFengDay.setWindSpeedMDay(windSpeedDay.get(i).toString().equals("null") ? -0.99f : new BigDecimal(windSpeedDay.get(i).toString()).floatValue() * 1000 / 3600);
  381. heFengDay.setWindScaleDay(speedLevel(windSpeedDay.get(i).toString().equals("null") ? "0" : windSpeedDay.get(i).toString()));
  382. heFengDay.setWind360Day(direction.get(i).toString().equals("null") ? -0.99f : new BigDecimal(direction.get(i).toString()).floatValue());
  383. heFengDay.setPrecip(precip.get(i).toString().equals("null") ? -0.99f : new BigDecimal(precip.get(i).toString()).floatValue());
  384. heFengDay.setTextDay(ConversionWeatherCodeXmo(code.get(i).toString().equals("null") ? "0" : code.get(i).toString()));
  385. heFengDay.setTempMax(temp.get(i).toString().equals("null") ? -0.99f : new BigDecimal(temp.get(i).toString()).floatValue());
  386. heFengDay.setTempMin(tempMin.get(i).toString().equals("null") ? -0.99f : new BigDecimal(tempMin.get(i).toString()).floatValue());
  387. heFengDay.setHumidity(precipitationSum.get(i).toString().equals("null") ? -0.99f : new BigDecimal(precipitationSum.get(i).toString()).floatValue());
  388. heFengDay.setDswrf(dswrfDay.get(i).toString().equals("null") ? -0.99f : new BigDecimal(dswrfDay.get(i).toString()).floatValue());
  389. heFengDayList.add(heFengDay);
  390. }
  391. } else {
  392. log.info("{} 的曦谋日数据不足16天,不入库!", name);
  393. }
  394. for (HeFengDay item : heFengDayList) {
  395. String insertSQL = "INSERT INTO hefeng_day_unit_" + areaCode + " USING hefeng_day_unit TAGS('" + areaCode + "') " +
  396. "(ts,wind_speed_day,wind_speed_m_day,wind_scale_day,wind_360_Day,precip,text_day,temp_max,temp_min,humidity,dswrf) values('"
  397. + item.getTs() + "', " + item.getWindSpeedDay() + ", " + item.getWindSpeedMDay() + ", " + item.getWindScaleDay() + ", " + item.getWind360Day() + ", "
  398. + item.getPrecip() + ", '" + item.getTextDay() + "', " + item.getTempMax() + ", " + item.getTempMin() + ", " + item.getHumidity() + ", "
  399. + item.getDswrf() + ")";
  400. SimpleDateFormat simpleFormatter = new SimpleDateFormat("yyyy-MM-dd");
  401. String insertSnap = "INSERT INTO weather_day_snap_" + areaCode + "_" + simpleFormatter.format(new Date()) + " USING hefeng_day_unit TAGS('" + areaCode + "','" + simpleFormatter.format(new Date()) + "') " +
  402. "(ts,wind_speed_day,wind_speed_m_day,wind_scale_day,wind_360_Day,precip,text_day,temp_max,temp_min,humidity,dswrf) values('"
  403. + item.getTs() + "', " + item.getWindSpeedDay() + ", " + item.getWindSpeedMDay() + ", " + item.getWindScaleDay() + ", " + item.getWind360Day() + ", "
  404. + item.getPrecip() + ", '" + item.getTextDay() + "', " + item.getTempMax() + ", " + item.getTempMin() + ", " + item.getHumidity() + ", "
  405. + item.getDswrf() + ")";
  406. int affectedRows = ps.executeUpdate(insertSQL);
  407. }
  408. if (ps != null)
  409. ps.close();
  410. } catch (Exception e) {
  411. log.error("曦谋天气,地区:{} 日天气数据下载失败JSON格式化错误", name);
  412. return true;
  413. }
  414. log.info("曦谋天气,地区:{} 日天气数据下载完成", name);
  415. return false;
  416. }
  417. private Timestamp getTimestamp(String time) {
  418. // 解析字符串为 ZonedDateTime
  419. ZonedDateTime zonedDateTime = ZonedDateTime.parse(time);
  420. // 将 ZonedDateTime 转换为 Instant
  421. Instant instant = zonedDateTime.toInstant();
  422. // 将 Instant 转换为 Timestamp
  423. return Timestamp.from(instant);
  424. }
  425. /**
  426. * 根据代码获取对应天气描述
  427. *
  428. * @param skycon
  429. * @return
  430. */
  431. private String skycon(String skycon) {
  432. switch (skycon) {
  433. case "CLEAR_DAY":
  434. case "CLEAR_NIGHT":
  435. return "晴";
  436. case "PARTLY_CLOUDY_DAY":
  437. case "PARTLY_CLOUDY_NIGHT":
  438. return "多云";
  439. case "CLOUDY":
  440. return "阴";
  441. case "LIGHT_HAZE":
  442. return "轻度雾霾";
  443. case "MODERATE_HAZE":
  444. return "中度雾霾";
  445. case "HEAVY_HAZE":
  446. return "重度雾霾";
  447. case "LIGHT_RAIN":
  448. return "小雨";
  449. case "MODERATE_RAIN":
  450. return "中雨";
  451. case "HEAVY_RAIN":
  452. return "大雨";
  453. case "STORM_RAIN":
  454. return "暴雨";
  455. case "FOG":
  456. return "雾";
  457. case "LIGHT_SNOW":
  458. return "小雪";
  459. case "MODERATE_SNOW":
  460. return "中雪";
  461. case "HEAVY_SNOW":
  462. return "大雪";
  463. case "STORM_SNOW":
  464. return "暴雪";
  465. case "DUST":
  466. return "浮尘";
  467. case "SAND":
  468. return "沙尘";
  469. case "WIND":
  470. return "大风";
  471. }
  472. return "晴";
  473. }
  474. private String ConversionWeatherCodeXmo(String code) {
  475. switch (code) {
  476. case "0":
  477. return "晴";
  478. case "1":
  479. return "多云";
  480. case "2":
  481. return "少云";
  482. case "3":
  483. return "阴";
  484. case "45":
  485. return "雾";
  486. case "48":
  487. return "冻雾";
  488. case "51":
  489. case "53":
  490. case "55":
  491. return "毛毛雨";
  492. case "56":
  493. case "57":
  494. return "冻毛毛雨";
  495. case "61":
  496. return "小雨";
  497. case "63":
  498. return "中雨";
  499. case "65":
  500. return "大雨";
  501. case "66":
  502. case "67":
  503. return "冻雨";
  504. case "71":
  505. return "小雪";
  506. case "73":
  507. return "中雪";
  508. case "75":
  509. return "大雪";
  510. case "77":
  511. return "雪粒";
  512. case "80":
  513. return "小阵雨";
  514. case "81":
  515. return "阵雨";
  516. case "82":
  517. return "强阵雨";
  518. case "85":
  519. return "小阵雪";
  520. case "86":
  521. return "阵雪";
  522. case "95":
  523. return "雷雨";
  524. case "96":
  525. case "99":
  526. return "雷雨伴有冰雹";
  527. default:
  528. return "晴"; // 默认返回晴
  529. }
  530. }
  531. }