接上一篇博文。http://blog.csdn.net/icedcap/article/details/20743627
上一篇博文稍微开了个头,没想到很多朋友都很感兴趣催我继续往下写。今天挤出点时间为大家继续介绍。
在进入真题之前,笔者还是想要吐槽以下中国气象局。事情是这样的,笔者申请的是android和ios平台的接口,而他却给我的web端的接口。笔者回信询问他却说统一发放web端的appid和private_key。既然你光给开发者web端的,你何必在官网介绍移动端介绍的那么好还给了那么详细的文档呢?要是知道你仅给个web端的,我还不如省去麻烦用其他不需要appid和private_key的web接口呢!
好了,唠叨就那么多,现在进入正题。
一、官方文档使用说明
以下是文档中的原话,copy过来。
1、产品概述
SmartWeatherAPI 接口(简称”SWA”接口)是中国气象局面向网络媒体、手机厂商、第三方气象服务机构等用户,通过 web 方式提供数据气象服务的官方载体。
2、使用说明
该数据主要包括实况、指数、常规预报等数据内容。
3、调用规范
规范用于指导开放平台用户合理调用实况、指数、常规预报等服务数据。
请求方式:http get
接口组成:由固定 URL 加 5 个不同的参数组成,完整 URL 需客户端经过固定方式加密后使用。
数据返回:json
完整 URL:http://webapi.weather.com.cn/data/?areaid=""&type=""&date=""&appid=""&key=".urlencode($key);
注意:这里的appid只取字符串的前六位。
固定 URL:http://webapi.weather.com.cn/data/
这里边的难点就在于请求URL的最后一个参数key=".urlencode($key),它是一个通过php的函数算出来的。具体如下:
加密方式:
private_key 仅负责与 public_key 共同合成 key 传参,私钥不可见,客户端与服务端各存储一份;
public_key 为不包含 key 在内的完整 URL 其它部分(此处appid 为完整 appid)
示例:
http://webapi.weather.com.cn/data/?areaid=101010100&type=forecast&date=201211281030&appid= cf2d61521456sads
key 的算法
key=base64_encode(hash_hmac(‘sha1‘,$public_key,$private_key,TRUE));
key 加密后通过 urlencode 对其编码后传参
注:每一个产品使用用户分配一个唯一标识 appid,用于统计用户访问情况、区分用户提供差异服务,终端用户按照终端型号分配,一个型号对应一个标识。
由于key的算法在web端开发是十分顺手的,只需要将上面那串代码写到php中就OK了,然而将上述算法迁徙到java中还是费了笔者不少的功夫,这里笔者将无私的分享给大家。具体代码如下:
/** * 计算签名 * @param baseString 明文 * @param keyString 私钥 * @return 秘钥 * @throws GeneralSecurityException * @throws UnsupportedEncodingException */ public static String computeSignature(String baseString, String keyString) throws GeneralSecurityException, UnsupportedEncodingException { SecretKey secretKey = null; byte[] keyBytes = keyString.getBytes(); secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKey); byte[] text = baseString.getBytes(); return new String(Base64.encodeBase64(mac.doFinal(text))).trim(); }
二、JSON解析
突破了秘钥的难关就已经完成了一半了。下面笔者将介绍如何解析的得到的JSON数据。
这里将拿得到的实时天气数据来解释。数据如下:
{"l":{"l1":"8","l2":"35","l3":"2","l4":"2","l7":"15:30"}}
很简单,对JSON没什么概念的就可以直接理解成第一个l代表引用在它冒号后面的是他的对象,其中对象中的l1,l2,l3,l4,l7分别是对象的不同属性,在API中这几个属性分别代表“当前温度”、“当前湿度”、“当前风力”、“当前风向”、“发布时间”。
代码如下:
JSONObject obj = new JSONObject(bufferString.trim()).getJSONObject("l");
String currentTemperature = obj.getString("l1"); String currentHumidity = obj.getString("l2"); String currentWindForce = obj.getString("l3"); String currentWindDirectionNumber = obj.getString("l4");
这是最简单的一种JSON数据格式,在该应用中你还会发现如下结构的JSON。
{"f1":[{"fg":"","ff":"0","fi":"06:34|18:15","fh":"0","fa":"","fd":"2","fe":"","fb":"53","fc":""},{"fg":"0","ff":"8","fi":"06:32|18:16","fh":"1","fa":"02","fd":"3","fe":"0","fb":"07","fc":"12"},{"fg":"0","ff":"0","fi":"06:30|18:17","fh":"0","fa":"00","fd":"-2","fe":"0","fb":"00","fc":"10"}]
}
这种结构也可以用对象的概念说通只不过对象变成了对象数组。
这里的f1代表的三天内的天气情况,天气具体情况存入了数组中解析的时候要用如下代码:
JSONArray forecast = forecast3d.getJSONArray("f1");
String[] dayWeatherPhenomenonNumber = new String[forecast.length()]; String[] nightWeatherPhenomenonNumber = new String[forecast .length()]; String[] maxTemperature = new String[forecast.length()]; String[] minTemperature = new String[forecast.length()]; String[] dayWindDirectionNumber = new String[forecast.length()]; String[] nightWindDirectionNumber = new String[forecast.length()]; String[] dayWindForce = new String[forecast.length()]; String[] nightWindForce = new String[forecast.length()]; String[] dayWindDirection = new String[forecast.length()]; String[] nightWindDirection = new String[forecast.length()]; String[] dayWeatherPhenomenon = new String[forecast.length()]; String[] nightWeatherPhenomenon = new String[forecast.length()]; String forecast3dMsg[] = new String[forecast.length()]; for (int i = 0; i < forecast.length(); i++) { JSONObject forecastObj = (JSONObject) forecast.opt(i); dayWeatherPhenomenonNumber[i] = forecastObj.getString("fa");// 白天天气现象编号 nightWeatherPhenomenonNumber[i] = forecastObj.getString("fb");// 夜晚天气现象编号 System.out.println("day气象编号----》"+ dayWeatherPhenomenonNumber[i]); dayWeatherPhenomenon[i] = Util.getWeatherPhenomenon(dayWeatherPhenomenonNumber[i]); System.out.println("night气象编号----》"+ nightWeatherPhenomenonNumber[i]); nightWeatherPhenomenon[i] = Util.getWeatherPhenomenon(nightWeatherPhenomenonNumber[i]);// 具体天气现象 maxTemperature[i] = forecastObj.getString("fc"); minTemperature[i] = forecastObj.getString("fd");// 气温 dayWindDirectionNumber[i] = forecastObj.getString("fe"); nightWindDirectionNumber[i] = forecastObj.getString("ff");// 风向编号 dayWindDirection[i] = Util.getWindDirection(dayWindDirectionNumber[i]); nightWindDirection[i] = Util.getWindDirection(nightWindDirectionNumber[i]);// 具体风向 dayWindForce[i] = forecastObj.getString("fg"); nightWindForce[i] = forecastObj.getString("fh");// 风力 forecast3dMsg[i] = "\n第" + (i + 1) + "天: " + "白天:" + dayWeatherPhenomenon[i] + " " + dayWindDirection[i] + dayWindForce[i] + "级\n" + " 夜晚:" + nightWeatherPhenomenon[i] + " " + nightWindDirection[i] + nightWindForce[i] + "级 气温:" + minTemperature[i] + "~" + maxTemperature[i] + "℃"; System.out.println(forecast3dMsg); }
好了,今天先说这么多吧。下一篇博客,将介绍http异步加载的优化。
由于有朋友留言要代码,那我就先贴出没优化过的代码:
http://download.csdn.net/detail/icedcap/7019301
最后的最后给大家贴出今未3天的天气情况(北京地区)