|
@@ -0,0 +1,298 @@
|
|
|
+package com.jsjty.jdc.data.service.impl;
|
|
|
+
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.security.InvalidKeyException;
|
|
|
+import java.text.DateFormat;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Calendar;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import javax.crypto.Mac;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.google.gson.JsonArray;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
+import com.google.gson.JsonObject;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
+import com.jsjty.jdc.data.mappers.WeatherAreaMapper;
|
|
|
+import com.jsjty.jdc.data.mappers.WeatherMapper;
|
|
|
+import com.jsjty.jdc.data.model.Weather;
|
|
|
+import com.jsjty.jdc.data.model.WeatherArea;
|
|
|
+import com.jsjty.jdc.data.service.FetchService;
|
|
|
+import com.jsjty.jdc.data.util.HttpProxy;
|
|
|
+import com.jsjty.jdc.data.util.IdGenerator;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 心知天气抓取服务
|
|
|
+ *
|
|
|
+ * @author
|
|
|
+ *
|
|
|
+ */
|
|
|
+@Service("weatherXZFetchService")
|
|
|
+public class WeatherXZFetchService implements FetchService {
|
|
|
+ private Logger logger = LoggerFactory.getLogger(WeatherXZFetchService.class);
|
|
|
+ /** 心知天气网APPID密钥 */
|
|
|
+ public static String WEATHER_KEY = "8jjmhrqevzmjxzh0";
|
|
|
+ @Autowired
|
|
|
+ private WeatherMapper mapper;
|
|
|
+ @Autowired
|
|
|
+ private WeatherAreaMapper areaMapper;
|
|
|
+ @Autowired
|
|
|
+ private IdGenerator idGenerator;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int doFetch() {
|
|
|
+ List<WeatherArea> areaList = areaMapper.selectAreas(getDeployTime());
|
|
|
+ boolean success = true;
|
|
|
+ for (WeatherArea area : areaList) {
|
|
|
+ if(area.getC2().equals("nanjing")) {
|
|
|
+ System.out.println("sss");
|
|
|
+ }
|
|
|
+ success = fetchWeater(area) && success;
|
|
|
+ }
|
|
|
+ /*if (!success) {
|
|
|
+ // 抓取没有完全成功,60秒后重新抓取
|
|
|
+ throw new TaskRedoException(60, TimeUnit.SECONDS, "抓取失败");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return areaList.size();
|
|
|
+ }*/
|
|
|
+ return areaList.size();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 抓取区域天气信息
|
|
|
+ *
|
|
|
+ * @param areaId
|
|
|
+ */
|
|
|
+ private boolean fetchWeater(WeatherArea area) {
|
|
|
+ Date d = new Date();
|
|
|
+ String url = buildUrl(area.getC2());
|
|
|
+ String res = null;
|
|
|
+ try {
|
|
|
+ logger.info("获取天气信息,url:{}", url);
|
|
|
+ res = HttpProxy.http_get_json(url);
|
|
|
+ }
|
|
|
+ catch (Exception e) {
|
|
|
+ logger.error("获取天气信息出错,url:{},错误信息:{}", url, e.getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (null == res) {
|
|
|
+ System.err.println("该区域未获取到天气信息:"+area.getC2());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 生成缓存key,天气每天发布3次,时间分别是08、11、18;
|
|
|
+ JsonParser jp = new JsonParser();
|
|
|
+ JsonElement je = jp.parse(res);
|
|
|
+ JsonObject retJson = je.getAsJsonObject();
|
|
|
+ JsonArray f = retJson.getAsJsonArray("results");
|
|
|
+ JsonArray dayweaters = retJson.getAsJsonArray("results")
|
|
|
+ .get(0).getAsJsonObject().get("daily").getAsJsonArray();
|
|
|
+ Calendar c = Calendar.getInstance();
|
|
|
+ c.setTime(d);
|
|
|
+ JsonObject d1 = dayweaters.get(0).getAsJsonObject();
|
|
|
+ JsonObject d2 = dayweaters.get(1).getAsJsonObject();
|
|
|
+ JsonObject d3 = dayweaters.get(2).getAsJsonObject();
|
|
|
+ saveWeather(area.getC1(), d1, c.getTime());
|
|
|
+ c.add(Calendar.DATE, 1);
|
|
|
+ saveWeather(area.getC1(), d2, c.getTime());
|
|
|
+ c.add(Calendar.DATE, 1);
|
|
|
+ saveWeather(area.getC1(), d3, c.getTime());
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存
|
|
|
+ * @param name 城市英文名
|
|
|
+ * @param data 数据
|
|
|
+ * @param time 日期
|
|
|
+ */
|
|
|
+ private void saveWeather(String areaId, JsonObject data, Date time) {
|
|
|
+ DateFormat df = new SimpleDateFormat("yyyyMMdd");
|
|
|
+ String sj = df.format(time);
|
|
|
+ Calendar c = Calendar.getInstance();
|
|
|
+ c.setTime(new Date());
|
|
|
+ // 系统当前日
|
|
|
+ int currDay = c.get(Calendar.DAY_OF_MONTH);
|
|
|
+ c.setTime(time);
|
|
|
+ // 数据所在日
|
|
|
+ int dataDay = c.get(Calendar.DAY_OF_MONTH);
|
|
|
+ // 数据所在时
|
|
|
+ int dataHour = c.get(Calendar.HOUR_OF_DAY);
|
|
|
+ // 查询老记录
|
|
|
+ Weather weather = mapper.selectBySjAndArea(sj, areaId);
|
|
|
+ // 如果已存在记录则判断是否需要更新
|
|
|
+ if (weather != null) {
|
|
|
+ weather.setFa(data.get("code_day").getAsString());
|
|
|
+ weather.setFb(data.get("code_night").getAsString());
|
|
|
+ weather.setFc(data.get("high").getAsString());
|
|
|
+ weather.setFd(data.get("low").getAsString());
|
|
|
+ weather.setFe(data.get("wind_direction").getAsString());
|
|
|
+ weather.setFf(data.get("wind_direction").getAsString());
|
|
|
+ weather.setFg(data.get("wind_scale").getAsString());
|
|
|
+ weather.setFh(data.get("wind_scale").getAsString());
|
|
|
+ weather.setFi("");
|
|
|
+ // 更新夜晚数据
|
|
|
+ if (dataDay == currDay && dataHour >= 18) {
|
|
|
+ mapper.updateNightByPrimaryKey(weather);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ mapper.updateByPrimaryKey(weather);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 不存在记录则插入
|
|
|
+ else {
|
|
|
+ weather = new Weather();
|
|
|
+ weather.setId(idGenerator.generateStringId());
|
|
|
+ weather.setFa(data.get("code_day").getAsString());
|
|
|
+ weather.setFb(data.get("code_night").getAsString());
|
|
|
+ weather.setFc(data.get("high").getAsString());
|
|
|
+ weather.setFd(data.get("low").getAsString());
|
|
|
+ weather.setFe(data.get("wind_direction").getAsString());
|
|
|
+ weather.setFf(data.get("wind_direction").getAsString());
|
|
|
+ weather.setFg(data.get("wind_scale").getAsString());
|
|
|
+ weather.setFh(data.get("wind_scale").getAsString());
|
|
|
+ weather.setSj(Integer.parseInt(sj));
|
|
|
+ weather.setArea(areaId);
|
|
|
+ mapper.insert(weather);
|
|
|
+ }
|
|
|
+ mapper.updateWeatherAreaF0ByC1(getDeployTime(), areaId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param name
|
|
|
+ * 城市英文名
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String buildUrl(String name) {
|
|
|
+ // 客户端日期 按照格式 yyyyMMddHHmm 获取客户端当前时间
|
|
|
+ String url = null;
|
|
|
+ try {
|
|
|
+ StringBuilder urlBuilder = new StringBuilder();
|
|
|
+ //需要加密的数据
|
|
|
+ urlBuilder.append("https://api.thinkpage.cn/v3/weather/daily.json?key=");
|
|
|
+ urlBuilder.append(WEATHER_KEY);
|
|
|
+ urlBuilder.append("&location=");
|
|
|
+ urlBuilder.append(name);
|
|
|
+ urlBuilder.append("&language=zh-Hans&unit=c&start=0&days=5");
|
|
|
+ url = urlBuilder.toString();
|
|
|
+ }
|
|
|
+ catch (Exception e) {
|
|
|
+ logger.error("创建天气查询出错,错误信息:{}", e.getMessage());
|
|
|
+ }
|
|
|
+ return url;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String standardURLEncoder(String data, String key) {
|
|
|
+ byte[] byteHMAC = null;
|
|
|
+ String urlEncoder = "";
|
|
|
+ try {
|
|
|
+ Mac mac = Mac.getInstance("HmacSHA1");
|
|
|
+ SecretKeySpec spec = new SecretKeySpec(key.getBytes(), "HmacSHA1");
|
|
|
+ mac.init(spec);
|
|
|
+ byteHMAC = mac.doFinal(data.getBytes());
|
|
|
+ if (byteHMAC != null) {
|
|
|
+ String oauth = encode(byteHMAC);
|
|
|
+ if (oauth != null) {
|
|
|
+ urlEncoder = URLEncoder.encode(oauth, "utf8");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (InvalidKeyException e1) {
|
|
|
+ e1.printStackTrace();
|
|
|
+ }
|
|
|
+ catch (Exception e2) {
|
|
|
+ e2.printStackTrace();
|
|
|
+ }
|
|
|
+ return urlEncoder;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final char last2byte = (char) Integer.parseInt("00000011", 2);
|
|
|
+ private static final char last4byte = (char) Integer.parseInt("00001111", 2);
|
|
|
+ private static final char last6byte = (char) Integer.parseInt("00111111", 2);
|
|
|
+ private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
|
|
|
+ private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
|
|
|
+ private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
|
|
|
+ private static final char[] encodeTable = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
|
|
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
|
|
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
|
|
|
+ '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
|
|
|
+
|
|
|
+ private String encode(byte[] from) {
|
|
|
+ StringBuffer to = new StringBuffer((int) (from.length * 1.34) + 3);
|
|
|
+ int num = 0;
|
|
|
+ char currentByte = 0;
|
|
|
+ for (int i = 0; i < from.length; i++) {
|
|
|
+ num = num % 8;
|
|
|
+ while (num < 8) {
|
|
|
+ switch (num) {
|
|
|
+ case 0:
|
|
|
+ currentByte = (char) (from[i] & lead6byte);
|
|
|
+ currentByte = (char) (currentByte >>> 2);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ currentByte = (char) (from[i] & last6byte);
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ currentByte = (char) (from[i] & last4byte);
|
|
|
+ currentByte = (char) (currentByte << 2);
|
|
|
+ if ((i + 1) < from.length) {
|
|
|
+ currentByte |= (from[i + 1] & lead2byte) >>> 6;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 6:
|
|
|
+ currentByte = (char) (from[i] & last2byte);
|
|
|
+ currentByte = (char) (currentByte << 4);
|
|
|
+ if ((i + 1) < from.length) {
|
|
|
+ currentByte |= (from[i + 1] & lead4byte) >>> 4;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ to.append(encodeTable[currentByte]);
|
|
|
+ num += 6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (to.length() % 4 != 0) {
|
|
|
+ for (int i = 4 - to.length() % 4; i > 0; i--) {
|
|
|
+ to.append("=");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return to.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前应该获取的数据时间
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getDeployTime() {
|
|
|
+ Calendar c = Calendar.getInstance();
|
|
|
+ int h = c.get(Calendar.HOUR_OF_DAY);
|
|
|
+ if (h >= 18) {
|
|
|
+ c.set(Calendar.HOUR_OF_DAY, 18);
|
|
|
+ }
|
|
|
+ else if (h >= 11) {
|
|
|
+ c.set(Calendar.HOUR_OF_DAY, 11);
|
|
|
+ }
|
|
|
+ else if (h >= 8) {
|
|
|
+ c.set(Calendar.HOUR_OF_DAY, 8);
|
|
|
+ }
|
|
|
+ DateFormat df = new SimpleDateFormat("yyyyMMddHH");
|
|
|
+ String dateTime = df.format(c.getTime());
|
|
|
+ dateTime += "00";
|
|
|
+ return dateTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getName() {
|
|
|
+ return "天气抓取服务";
|
|
|
+ }
|
|
|
+}
|