需求
做了一个系统,里面要显示天气信息,不是实时天气,而是历史天气,好多天,任何天,具体哪天,要看用户在页面上选择的日期是哪天。
方案调研
最开始想到了高德地图,它提供了天气API,但是后来发现它提供的是当前实时天气的API,系统中还有要显示2019年天气的地方,不合适。
在网上又找了几个免费的,网页的。发请求,得到网页内容之后,使用正则、XPath等各种魔法,解析内容,获得天气。刚开始可以跑,后来发现数据有限,跑着跑着就没数据了,代码都写好了,发现数据没有了,好烦。
最终找到了易客云的天气API,实时天气、历史天气、降水、气温等等,各类专业的API,非常好,调接口得到的就是JSON,直接缓存到Redis并入MySQL,下次就不调他了,直接从自己的缓存中取,缓存中没有去就数据库中取,搞定!
易客云天气API使用
使用非常简单,去官网 易客云天气API免费天气API接口|天气预报接口|全球天气API接口|气象预警|空气质量 注册一个账号:
会免费送许多额度:
就可以开始调用了。
调用的地址、参数都在官方文档中,一个HTTP get请求就搞定了,还不是HTTPS的,HTTP即可,又快又省事,太简单了。以获取历史天气信息为例:
接口地址:
http://v1.yiketianqi.com/free/history?appid=96142279&appsecret=x7lVy6Bk&cityid=101120101&year=2022&month=1
在这里我使用hutool的HTTP请求工具,不再单独写HTTPConnection的封装了:
@Override
public Object pullHistoryWeather2(String year, String month) {
String body;
Object o = objectRedisTemplate.opsForHash().get(Constants.WEATHER_YI_KE_TIAN_QI_LIMITED, year + "-" + month);
if (o == null) {
// 这是个付费接口,要严格限制它的调用次数,防止被攻击刷钱
String url = String.format("http://v0.yiketianqi.com/api?version=history&appid=123&appsecret=abc&adcode=330100000000&year=%s&month=%s", year, month);
LocalDateTime start = LocalDateTime.now();
HttpRequest httpRequest = HttpUtil.createGet(url);
HttpResponse httpResponse = httpRequest.execute();
int status = httpResponse.getStatus();
if (status != HttpStatus.HTTP_OK) {
return "第三方接口失败,状态码:" + status;
}
body = httpResponse.body();
if (StringUtils.isBlank(body)) {
return "第三方接口失败,响应为空";
}
log.info("请求完成,URL:{},耗时:{},响应:{}", url, Duration.between(start, LocalDateTime.now()), body);
objectRedisTemplate.opsForHash().put(Constants.WEATHER_YI_KE_TIAN_QI_LIMITED, year + "-" + month, body);
objectRedisTemplate.expire(Constants.WEATHER_YI_KE_TIAN_QI_LIMITED, 365, TimeUnit.DAYS);
} else {
body = o.toString();
if (StringUtils.isBlank(body)) {
return "缓存的第三方接口失败响应为空";
}
}
JSONObject parsedObject = JSON.parseObject(body);
JSONArray data = parsedObject.getJSONArray("data");
for (int i = 0; i < data.size(); i++) {
JSONObject jsonObject = data.getJSONObject(i);
String ymd = jsonObject.getString("ymd");
String tianQi = jsonObject.getString("tianqi");
Weather row = new Weather();
row.setDate(ymd);
row.setWeather(tianQi);
weatherMapper.insertOrUpdate(row);
}
return "成功";
}
代码很简单,发请求之前,先去Redis中找,如果找到了,就不去调接口了,如果没找到,再调接口,避免给接口造成太大压力,或者资源浪费。
最后说一点,这个接口它查历史天气的时候,支持按年月查,这个就方便很多了。不必自己反复计算哪天到哪天差几天漏哪天什么的。一个for循环,搞定。