GetWeather.java 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  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.time.Instant;
  24. import java.time.LocalDate;
  25. import java.time.ZonedDateTime;
  26. import java.util.*;
  27. import java.util.stream.Collectors;
  28. @Service
  29. @Validated
  30. @Slf4j
  31. public class GetWeather {
  32. @Resource
  33. private WeixinPush weixinPush;
  34. /*public void download() {
  35. List<String> areaCodes = new ArrayList<>();
  36. List<DistrictCodeDO> districtCodeDOList = new ArrayList<>();
  37. try {
  38. List<Entity> dictList = Db.use().findAll("system_dict_data");
  39. for (Entity entity : dictList) {
  40. String name = entity.getStr("label");
  41. if (name.contains("area_code")) {
  42. String code = entity.getStr("value");
  43. String[] s = code.split(",");
  44. areaCodes = Arrays.asList(s);
  45. }
  46. }
  47. List<Entity> districtCodes = Db.use().findAll("jy_district_code");
  48. for (Entity e : districtCodes) {
  49. DistrictCodeDO districtCodeDO = new DistrictCodeDO();
  50. districtCodeDO.setCode(Integer.parseInt(e.getStr("code")));
  51. districtCodeDO.setName(e.getStr("name"));
  52. districtCodeDO.setLevel(Integer.parseInt(e.getStr("level")));
  53. districtCodeDO.setType(Integer.parseInt(e.getStr("type")));
  54. districtCodeDO.setAbname(e.getStr("abname"));
  55. districtCodeDO.setPid(Integer.parseInt(e.getStr("pid")));
  56. districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  57. districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  58. districtCodeDOList.add(districtCodeDO);
  59. }
  60. String jdbcUrl = "jdbc:TAOS://192.168.12.241:29500/etadm_local?user=root&password=taosdata";
  61. Properties connProps = new Properties();
  62. connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
  63. connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
  64. connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
  65. Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
  66. //省份
  67. for (String code : areaCodes) {
  68. List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
  69. //市
  70. for (DistrictCodeDO d : shiList) {
  71. List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
  72. log.info("开始下载地区:{} 的天气数据", d.getName());
  73. String hefeng24;
  74. String caiyun24;
  75. String hefengDay;
  76. String caiyunDay;
  77. //!!!!!!!!!!拼的彩云的辐照度!!!!!!!!!!!!!
  78. //和风逐小时数据
  79. hefeng24 = "https://devapi.qweather.com/v7/grid-weather/24h?location=" + d.getLng() + "," + d.getLat() + "&key=54d9633382814e148836ce6be2d003fb";
  80. //彩云逐小时数据
  81. caiyun24 = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/hourly?hourlysteps=24";
  82. //和风逐日数据
  83. hefengDay = "https://devapi.qweather.com/v7/grid-weather/7d?location=" + d.getLng() + "," + d.getLat() + "&key=54d9633382814e148836ce6be2d003fb";
  84. //彩云逐日数据
  85. caiyunDay = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/daily?dailysteps=7";
  86. analysis24(hefeng24, caiyun24, d.getCode(), d.getName(), conn);
  87. analysisDay(hefengDay, caiyunDay, d.getCode(), d.getName(), conn);
  88. //区
  89. for (DistrictCodeDO q : quList) {
  90. log.info("开始下载地区:{} 的天气数据", q.getName());
  91. //和风逐小时数据
  92. hefeng24 = "https://devapi.qweather.com/v7/grid-weather/24h?location=" + q.getLng() + "," + q.getLat() + "&key=54d9633382814e148836ce6be2d003fb";
  93. //彩云逐小时数据
  94. caiyun24 = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/hourly?hourlysteps=24";
  95. //和风逐日数据
  96. hefengDay = "https://devapi.qweather.com/v7/grid-weather/7d?location=" + q.getLng() + "," + q.getLat() + "&key=54d9633382814e148836ce6be2d003fb";
  97. //彩云逐日数据
  98. caiyunDay = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/daily?dailysteps=7";
  99. analysis24(hefeng24, caiyun24, q.getCode(), q.getName(), conn);
  100. analysisDay(hefengDay, caiyunDay, q.getCode(), q.getName(), conn);
  101. }
  102. }
  103. }
  104. conn.close();
  105. log.info("天气数据全部下载完毕");
  106. } catch (Exception e) {
  107. e.printStackTrace();
  108. }
  109. }*/
  110. /**
  111. * 根据风速获取对应风力等级
  112. * 2025-01-09 改为km/h单位
  113. *
  114. * @param speed 风速,单位为 km/h
  115. * @return 风力等级
  116. */
  117. public static int speedLevel(String speed) {
  118. BigDecimal val = new BigDecimal(speed);
  119. //<0.3 无风 0级
  120. if (val.compareTo(new BigDecimal("1")) < 0) {
  121. return 0;
  122. } else if (val.compareTo(new BigDecimal("6")) < 0) {
  123. //0.3-1.6 微风徐徐 1级
  124. return 1;
  125. } else if (val.compareTo(new BigDecimal("12")) < 0) {
  126. //1.6-3.4 清风 2级
  127. return 2;
  128. } else if (val.compareTo(new BigDecimal("20")) < 0) {
  129. //3.4-5.5 树叶摇摆 3级
  130. return 3;
  131. } else if (val.compareTo(new BigDecimal("29")) < 0) {
  132. //5.5-8.0 树枝摇动 4级
  133. return 4;
  134. } else if (val.compareTo(new BigDecimal("39")) < 0) {
  135. //8.0-10.8 风吹折小树 5级
  136. return 5;
  137. } else if (val.compareTo(new BigDecimal("50")) < 0) {
  138. //10.8-13.9 树枝折断 6级
  139. return 6;
  140. } else if (val.compareTo(new BigDecimal("62")) < 0) {
  141. //13.9-17.2 风吹倒树木 7级
  142. return 7;
  143. } else if (val.compareTo(new BigDecimal("75")) < 0) {
  144. //17.2-20.8 风吹断大树 8级
  145. return 8;
  146. } else if (val.compareTo(new BigDecimal("89")) < 0) {
  147. //20.8-24.5 强风 9级
  148. return 9;
  149. } else if (val.compareTo(new BigDecimal("103")) < 0) {
  150. //24.5-28.5 狂风 10级
  151. return 10;
  152. } else if (val.compareTo(new BigDecimal("117")) < 0) {
  153. //28.5-32.7 暴风 11级
  154. return 11;
  155. } else if (val.compareTo(new BigDecimal("134")) < 0) {
  156. //32.7-37.0 大暴风 12级
  157. return 12;
  158. } else if (val.compareTo(new BigDecimal("150")) < 0) {
  159. //37.0-41.5 飓风 13级
  160. return 13;
  161. } else if (val.compareTo(new BigDecimal("167")) < 0) {
  162. //41.5-46.2 强飓风 14级
  163. return 14;
  164. } else if (val.compareTo(new BigDecimal("184")) < 0) {
  165. //46.2-50.9 猛烈飓风 15级
  166. return 15;
  167. } else if (val.compareTo(new BigDecimal("202")) < 0) {
  168. //50.9-56.1 毁灭性飓风 16级
  169. return 16;
  170. } else {
  171. //56.1-61.3 超级飓风 17级
  172. return 17;
  173. }
  174. }
  175. public static Timestamp convertStringToTimestamp(String dateStr) {
  176. LocalDate localDate = LocalDate.parse(dateStr); // 解析 yyyy-MM-dd
  177. return Timestamp.valueOf(localDate.atStartOfDay()); // 转换为当天的开始时间
  178. }
  179. /*public void analysis24(String hefeng24url, String caiyun24url, int areaCode, String name, Connection conn) {
  180. try {
  181. Statement ps = conn.createStatement();
  182. String caiyunBody = HttpUtil.createGet(caiyun24url).execute().charset("utf-8").body();
  183. JSONObject caiyunjsonObject = JSONUtil.parseObj(caiyunBody);
  184. JSONObject caiyunResult = JSONUtil.parseObj(caiyunjsonObject.get("result"));
  185. JSONObject hourly = JSONUtil.parseObj(caiyunResult.get("hourly"));
  186. JSONArray dswrf = JSONUtil.parseArray(hourly.get("dswrf"));
  187. String hefengBody = HttpUtil.createGet(hefeng24url).execute().charset("utf-8").body();
  188. JSONObject jsonObject = JSONUtil.parseObj(hefengBody);
  189. JSONArray hefengList = JSONUtil.parseArray(jsonObject.get("hourly"));
  190. List<HeFengHour> list = new ArrayList<>();
  191. hefengList.forEach(item -> {
  192. JSONObject jsonObject1 = JSONUtil.parseObj(item);
  193. try {
  194. HeFengHour weather = new HeFengHour();
  195. String s = jsonObject1.getStr("fxTime");
  196. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mmXXX");
  197. ZonedDateTime zonedDateTime = ZonedDateTime.parse(s, formatter);
  198. Instant instant = zonedDateTime.toInstant();
  199. Timestamp timestamp = Timestamp.from(instant);
  200. weather.setTs(timestamp);
  201. weather.setTemp(new BigDecimal(jsonObject1.getStr("temp")).floatValue());
  202. weather.setAreaCode(String.valueOf(areaCode));
  203. weather.setText(jsonObject1.getStr("text"));
  204. weather.setWindDir(jsonObject1.getStr("windDir"));
  205. weather.setWind360(new BigDecimal(jsonObject1.getStr("wind360")).floatValue());
  206. weather.setWindSpeed(new BigDecimal(jsonObject1.getStr("windSpeed")).divide(new BigDecimal("3.6"), 2, RoundingMode.HALF_UP).floatValue());
  207. weather.setWindScale(new BigDecimal(jsonObject1.getStr("windScale")).floatValue());
  208. weather.setHumidity(new BigDecimal(jsonObject1.getStr("humidity")).floatValue());
  209. weather.setCloud(new BigDecimal(jsonObject1.getStr("cloud")).floatValue());
  210. weather.setPrecip(new BigDecimal(jsonObject1.getStr("precip")).floatValue());
  211. weather.setDew(new BigDecimal(jsonObject1.getStr("dew")).floatValue());
  212. weather.setPressure(new BigDecimal(jsonObject1.getStr("pressure")).floatValue());
  213. list.add(weather);
  214. } catch (Exception e) {
  215. throw new RuntimeException(e);
  216. }
  217. });
  218. if (!dswrf.isEmpty()) {
  219. if (list.size() != 24) {
  220. log.error("地区:{} 24小时天气数据下载失败,和风天气数据不全", name);
  221. } else {
  222. if (dswrf.size() != 24) {
  223. log.error("地区:{} 24小时天气数据下载失败,心知天气数据不全", name);
  224. } else {
  225. for (int i = 0; i < 24; i++) {
  226. Map ds = (Map) dswrf.get(i);
  227. list.get(i).setDswrf(new BigDecimal(ds.get("value").toString()).floatValue());
  228. }
  229. }
  230. }
  231. }
  232. for (HeFengHour item : list) {
  233. 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() + ")";
  234. int affectedRows = ps.executeUpdate(insertSql);
  235. }
  236. if (ps != null)
  237. ps.close();
  238. } catch (Exception e) {
  239. log.error("地区:{} 24小时天气数据下载失败JSON格式化错误", name);
  240. }
  241. log.info("地区:{} 24小时天气数据下载完成", name);
  242. }
  243. public void analysisDay(String hefeng24url, String caiyun24url, int areaCode, String name, Connection conn) {
  244. try {
  245. Statement ps = conn.createStatement();
  246. String caiyunBody = HttpUtil.createGet(caiyun24url).execute().charset("utf-8").body();
  247. JSONObject caiyunjsonObject = JSONUtil.parseObj(caiyunBody);
  248. JSONObject caiyunResult = JSONUtil.parseObj(caiyunjsonObject.get("result"));
  249. JSONObject daily = JSONUtil.parseObj(caiyunResult.get("daily"));
  250. JSONArray dswrf = JSONUtil.parseArray(daily.get("dswrf"));
  251. String hefengBody = HttpUtil.createGet(hefeng24url).execute().charset("utf-8").body();
  252. JSONObject jsonObject = JSONUtil.parseObj(hefengBody);
  253. JSONArray hefengList = JSONUtil.parseArray(jsonObject.get("daily"));
  254. List<HeFengDay> list = new ArrayList<>();
  255. hefengList.forEach(item -> {
  256. JSONObject jsonObject1 = JSONUtil.parseObj(item);
  257. try {
  258. HeFengDay weather = new HeFengDay();
  259. String s = jsonObject1.getStr("fxDate");
  260. LocalDate localDate = LocalDate.parse(s);
  261. // 将 LocalDate 转换为 Instant,然后再转换为 Timestamp
  262. Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay(ZoneOffset.UTC).toLocalDateTime());
  263. weather.setTs(timestamp);
  264. weather.setAreaCode(String.valueOf(areaCode));
  265. weather.setTempMax(new BigDecimal(jsonObject1.getStr("tempMax")).floatValue());
  266. weather.setTempMin(new BigDecimal(jsonObject1.getStr("tempMin")).floatValue());
  267. weather.setTextDay(jsonObject1.getStr("textDay"));
  268. weather.setTextNight(jsonObject1.getStr("textNight"));
  269. weather.setWind360Day(new BigDecimal(jsonObject1.getStr("wind360Day")).floatValue());
  270. weather.setWind360Night(new BigDecimal(jsonObject1.getStr("wind360Night")).floatValue());
  271. weather.setWindDirDay(jsonObject1.getStr("windDirDay"));
  272. weather.setWindDirNight(jsonObject1.getStr("windDirNight"));
  273. weather.setWindScaleDay(new BigDecimal(jsonObject1.getStr("windScaleDay")).floatValue());
  274. weather.setWindScaleNight(new BigDecimal(jsonObject1.getStr("windScaleNight")).floatValue());
  275. weather.setWindSpeedDay(new BigDecimal(jsonObject1.getStr("windSpeedDay")).divide(new BigDecimal("3.6"), 2, RoundingMode.HALF_UP).floatValue());
  276. weather.setWindSpeedNight(new BigDecimal(jsonObject1.getStr("windSpeedNight")).divide(new BigDecimal("3.6"), 2, RoundingMode.HALF_UP).floatValue());
  277. weather.setHumidity(new BigDecimal(jsonObject1.getStr("humidity")).floatValue());
  278. weather.setPrecip(new BigDecimal(jsonObject1.getStr("precip")).floatValue());
  279. weather.setPressure(new BigDecimal(jsonObject1.getStr("pressure")).floatValue());
  280. list.add(weather);
  281. } catch (Exception e) {
  282. throw new RuntimeException(e);
  283. }
  284. });
  285. if (!dswrf.isEmpty()) {
  286. if (list.size() != 7) {
  287. log.error("地区:{} 日天气数据下载失败,和风天气数据不全", name);
  288. } else {
  289. for (HeFengDay heFengDay : list) {
  290. Map ds = (Map) dswrf.get(0);
  291. heFengDay.setDswrf(new BigDecimal(ds.get("max").toString()).floatValue());
  292. }
  293. }
  294. }
  295. for (HeFengDay item : list) {
  296. String insertSQL = "INSERT INTO hefeng_day_unit_" + item.getAreaCode() + " USING hefeng_day_unit TAGS('" + item.getAreaCode() + "') 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() + ")";
  297. int affectedRows = ps.executeUpdate(insertSQL);
  298. }
  299. if (ps != null)
  300. ps.close();
  301. } catch (Exception e) {
  302. log.error("地区:{} 日天气数据下载失败JSON格式化错误", name);
  303. }
  304. log.info("地区:{} 日天气数据下载完成", name);
  305. }*/
  306. public void download() {
  307. List<String> areaCodes = new ArrayList<>();
  308. List<DistrictCodeDO> districtCodeDOList = new ArrayList<>();
  309. boolean isApiQuotaExhausted = false; // 引入标志变量
  310. String startDate = DateUtil.today();
  311. String endDate = DateUtil.offsetDay(DateUtil.date(), 15).toString("yyyy-MM-dd");
  312. try {
  313. List<Entity> dictList = Db.use().findAll("system_dict_data");
  314. for (Entity entity : dictList) {
  315. String name = entity.getStr("label");
  316. if (name.contains("area_code")) {
  317. String code = entity.getStr("value");
  318. String[] s = code.split(",");
  319. areaCodes = Arrays.asList(s);
  320. }
  321. }
  322. List<Entity> districtCodes = Db.use().findAll("jy_district_code");
  323. for (Entity e : districtCodes) {
  324. DistrictCodeDO districtCodeDO = new DistrictCodeDO();
  325. districtCodeDO.setCode(Integer.parseInt(e.getStr("code")));
  326. districtCodeDO.setName(e.getStr("name"));
  327. districtCodeDO.setLevel(Integer.parseInt(e.getStr("level")));
  328. districtCodeDO.setType(Integer.parseInt(e.getStr("type")));
  329. districtCodeDO.setAbname(e.getStr("abname"));
  330. districtCodeDO.setPid(Integer.parseInt(e.getStr("pid")));
  331. districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  332. districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
  333. districtCodeDOList.add(districtCodeDO);
  334. }
  335. String jdbcUrl = "jdbc:TAOS://192.168.12.241:29500/etadm_local?user=root&password=taosdata";
  336. Properties connProps = new Properties();
  337. connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
  338. connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
  339. connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
  340. Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
  341. //省份
  342. for (String code : areaCodes) {
  343. //只有甘肃用xmo天气日接口
  344. if (code.equals("620000")) {
  345. if (isApiQuotaExhausted) break; // 检查标志变量
  346. List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
  347. //市
  348. for (DistrictCodeDO d : shiList) {
  349. if (isApiQuotaExhausted) break; // 检查标志变量
  350. List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
  351. String xmoUrl;
  352. //彩云综合数据查询
  353. 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&timezone=Asia%2FShanghai&start_date=" + startDate + "&end_date=" + endDate;
  354. isApiQuotaExhausted = analysisXMO(xmoUrl, d.getCode(), d.getName(), conn); // 传递标志变量
  355. if (isApiQuotaExhausted) break; // 检查标志变量
  356. //区
  357. for (DistrictCodeDO q : quList) {
  358. if (isApiQuotaExhausted) break; // 检查标志变量
  359. 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&timezone=Asia%2FShanghai&start_date=" + startDate + "&end_date=" + endDate;
  360. isApiQuotaExhausted = analysisXMO(xmoUrl, q.getCode(), q.getName(), conn); // 传递标志变量
  361. if (isApiQuotaExhausted) break; // 检查标志变量
  362. //线程睡5秒 防止请求过快
  363. //花钱了 硬气 不管他
  364. //Thread.sleep(5000);
  365. }
  366. }
  367. } else {
  368. if (isApiQuotaExhausted) break; // 检查标志变量
  369. List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
  370. //市
  371. for (DistrictCodeDO d : shiList) {
  372. if (isApiQuotaExhausted) break; // 检查标志变量
  373. List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
  374. String caiyun;
  375. //彩云综合数据查询
  376. caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
  377. isApiQuotaExhausted = analysis(caiyun, d.getCode(), d.getName(), conn); // 传递标志变量
  378. if (isApiQuotaExhausted) break; // 检查标志变量
  379. //区
  380. for (DistrictCodeDO q : quList) {
  381. if (isApiQuotaExhausted) break; // 检查标志变量
  382. caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
  383. isApiQuotaExhausted = analysis(caiyun, q.getCode(), q.getName(), conn); // 传递标志变量
  384. if (isApiQuotaExhausted) break; // 检查标志变量
  385. //线程睡5秒 防止请求过快
  386. //花钱了 硬气 不管他
  387. //Thread.sleep(5000);
  388. }
  389. }
  390. }
  391. }
  392. conn.close();
  393. String alarm = "电力交易系统在获取日级天气数据时报错, 彩云天气API 额度已用尽";
  394. String description = "接口调用异常";
  395. if (isApiQuotaExhausted) {
  396. //给企业微信发送消息
  397. /* WeixinPush weixinPush = new WeixinPush();
  398. WeixinMessage weixinMessage = new WeixinMessage();
  399. weixinMessage.setToUser("WangHongChen|XiuWei|DouZhi");
  400. //获取今天的ymd
  401. String ymd = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
  402. weixinMessage.setContent(ymd + "日 电力交易系统在获取天气数据时报错, 彩云天气API 额度已用尽");
  403. weixinMessage.setMsgType("text");
  404. weixinMessage.setAgentid(1000009); // 确保 agentid 正确
  405. weixinPush.sendMessage(weixinMessage);
  406. */
  407. weixinPush.sendMessageBot(alarm, description);
  408. } else {
  409. alarm = "电力交易系统彩云天气数据全部下载完毕";
  410. description = "接口调用成功";
  411. weixinPush.sendMessageBot(alarm, description);
  412. log.info("彩云天气数据全部下载完毕");
  413. }
  414. } catch (Exception e) {
  415. e.printStackTrace();
  416. }
  417. }
  418. public boolean analysis(String caiyun, int areaCode, String name, Connection conn) {
  419. log.info("开始下载地区:{} 的天气数据", name);
  420. try {
  421. Statement ps = conn.createStatement();
  422. String caiyunBody = HttpUtil.createGet(caiyun).execute().charset("utf-8").body();
  423. JSONObject caiyunjsonObject = JSONUtil.parseObj(caiyunBody);
  424. if (caiyunjsonObject.toString().contains("API quota is exhausted")) {
  425. return true;
  426. }
  427. JSONObject caiyunResult = JSONUtil.parseObj(caiyunjsonObject.get("result"));
  428. //小时数据 72小时
  429. /*JSONObject hourly = JSONUtil.parseObj(caiyunResult.get("hourly"));
  430. //小时->温度
  431. JSONArray temperature = JSONUtil.parseArray(hourly.get("temperature"));
  432. //小时->辐照度
  433. JSONArray dswrf = JSONUtil.parseArray(hourly.get("dswrf"));
  434. //小时->风速
  435. JSONArray windSpeed = JSONUtil.parseArray(hourly.get("wind"));
  436. //小时->天气标识
  437. JSONArray skyconHour = JSONUtil.parseArray(hourly.get("skycon"));
  438. //小时->湿度
  439. JSONArray humidityHour = JSONUtil.parseArray(hourly.get("humidity"));
  440. //小时->压强
  441. JSONArray pressureHour = JSONUtil.parseArray(hourly.get("pressure"));*/
  442. //日数据 7d
  443. JSONObject daily = JSONUtil.parseObj(caiyunResult.get("daily"));
  444. //日->辐照度
  445. JSONArray dswrfDay = JSONUtil.parseArray(daily.get("dswrf"));
  446. //日->温度
  447. JSONArray temperatureDay = JSONUtil.parseArray(daily.get("temperature"));
  448. //日->风速 8点到20点
  449. JSONArray windSpeed8Day = JSONUtil.parseArray(daily.get("wind_08h_20h"));
  450. //日->风速 20点到32点
  451. JSONArray windSpeed20Day = JSONUtil.parseArray(daily.get("wind_20h_32h"));
  452. //日->天气描述 8点到20点
  453. JSONArray skycon8 = JSONUtil.parseArray(daily.get("skycon_08h_20h"));
  454. //日->天气描述 20点到32点
  455. JSONArray skycon20 = JSONUtil.parseArray(daily.get("skycon_20h_32h"));
  456. //小时数据写入。 时间 风速 辐照度
  457. /*List<HeFengHour> heFengHourList = new ArrayList<>();
  458. if (windSpeed.size() == 72 && dswrf.size() == 72 && temperature.size() == 72) {
  459. for (int i = 0; i < windSpeed.size(); i++) {
  460. String time = ((JSONObject) windSpeed.get(i)).get("datetime").toString();
  461. HeFengHour heFengHour = new HeFengHour();
  462. heFengHour.setTs(getTimestamp(time));
  463. heFengHour.setWindSpeed(new BigDecimal(((JSONObject) windSpeed.get(i)).get("speed").toString()).floatValue());
  464. heFengHour.setWindSpeedM(new BigDecimal(((JSONObject) windSpeed.get(i)).get("speed").toString()).floatValue() * 1000 / 3600);
  465. heFengHour.setWindScale(speedLevel(((JSONObject) windSpeed.get(i)).get("speed").toString()));
  466. heFengHour.setWind360(new BigDecimal(((JSONObject) windSpeed.get(i)).get("direction").toString()).floatValue());
  467. heFengHour.setHumidity(new BigDecimal(((JSONObject) humidityHour.get(i)).get("value").toString()).floatValue());
  468. heFengHour.setPressure(new BigDecimal(((JSONObject) pressureHour.get(i)).get("value").toString()).floatValue());
  469. heFengHour.setText(skycon(((JSONObject) skyconHour.get(i)).get("value").toString()));
  470. heFengHour.setDswrf(new BigDecimal(((JSONObject) dswrf.get(i)).get("value").toString()).floatValue());
  471. heFengHour.setTemp(new BigDecimal(((JSONObject) temperature.get(i)).get("value").toString()).floatValue());
  472. heFengHourList.add(heFengHour);
  473. }
  474. } else {
  475. log.info("{} 的彩云小时数据不足72小时,不入库!", name);
  476. }*/
  477. //日数据写入
  478. List<HeFengDay> heFengDayList = new ArrayList<>();
  479. if (windSpeed8Day.size() == 7 && windSpeed20Day.size() == 7 && skycon8.size() == 7 && skycon20.size() == 7 && dswrfDay.size() == 7 & temperatureDay.size() == 7) {
  480. for (int i = 0; i < windSpeed8Day.size(); i++) {
  481. String time = ((JSONObject) windSpeed8Day.get(i)).get("date").toString();
  482. //白天风速
  483. Map windspeedDay = (Map) ((JSONObject) windSpeed8Day.get(i)).get("avg");
  484. String windspeedDay1 = windspeedDay.get("speed").toString();
  485. //白天风向
  486. String wind360Day1 = windspeedDay.get("direction").toString();
  487. //夜间风速
  488. Map windspeedNight = (Map) ((JSONObject) windSpeed20Day.get(i)).get("avg");
  489. String windspeedNight1 = windspeedNight.get("speed").toString();
  490. String wind360Night1 = windspeedNight.get("direction").toString();
  491. //辐照度
  492. String dswrf1 = ((JSONObject) dswrfDay.get(i)).get("avg").toString();
  493. //白天天气
  494. String skycon = ((JSONObject) skycon8.get(i)).get("value").toString();
  495. //夜间天气
  496. String skyconN = ((JSONObject) skycon20.get(i)).get("value").toString();
  497. //最高温度
  498. String temperatureMax = ((JSONObject) temperatureDay.get(i)).get("max").toString();
  499. //最低温度
  500. String temperatureMin = ((JSONObject) temperatureDay.get(i)).get("min").toString();
  501. HeFengDay heFengDay = new HeFengDay();
  502. heFengDay.setTs(getTimestamp(time));
  503. heFengDay.setWindSpeedDay(new BigDecimal(windspeedDay1).floatValue());
  504. heFengDay.setWindSpeedMDay(new BigDecimal(windspeedDay1).floatValue() * 1000 / 3600);
  505. heFengDay.setWind360Day(new BigDecimal(wind360Day1).floatValue());
  506. heFengDay.setWindScaleDay(speedLevel(windspeedDay1));
  507. heFengDay.setWindSpeedNight(new BigDecimal(windspeedNight1).floatValue());
  508. heFengDay.setWindSpeedMNight(new BigDecimal(windspeedNight1).floatValue() * 1000 / 3600);
  509. heFengDay.setWind360Night(new BigDecimal(wind360Night1).floatValue());
  510. heFengDay.setWindScaleNight(speedLevel(windspeedNight1));
  511. heFengDay.setDswrf(new BigDecimal(dswrf1).floatValue());
  512. heFengDay.setTextDay(skycon(skycon));
  513. heFengDay.setTextNight(skycon(skyconN));
  514. heFengDay.setTempMax(new BigDecimal(temperatureMax).floatValue());
  515. heFengDay.setTempMin(new BigDecimal(temperatureMin).floatValue());
  516. heFengDayList.add(heFengDay);
  517. }
  518. } else {
  519. log.info("{} 的彩云日数据不足7天,不入库!", name);
  520. }
  521. /*for (HeFengHour item : heFengHourList) {
  522. 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()+ ")";
  523. int affectedRows = ps.executeUpdate(insertSql);
  524. }*/
  525. for (HeFengDay item : heFengDayList) {
  526. 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() + ")";
  527. int affectedRows = ps.executeUpdate(insertSQL);
  528. }
  529. if (ps != null)
  530. ps.close();
  531. } catch (Exception e) {
  532. log.error("彩云天气,地区:{} 日天气数据下载失败JSON格式化错误", name);
  533. return true;
  534. }
  535. log.info("彩云天气,地区:{} 日天气数据下载完成", name);
  536. return false;
  537. }
  538. public boolean analysisXMO(String xmoUrl, int areaCode, String name, Connection conn) {
  539. log.info("开始下载地区:{} 的天气数据", name);
  540. try {
  541. Statement ps = conn.createStatement();
  542. String body = HttpUtil.createGet(xmoUrl).header("apikey", "c615a8f6-f5dd-4a81-86fe-db2a42862c15").execute().charset("utf-8").body();
  543. //String body = HttpUtil.createGet(xmoUrl).header("apikey", "51bcabf8-3a5e-41e9-8bf2-b7676936cb22").execute().charset("utf-8").body();
  544. JSONObject jsonObject = JSONUtil.parseObj(body);
  545. //log.info("获取到的数据为:{}", body);
  546. if (jsonObject.toString().contains("API call limit has been reached")) {
  547. return true;
  548. }
  549. //日数据 7d
  550. JSONObject daily = JSONUtil.parseObj(jsonObject.get("daily"));
  551. //日期
  552. JSONArray date = JSONUtil.parseArray(daily.get("time"));
  553. //日->辐照度
  554. JSONArray dswrfDay = JSONUtil.parseArray(daily.get("shortwave_radiation_sum"));
  555. //日->风速
  556. JSONArray windSpeedDay = JSONUtil.parseArray(daily.get("wind_speed_10m_max"));
  557. //雨量
  558. JSONArray precip = JSONUtil.parseArray(daily.get("rain_sum"));
  559. //2m温度
  560. JSONArray temp = JSONUtil.parseArray(daily.get("temperature_2m_max"));
  561. //10米风向
  562. JSONArray direction = JSONUtil.parseArray(daily.get("wind_direction_10m_dominant"));
  563. //天气代码
  564. JSONArray code = JSONUtil.parseArray(daily.get("weather_code"));
  565. //日数据写入
  566. List<HeFengDay> heFengDayList = new ArrayList<>();
  567. if (date.size() == 16) {
  568. for (int i = 0; i < date.size(); i++) {
  569. String time = date.get(i).toString();
  570. HeFengDay heFengDay = new HeFengDay();
  571. heFengDay.setTs(convertStringToTimestamp(time));
  572. heFengDay.setWindSpeedDay(windSpeedDay.get(i) == null ? -0.99f : new BigDecimal(windSpeedDay.get(i).toString()).floatValue());
  573. heFengDay.setWind360Day(direction.get(i).toString() == null ? -0.99f : new BigDecimal(direction.get(i).toString()).floatValue());
  574. heFengDay.setPrecip(precip.get(i) == null ? -0.99f : new BigDecimal(precip.get(i).toString()).floatValue());
  575. heFengDay.setTextDay(ConversionWeatherCodeXmo(code.get(i).toString() == null ? "0" : code.get(i).toString()));
  576. heFengDay.setTempMax(temp.get(i) == null ? -0.99f : new BigDecimal(temp.get(i).toString()).floatValue());
  577. heFengDay.setDswrf(dswrfDay.get(i) == null ? -0.99f : new BigDecimal(dswrfDay.get(i).toString()).floatValue());
  578. heFengDayList.add(heFengDay);
  579. }
  580. } else {
  581. log.info("{} 的曦谋日数据不足16天,不入库!", name);
  582. }
  583. for (HeFengDay item : heFengDayList) {
  584. String insertSQL = "INSERT INTO hefeng_day_unit_" + areaCode + " USING hefeng_day_unit TAGS('" + areaCode + "') " +
  585. "(ts,wind_speed_day,wind_360_Day,precip,text_day,temp_max,dswrf) values('"
  586. + item.getTs() + "', " + item.getWindSpeedDay() + ", " + item.getWind360Day() + ", " + item.getPrecip() + ", '"
  587. + item.getTextDay() + "', " + item.getTempMax() + ", " + item.getDswrf() + ")";
  588. int affectedRows = ps.executeUpdate(insertSQL);
  589. }
  590. if (ps != null)
  591. ps.close();
  592. } catch (Exception e) {
  593. log.error("曦谋天气,地区:{} 日天气数据下载失败JSON格式化错误", name);
  594. return true;
  595. }
  596. log.info("曦谋天气,地区:{} 日天气数据下载完成", name);
  597. return false;
  598. }
  599. private Timestamp getTimestamp(String time) {
  600. // 解析字符串为 ZonedDateTime
  601. ZonedDateTime zonedDateTime = ZonedDateTime.parse(time);
  602. // 将 ZonedDateTime 转换为 Instant
  603. Instant instant = zonedDateTime.toInstant();
  604. // 将 Instant 转换为 Timestamp
  605. return Timestamp.from(instant);
  606. }
  607. /**
  608. * 根据代码获取对应天气描述
  609. *
  610. * @param skycon
  611. * @return
  612. */
  613. private String skycon(String skycon) {
  614. switch (skycon) {
  615. case "CLEAR_DAY":
  616. case "CLEAR_NIGHT":
  617. return "晴";
  618. case "PARTLY_CLOUDY_DAY":
  619. case "PARTLY_CLOUDY_NIGHT":
  620. return "多云";
  621. case "CLOUDY":
  622. return "阴";
  623. case "LIGHT_HAZE":
  624. return "轻度雾霾";
  625. case "MODERATE_HAZE":
  626. return "中度雾霾";
  627. case "HEAVY_HAZE":
  628. return "重度雾霾";
  629. case "LIGHT_RAIN":
  630. return "小雨";
  631. case "MODERATE_RAIN":
  632. return "中雨";
  633. case "HEAVY_RAIN":
  634. return "大雨";
  635. case "STORM_RAIN":
  636. return "暴雨";
  637. case "FOG":
  638. return "雾";
  639. case "LIGHT_SNOW":
  640. return "小雪";
  641. case "MODERATE_SNOW":
  642. return "中雪";
  643. case "HEAVY_SNOW":
  644. return "大雪";
  645. case "STORM_SNOW":
  646. return "暴雪";
  647. case "DUST":
  648. return "浮尘";
  649. case "SAND":
  650. return "沙尘";
  651. case "WIND":
  652. return "大风";
  653. }
  654. return "晴";
  655. }
  656. private String ConversionWeatherCodeXmo(String code) {
  657. switch (code) {
  658. case "0":
  659. return "晴";
  660. case "1":
  661. return "多云";
  662. case "2":
  663. return "少云";
  664. case "3":
  665. return "阴";
  666. case "45":
  667. return "雾";
  668. case "48":
  669. return "冻雾";
  670. case "51":
  671. case "53":
  672. case "55":
  673. return "毛毛雨";
  674. case "56":
  675. case "57":
  676. return "冻毛毛雨";
  677. case "61":
  678. return "小雨";
  679. case "63":
  680. return "中雨";
  681. case "65":
  682. return "大雨";
  683. case "66":
  684. case "67":
  685. return "冻雨";
  686. case "71":
  687. return "小雪";
  688. case "73":
  689. return "中雪";
  690. case "75":
  691. return "大雪";
  692. case "77":
  693. return "雪粒";
  694. case "80":
  695. return "小阵雨";
  696. case "81":
  697. return "阵雨";
  698. case "82":
  699. return "强阵雨";
  700. case "85":
  701. return "小阵雪";
  702. case "86":
  703. return "阵雪";
  704. case "95":
  705. return "雷雨";
  706. case "96":
  707. case "99":
  708. return "雷雨伴有冰雹";
  709. default:
  710. return "晴"; // 默认返回晴
  711. }
  712. }
  713. }