|
@@ -1,5 +1,6 @@
|
|
|
package com.example.getweather.service;
|
|
|
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.db.Db;
|
|
|
import cn.hutool.db.Entity;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
@@ -22,6 +23,7 @@ import java.sql.DriverManager;
|
|
|
import java.sql.Statement;
|
|
|
import java.sql.Timestamp;
|
|
|
import java.time.Instant;
|
|
|
+import java.time.LocalDate;
|
|
|
import java.time.ZonedDateTime;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
@@ -178,91 +180,9 @@ public class GetWeather {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public void download() {
|
|
|
- List<String> areaCodes = new ArrayList<>();
|
|
|
- List<DistrictCodeDO> districtCodeDOList = new ArrayList<>();
|
|
|
- boolean isApiQuotaExhausted = false; // 引入标志变量
|
|
|
-
|
|
|
- try {
|
|
|
- List<Entity> dictList = Db.use().findAll("system_dict_data");
|
|
|
- for (Entity entity : dictList) {
|
|
|
- String name = entity.getStr("label");
|
|
|
- if (name.contains("area_code")) {
|
|
|
- String code = entity.getStr("value");
|
|
|
- String[] s = code.split(",");
|
|
|
- areaCodes = Arrays.asList(s);
|
|
|
- }
|
|
|
- }
|
|
|
- List<Entity> districtCodes = Db.use().findAll("jy_district_code");
|
|
|
- for (Entity e : districtCodes) {
|
|
|
- DistrictCodeDO districtCodeDO = new DistrictCodeDO();
|
|
|
- districtCodeDO.setCode(Integer.parseInt(e.getStr("code")));
|
|
|
- districtCodeDO.setName(e.getStr("name"));
|
|
|
- districtCodeDO.setLevel(Integer.parseInt(e.getStr("level")));
|
|
|
- districtCodeDO.setType(Integer.parseInt(e.getStr("type")));
|
|
|
- districtCodeDO.setAbname(e.getStr("abname"));
|
|
|
- districtCodeDO.setPid(Integer.parseInt(e.getStr("pid")));
|
|
|
- districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
|
|
|
- districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
|
|
|
- districtCodeDOList.add(districtCodeDO);
|
|
|
- }
|
|
|
- String jdbcUrl = "jdbc:TAOS://192.168.12.241:29500/etadm_local?user=root&password=taosdata";
|
|
|
- Properties connProps = new Properties();
|
|
|
- connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
|
|
- connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
|
|
- connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
|
|
- Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
|
|
|
- //省份
|
|
|
- for (String code : areaCodes) {
|
|
|
- if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
- List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
|
|
|
- //市
|
|
|
- for (DistrictCodeDO d : shiList) {
|
|
|
- if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
- List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
|
|
|
- String caiyun;
|
|
|
- //彩云综合数据查询
|
|
|
- caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
|
|
|
- isApiQuotaExhausted = analysis(caiyun, d.getCode(), d.getName(), conn); // 传递标志变量
|
|
|
- if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
- //区
|
|
|
- for (DistrictCodeDO q : quList) {
|
|
|
- if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
- caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
|
|
|
- isApiQuotaExhausted = analysis(caiyun, q.getCode(), q.getName(), conn); // 传递标志变量
|
|
|
- if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
- //线程睡5秒 防止请求过快
|
|
|
- //花钱了 硬气 不管他
|
|
|
- //Thread.sleep(5000);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- conn.close();
|
|
|
- String alarm = "电力交易系统在获取日级天气数据时报错, 彩云天气API 额度已用尽";
|
|
|
- String description = "接口调用异常";
|
|
|
- if (isApiQuotaExhausted) {
|
|
|
- //给企业微信发送消息
|
|
|
- /* WeixinPush weixinPush = new WeixinPush();
|
|
|
- WeixinMessage weixinMessage = new WeixinMessage();
|
|
|
- weixinMessage.setToUser("WangHongChen|XiuWei|DouZhi");
|
|
|
- //获取今天的ymd
|
|
|
- String ymd = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
|
|
|
- weixinMessage.setContent(ymd + "日 电力交易系统在获取天气数据时报错, 彩云天气API 额度已用尽");
|
|
|
- weixinMessage.setMsgType("text");
|
|
|
- weixinMessage.setAgentid(1000009); // 确保 agentid 正确
|
|
|
- weixinPush.sendMessage(weixinMessage);
|
|
|
- */
|
|
|
- weixinPush.sendMessageBot(alarm, description);
|
|
|
- } else {
|
|
|
- alarm = "电力交易系统彩云天气数据全部下载完毕";
|
|
|
- description = "接口调用成功";
|
|
|
- weixinPush.sendMessageBot(alarm, description);
|
|
|
- log.info("彩云天气数据全部下载完毕");
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
+ public static Timestamp convertStringToTimestamp(String dateStr) {
|
|
|
+ LocalDate localDate = LocalDate.parse(dateStr); // 解析 yyyy-MM-dd
|
|
|
+ return Timestamp.valueOf(localDate.atStartOfDay()); // 转换为当天的开始时间
|
|
|
}
|
|
|
|
|
|
/*public void analysis24(String hefeng24url, String caiyun24url, int areaCode, String name, Connection conn) {
|
|
@@ -397,6 +317,119 @@ public class GetWeather {
|
|
|
log.info("地区:{} 日天气数据下载完成", name);
|
|
|
}*/
|
|
|
|
|
|
+ public void download() {
|
|
|
+ List<String> areaCodes = new ArrayList<>();
|
|
|
+ List<DistrictCodeDO> districtCodeDOList = new ArrayList<>();
|
|
|
+ boolean isApiQuotaExhausted = false; // 引入标志变量
|
|
|
+ String startDate = DateUtil.today();
|
|
|
+ String endDate = DateUtil.offsetDay(DateUtil.date(), 15).toString("yyyy-MM-dd");
|
|
|
+ try {
|
|
|
+ List<Entity> dictList = Db.use().findAll("system_dict_data");
|
|
|
+ for (Entity entity : dictList) {
|
|
|
+ String name = entity.getStr("label");
|
|
|
+ if (name.contains("area_code")) {
|
|
|
+ String code = entity.getStr("value");
|
|
|
+ String[] s = code.split(",");
|
|
|
+ areaCodes = Arrays.asList(s);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ List<Entity> districtCodes = Db.use().findAll("jy_district_code");
|
|
|
+ for (Entity e : districtCodes) {
|
|
|
+ DistrictCodeDO districtCodeDO = new DistrictCodeDO();
|
|
|
+ districtCodeDO.setCode(Integer.parseInt(e.getStr("code")));
|
|
|
+ districtCodeDO.setName(e.getStr("name"));
|
|
|
+ districtCodeDO.setLevel(Integer.parseInt(e.getStr("level")));
|
|
|
+ districtCodeDO.setType(Integer.parseInt(e.getStr("type")));
|
|
|
+ districtCodeDO.setAbname(e.getStr("abname"));
|
|
|
+ districtCodeDO.setPid(Integer.parseInt(e.getStr("pid")));
|
|
|
+ districtCodeDO.setLat(!Objects.equals(e.getStr("lat"), "") && e.getStr("lat") != null ? new BigDecimal(e.getStr("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
|
|
|
+ districtCodeDO.setLng(!Objects.equals(e.getStr("lng"), "") && e.getStr("lng") != null ? new BigDecimal(e.getStr("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue() : 0d);
|
|
|
+ districtCodeDOList.add(districtCodeDO);
|
|
|
+ }
|
|
|
+ String jdbcUrl = "jdbc:TAOS://192.168.12.241:29500/etadm_local?user=root&password=taosdata";
|
|
|
+ Properties connProps = new Properties();
|
|
|
+ connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
|
|
+ connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
|
|
+ connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
|
|
+ Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
|
|
|
+ //省份
|
|
|
+ for (String code : areaCodes) {
|
|
|
+ //只有甘肃用xmo天气日接口
|
|
|
+ if (code.equals("620000")) {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
|
|
|
+ //市
|
|
|
+ for (DistrictCodeDO d : shiList) {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
|
|
|
+ String xmoUrl;
|
|
|
+ //彩云综合数据查询
|
|
|
+ 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;
|
|
|
+ isApiQuotaExhausted = analysisXMO(xmoUrl, d.getCode(), d.getName(), conn); // 传递标志变量
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ //区
|
|
|
+ for (DistrictCodeDO q : quList) {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ 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;
|
|
|
+ isApiQuotaExhausted = analysisXMO(xmoUrl, q.getCode(), q.getName(), conn); // 传递标志变量
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ //线程睡5秒 防止请求过快
|
|
|
+ //花钱了 硬气 不管他
|
|
|
+ //Thread.sleep(5000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ List<DistrictCodeDO> shiList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(code)).collect(Collectors.toList());
|
|
|
+ //市
|
|
|
+ for (DistrictCodeDO d : shiList) {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ List<DistrictCodeDO> quList = districtCodeDOList.stream().filter(item -> item.getPid().toString().equals(d.getCode().toString())).collect(Collectors.toList());
|
|
|
+ String caiyun;
|
|
|
+ //彩云综合数据查询
|
|
|
+ caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + d.getLng() + "," + d.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
|
|
|
+ isApiQuotaExhausted = analysis(caiyun, d.getCode(), d.getName(), conn); // 传递标志变量
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ //区
|
|
|
+ for (DistrictCodeDO q : quList) {
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ caiyun = "https://api.caiyunapp.com/v2.6/SRQIFijX5MGtdmhe/" + q.getLng() + "," + q.getLat() + "/weather?alert=true&dailysteps=7&hourlysteps=72";
|
|
|
+ isApiQuotaExhausted = analysis(caiyun, q.getCode(), q.getName(), conn); // 传递标志变量
|
|
|
+ if (isApiQuotaExhausted) break; // 检查标志变量
|
|
|
+ //线程睡5秒 防止请求过快
|
|
|
+ //花钱了 硬气 不管他
|
|
|
+ //Thread.sleep(5000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ conn.close();
|
|
|
+ String alarm = "电力交易系统在获取日级天气数据时报错, 彩云天气API 额度已用尽";
|
|
|
+ String description = "接口调用异常";
|
|
|
+ if (isApiQuotaExhausted) {
|
|
|
+ //给企业微信发送消息
|
|
|
+ /* WeixinPush weixinPush = new WeixinPush();
|
|
|
+ WeixinMessage weixinMessage = new WeixinMessage();
|
|
|
+ weixinMessage.setToUser("WangHongChen|XiuWei|DouZhi");
|
|
|
+ //获取今天的ymd
|
|
|
+ String ymd = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
|
|
|
+ weixinMessage.setContent(ymd + "日 电力交易系统在获取天气数据时报错, 彩云天气API 额度已用尽");
|
|
|
+ weixinMessage.setMsgType("text");
|
|
|
+ weixinMessage.setAgentid(1000009); // 确保 agentid 正确
|
|
|
+ weixinPush.sendMessage(weixinMessage);
|
|
|
+ */
|
|
|
+ weixinPush.sendMessageBot(alarm, description);
|
|
|
+ } else {
|
|
|
+ alarm = "电力交易系统彩云天气数据全部下载完毕";
|
|
|
+ description = "接口调用成功";
|
|
|
+ weixinPush.sendMessageBot(alarm, description);
|
|
|
+ log.info("彩云天气数据全部下载完毕");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public boolean analysis(String caiyun, int areaCode, String name, Connection conn) {
|
|
|
log.info("开始下载地区:{} 的天气数据", name);
|
|
|
try {
|
|
@@ -518,6 +551,68 @@ public class GetWeather {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ public boolean analysisXMO(String xmoUrl, int areaCode, String name, Connection conn) {
|
|
|
+ log.info("开始下载地区:{} 的天气数据", name);
|
|
|
+ try {
|
|
|
+ Statement ps = conn.createStatement();
|
|
|
+ String body = HttpUtil.createGet(xmoUrl).header("apikey", "c615a8f6-f5dd-4a81-86fe-db2a42862c15").execute().charset("utf-8").body();
|
|
|
+ //String body = HttpUtil.createGet(xmoUrl).header("apikey", "51bcabf8-3a5e-41e9-8bf2-b7676936cb22").execute().charset("utf-8").body();
|
|
|
+ JSONObject jsonObject = JSONUtil.parseObj(body);
|
|
|
+ //log.info("获取到的数据为:{}", body);
|
|
|
+ if (jsonObject.toString().contains("API call limit has been reached")) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //日数据 7d
|
|
|
+ JSONObject daily = JSONUtil.parseObj(jsonObject.get("daily"));
|
|
|
+ //日期
|
|
|
+ JSONArray date = JSONUtil.parseArray(daily.get("time"));
|
|
|
+ //日->辐照度
|
|
|
+ JSONArray dswrfDay = JSONUtil.parseArray(daily.get("shortwave_radiation_sum"));
|
|
|
+ //日->风速
|
|
|
+ JSONArray windSpeedDay = JSONUtil.parseArray(daily.get("wind_speed_10m_max"));
|
|
|
+ //雨量
|
|
|
+ JSONArray precip = JSONUtil.parseArray(daily.get("rain_sum"));
|
|
|
+ //2m温度
|
|
|
+ JSONArray temp = JSONUtil.parseArray(daily.get("temperature_2m_max"));
|
|
|
+ //10米风向
|
|
|
+ JSONArray direction = JSONUtil.parseArray(daily.get("wind_direction_10m_dominant"));
|
|
|
+ //天气代码
|
|
|
+ JSONArray code = JSONUtil.parseArray(daily.get("weather_code"));
|
|
|
+ //日数据写入
|
|
|
+ List<HeFengDay> heFengDayList = new ArrayList<>();
|
|
|
+ if (date.size() == 16) {
|
|
|
+ for (int i = 0; i < date.size(); i++) {
|
|
|
+ String time = date.get(i).toString();
|
|
|
+ HeFengDay heFengDay = new HeFengDay();
|
|
|
+ heFengDay.setTs(convertStringToTimestamp(time));
|
|
|
+ heFengDay.setWindSpeedDay(windSpeedDay.get(i) == null ? -0.99f : new BigDecimal(windSpeedDay.get(i).toString()).floatValue());
|
|
|
+ heFengDay.setWind360Day(direction.get(i).toString() == null ? -0.99f : new BigDecimal(direction.get(i).toString()).floatValue());
|
|
|
+ heFengDay.setPrecip(precip.get(i) == null ? -0.99f : new BigDecimal(precip.get(i).toString()).floatValue());
|
|
|
+ heFengDay.setTextDay(ConversionWeatherCodeXmo(code.get(i).toString() == null ? "0" : code.get(i).toString()));
|
|
|
+ heFengDay.setTempMax(temp.get(i) == null ? -0.99f : new BigDecimal(temp.get(i).toString()).floatValue());
|
|
|
+ heFengDay.setDswrf(dswrfDay.get(i) == null ? -0.99f : new BigDecimal(dswrfDay.get(i).toString()).floatValue());
|
|
|
+ heFengDayList.add(heFengDay);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("{} 的曦谋日数据不足16天,不入库!", name);
|
|
|
+ }
|
|
|
+ for (HeFengDay item : heFengDayList) {
|
|
|
+ String insertSQL = "INSERT INTO hefeng_day_unit_" + areaCode + " USING hefeng_day_unit TAGS('" + areaCode + "') " +
|
|
|
+ "(ts,wind_speed_day,wind_360_Day,precip,text_day,temp_max,dswrf) values('"
|
|
|
+ + item.getTs() + "', " + item.getWindSpeedDay() + ", " + item.getWind360Day() + ", " + item.getPrecip() + ", '"
|
|
|
+ + item.getTextDay() + "', " + item.getTempMax() + ", " + item.getDswrf() + ")";
|
|
|
+ int affectedRows = ps.executeUpdate(insertSQL);
|
|
|
+ }
|
|
|
+ if (ps != null)
|
|
|
+ ps.close();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("曦谋天气,地区:{} 日天气数据下载失败JSON格式化错误", name);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ log.info("曦谋天气,地区:{} 日天气数据下载完成", name);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
private Timestamp getTimestamp(String time) {
|
|
|
// 解析字符串为 ZonedDateTime
|
|
|
ZonedDateTime zonedDateTime = ZonedDateTime.parse(time);
|
|
@@ -577,5 +672,61 @@ public class GetWeather {
|
|
|
return "晴";
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ private String ConversionWeatherCodeXmo(String code) {
|
|
|
+ switch (code) {
|
|
|
+ case "0":
|
|
|
+ return "晴";
|
|
|
+ case "1":
|
|
|
+ return "多云";
|
|
|
+ case "2":
|
|
|
+ return "少云";
|
|
|
+ case "3":
|
|
|
+ return "阴";
|
|
|
+ case "45":
|
|
|
+ return "雾";
|
|
|
+ case "48":
|
|
|
+ return "冻雾";
|
|
|
+ case "51":
|
|
|
+ case "53":
|
|
|
+ case "55":
|
|
|
+ return "毛毛雨";
|
|
|
+ case "56":
|
|
|
+ case "57":
|
|
|
+ return "冻毛毛雨";
|
|
|
+ case "61":
|
|
|
+ return "小雨";
|
|
|
+ case "63":
|
|
|
+ return "中雨";
|
|
|
+ case "65":
|
|
|
+ return "大雨";
|
|
|
+ case "66":
|
|
|
+ case "67":
|
|
|
+ return "冻雨";
|
|
|
+ case "71":
|
|
|
+ return "小雪";
|
|
|
+ case "73":
|
|
|
+ return "中雪";
|
|
|
+ case "75":
|
|
|
+ return "大雪";
|
|
|
+ case "77":
|
|
|
+ return "雪粒";
|
|
|
+ case "80":
|
|
|
+ return "小阵雨";
|
|
|
+ case "81":
|
|
|
+ return "阵雨";
|
|
|
+ case "82":
|
|
|
+ return "强阵雨";
|
|
|
+ case "85":
|
|
|
+ return "小阵雪";
|
|
|
+ case "86":
|
|
|
+ return "阵雪";
|
|
|
+ case "95":
|
|
|
+ return "雷雨";
|
|
|
+ case "96":
|
|
|
+ case "99":
|
|
|
+ return "雷雨伴有冰雹";
|
|
|
+ default:
|
|
|
+ return "晴"; // 默认返回晴
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|