一.需求
最近,刚好项目中有天气预报查询功能的需求,要求录入城市名称,获取该城市今日天气信息及相关气象生活辅助信息等。
例如:查询北京市天气
结果为:
今日北京天气:15℃~5℃ 阵雨转阴,北风3-4级,天气冷,建议着棉服、羽绒服、皮夹克加羊毛衫等冬季服装。年老体弱者宜着厚棉衣、冬大衣 或厚羽绒服。 洗车指数:不宜。紫外线指数:最弱。晨练指数:较不宜.舒适指数:较舒适。
还好,国家气象局提供相关接口,再此表示感谢,虽然个人觉得该api设计思路有待提高,但是相比于其他部委【如交通部】来说,气象局这个冷衙门有开源、开放的心态,相比而言,相当了不起。期待后期能在接口规范、可提供查询城市数量等方面继续提高。
二.接口说明
据我所知,气象局提供三个天气查询接口,如下:
1、实时天气接口
地址:http://www.weather.com.cn/data/ sk/【城市代码】.html
例如:查询北京实时天气
结果:
{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"13","WD":"南风","WS":"2","SD":"59%","WSE":"2","time":"10:30","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}}
2、今日天气接口
地址:http://www.weather.com.cn/data/cityinfo/【城市代码】.html
例如:查询北京今日天气
结果:
{"weatherinfo":{"city":"北京","cityid":"101010100","temp1":"15","temp2":"5℃","weather":"阵雨转阴","img1":"d3.gif","img2":"n2.gif","ptime":"08:00"}}
3、今日及未来天气接口【内容最详细】
地址:http://m.weather.com.cn/data/【城市代码】.html
例如:查询北京今日及未来天气
结果:
{"weatherinfo":{"city":"北京","city_en":"beijing","date_y":"2013年10月22日","date":"","week":"星期二","fchh":"08","cityid":"101010100","temp1":"15℃~5℃","temp2":"15℃~4℃………【省略】"index_tr":"适宜","index_co":"较舒适","st1":"11","st2":"1","st3":"13","st4":"5","st5":"14","st6":"4","index_cl":"较不宜","index_ls":"不太适宜","index_ag":"不易发"}}
字段说明:我刚好是调用这个接口,所以下面通过对应的实体及属性来说明上述返回结果中各字段的含义
/// <summary>
/// 天气查询结果信息实体
/// </summary>
public class WeatherinfoModel
{
/// <summary>
/// 城市名称
/// </summary>
public String city{get;set;} /// <summary>
/// 城市英文名称==拼音
/// </summary>
public String city_en{get;set;} /// <summary>
/// 今日时间【年-月-日】
/// </summary>
public String date_y{get;set;} /// <summary>
/// 为空,无用
/// </summary>
public String date{get;set;} /// <summary>
/// 星期几
/// </summary>
public String week{get;set;} /// <summary>
/// 系统更新时间
/// </summary>
public String fchh{get;set;} /// <summary>
/// 城市代码
/// </summary>
public String cityid{get;set;} /// <summary>
/// 今天及之后五天的摄氏温度
/// </summary>
public String temp1{get;set;}
public String temp2{get;set;}
public String temp3{get;set;}
public String temp4{get;set;}
public String temp5{get;set;}
public String temp6{get;set;} /// <summary>
/// 今天及之后五天的华氏温度
/// </summary>
public String tempF1{get;set;}
public String tempF2{get;set;}
public String tempF3{get;set;}
public String tempF4{get;set;}
public String tempF5{get;set;}
public String tempF6{get;set;} /// <summary>
/// 今天及之后五天的天气描述
/// </summary>
public String weather1{get;set;}
public String weather2{get;set;}
public String weather3{get;set;}
public String weather4{get;set;}
public String weather5{get;set;}
public String weather6{get;set;} /// <summary>
/// 天气描述图片序号
/// </summary>
public String img1{get;set;}
public String img2{get;set;}
public String img3{get;set;}
public String img4{get;set;}
public String img5{get;set;}
public String img6{get;set;}
public String img7{get;set;}
public String img8{get;set;}
public String img9{get;set;}
public String img10{get;set;}
public String img11{get;set;}
public String img12{get;set;}
public String img_single{get;set;} /// <summary>
/// 图片名称
/// </summary>
public String img_title1{get;set;}
public String img_title2{get;set;}
public String img_title3{get;set;}
public String img_title4{get;set;}
public String img_title5{get;set;}
public String img_title6{get;set;}
public String img_title7{get;set;}
public String img_title8{get;set;}
public String img_title9{get;set;}
public String img_title10{get;set;}
public String img_title11{get;set;}
public String img_title12{get;set;}
public String img_title_single{get;set;} /// <summary>
/// 今天及之后五天的风速描述
/// </summary>
public String wind1{get;set;}
public String wind2{get;set;}
public String wind3{get;set;}
public String wind4{get;set;}
public String wind5{get;set;}
public String wind6{get;set;} /// <summary>
/// 风速级别描述
/// </summary>
public String fx1{get;set;}
public String fx2{get;set;}
public String fl1{get;set;}
public String fl2{get;set;}
public String fl3{get;set;}
public String fl5{get;set;}
public String fl6{get;set;} /// <summary>
/// 今天穿衣指数
/// </summary>
public String index{get;set;}
public String index_d{get;set;} /// <summary>
/// 48小时穿衣指数
/// </summary>
public String index48{get;set;}
public String index48_d{get;set;} /// <summary>
/// 紫外线及48小时紫外线
/// </summary>
public String index_uv{get;set;}
public String index48_uv{get;set;} /// <summary>
/// 洗车
/// </summary>
public String index_xc{get;set;} /// <summary>
/// 旅游
/// </summary>
public String index_tr{get;set;} /// <summary>
/// 舒适指数
/// </summary>
public String index_co{get;set;} /// <summary>
/// ??
/// </summary>
public String st1{get;set;}
public String st2{get;set;}
public String st3{get;set;}
public String st4{get;set;}
public String st5{get;set;}
public String st6{get;set;} /// <summary>
/// 晨练
/// </summary>
public String index_cl{get;set;} /// <summary>
/// 晾晒
/// </summary>
public String index_ls{ get; set; } /// <summary>
/// 过敏
/// </summary>
public String index_ag{get;set;}
}
总结:从上面三个接口来看,调用的关键是获取【城市代码】,所以气象局又提供了三个查询城市代码接口。个人有个疑问?为何气象局不提供一个或三个xml文档或json文本?比现在省市县逐级拼接获取方便很多,或许已经有,只是我不知道,求补充啊!
4、省份或直辖市代码接口
地址:http://www.weather.com.cn/data/citydata/china.html
结果:
{"10101":"北京","10102":"上海","10103":"天津","10104":"重庆","10105":"黑龙江","10106":"吉林","10107":"辽宁","10108":"内蒙古","10109":"河北","10110":"山西","10111":"陕西","10112":"山东","10113":"*","10114":"*","10115":"青海","10116":"甘肃","10117":"宁夏","10118":"河南","10119":"江苏","10120":"湖北","10121":"浙江","10122":"安徽","10123":"福建","10124":"江西","10125":"湖南","10126":"贵州","10127":"四川","10128":"广东","10129":"云南","10130":"广西","10131":"海南","10132":"香港","10133":"澳门","10134":"*"}
5、省会或地区市代码接口
地址:http://www.weather.com.cn/data/citydata/district/【省份或直辖市代码】.html
例如:查询福建省包含的城市
结果:
{"01":"福州","02":"厦门","03":"宁德","04":"莆田","05":"泉州","06":"漳州","07":"龙岩","08":"三明","09":"南平"}
6、区或县代码
地址:http://www.weather.com.cn/data/citydata/city/【省份或直辖市代码】+【省会或地区市代码】.html
例如:查询福建省南平市包含的区县
结果:
{"01":"南平","02":"顺昌","03":"光泽","04":"邵武","05":"武夷山","06":"浦城","07":"建阳","08":"松溪","09":"政和","10":"建瓯"}
说明:
注意该结果不仅包含区县,还包含上级的地级市或省会城市,所以我们只要获取这一级别的结果,再拼接就可以获取省会城市、地级市及区县的城市代码!
三. 城市代码拼接
通过上述三个接口,我们可以通过拼接省市县级别城市代码,来获取南平市或政和县的城市代码。
例如:南平市代码为:101230901【10123是福建省的省级代码+09南平市的市级代码+01南平市的区县级代码】,同理,政和县代码为:101230909。
知道城市代码后,要获取政和县的今日天气,调用下面的url就可以了:
注意:并不是所有的城市代码都是通过省市县来拼接,存在下面两个问题。个人建议各城市的代码完全可以==该城市的邮编,因为各省市县的邮编都是不可能重复的,but.....
问题一:海南下属市及湖北荆州的沙市中区县代码包含省级代码和市级代码,如:
问题二:四个直辖市的城市代码不是由省+市+县代码拼接,而是用省+县+市代码拼接方式。
所以,城市代码的拼接方法如下:
//pID:省或直辖市代码
//cID:省会或地区市代码
//dID:区或县代码
int code=0;//城市代码
//name:区县名称
//如果是海南省或湖北荆州沙市【感谢luoliurong反馈,否则未对沙市特别处理,无法查询】,则直接获取
if (pID == 10131||name == "沙市")
{
code = int.Parse(dID);
}
//如果是直辖市
else if (pID < 10105)
{
int.TryParse(string.Format("{0}{1}{2}", pID, dID, cID), out code);
}
else
{
int.TryParse(string.Format("{0}{1}{2}", pID, cID, dID), out code);
}
通过上述说明,表明我们需要建一个项目循环请求并获取各级城市的城市代码,可以将城市代码保存在数据库中,也可以保存在xml文件中。我做法是保存在数据库中,同时生成xml文件,一周更新xml文件一次,并将该xml通过文件依赖缓存到内存中,使用该缓存的xml作为城市代码查询的数据源。
四. 省市县代码表表结构
表名:Weather_Province【省代码表实体】
表名:Weather_City【省会或地级市代码表实体】
表名:Weather_District【区或县代码表实体】
可被直接调用代码,即该区县的代码
源码包中的DBScript.sql为上述数据脚本
五. 获取省级代码数据
Http请求方法:
/// <summary>
/// Get方式获取url地址输出内容
/// </summary>
/// <param name="url">url</param>
/// <param name="encoding">返回内容编码方式,例如:Encoding.UTF8</param>
/// <returns></returns>
public static String SendRequestByGetMethod(String url,Encoding encoding)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "GET";
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
StreamReader sr = new StreamReader(webResponse.GetResponseStream(), encoding);
return sr.ReadToEnd();
}
/// <summary>
/// 生成天气查询省代码表
/// </summary>
private void CreateProvinceCode()
{
m_ProvinceBLL.TruncateProvince();
var responseText = HttpRequestOpt.SendRequestByGetMethod("http://www.weather.com.cn/data/citydata/china.html",System.Text.Encoding.UTF8);
if (!String.IsNullOrEmpty(responseText))
{
m_ProvinceBLL.SaveProvinceCode(responseText);
}
}
/// <summary>
/// 添加天气查询省代码表
/// </summary>
/// <param name="responseText">查询结果文本</param>
public void SaveProvinceCode(String responseText)
{
responseText = responseText.TrimStart('{').TrimEnd('}');
List<Weather_ProvinceModel> list = new List<Weather_ProvinceModel>();
responseText.Split(',').ToList().ForEach(item =>
{
Weather_ProvinceModel provinceModel = new Weather_ProvinceModel();
if (!String.IsNullOrEmpty(item) && item.Split(':').Count() == 2 && !String.IsNullOrEmpty(item.Split(':')[0]) && !String.IsNullOrEmpty(item.Split(':')[1]))
{
int pID = 0;
int.TryParse(item.Split(':')[0].Trim('"'), out pID);
provinceModel.PID = pID;
provinceModel.Name = item.Split(':')[1].Trim('"');
list.Add(provinceModel);
}
});
if (list.Count > 0)
{
m_ProvinceDAL.SaveProvinceCode(list);
}
}
/// <summary>
/// 批量添加天气查询省代码表
/// </summary>
/// <param name="list">省代码表实体集</param>
public void SaveProvinceCode(List<Weather_ProvinceModel> list)
{
SqlBulkCopy sqlBc = null;
DataTable dt = new DataTable();
try
{
sqlBc = new SqlBulkCopy(Common.WebConfig.WeatherDBConnString, SqlBulkCopyOptions.UseInternalTransaction);
sqlBc.DestinationTableName = "Weather_Province";
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(String));
dt.Columns.Add("PID", typeof(int));
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
list.ForEach(entity =>
{
DataRow dr = dt.NewRow();
dr["Name"] = entity.Name;
dr["PID"] = entity.PID;
dt.Rows.Add(dr);
});
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
}
catch (Exception ex)
{
string mayLoseData = Common.JsonHelp.SerializeJson(dt);
Common.Log4NetHelp.LoseDataLog("ProvinceDAL", "SaveProvinceCode", string.Format("批量添加天气查询省代码表异常,异常信息:{0}", ex.Message), mayLoseData);
}
finally
{
if (sqlBc != null)
{
sqlBc.Close();
}
}
}
六. 获取省会或地级市代码表数据
///<summary>/// 获取天气查询省代码表所有数据
///</summary>///<returns></returns>public DataSet GetAllProvince()
{
String strSql ="select * from Weather_Province order by PID asc";
return DbHelperSQL.Query(strSql);
}
/// <summary>
/// 生成天气查询市代码表
/// </summary>
private void CreateCityCode()
{
m_CityBLL.TruncateCity();
DataSet ds = m_ProvinceBLL.GetAllProvince();
if (ds != null && ds.Tables.Count > 0 & ds.Tables[0].Rows.Count > 0)
{
ds.Tables[0].Rows.Cast<DataRow>().ToList().ForEach(dr =>
{
int pID = 0;
int.TryParse(dr["PID"].ToString(), out pID);
if (pID > 0)
{
string url = string.Format("http://www.weather.com.cn/data/citydata/district/{0}.html", pID);
var responseText = HttpRequestOpt.SendRequestByGetMethod(url,System.Text.Encoding.UTF8);
if (!String.IsNullOrEmpty(responseText))
{
m_CityBLL.SaveCityCode(pID, responseText);
}
}
else
{
Log4NetHelp.ErrorLog("GetCode", "CreateCityCode",string.Format("存在PID<=0的数据"));
}
});
}
}
/// <summary>
/// 添加天气查询省会或地级市代码
/// </summary>
/// <param name="pID">省ID</param>
/// <param name="responseText">查询结果文本</param>
public void SaveCityCode(int pID, String responseText)
{
responseText = responseText.TrimStart('{').TrimEnd('}');
List<Weather_CityModel> list = new List<Weather_CityModel>();
responseText.Split(',').ToList().ForEach(item =>
{
Weather_CityModel cityModel = new Weather_CityModel();
if (!String.IsNullOrEmpty(item) && item.Split(':').Count() == 2 && !String.IsNullOrEmpty(item.Split(':')[0]) && !String.IsNullOrEmpty(item.Split(':')[1]))
{
cityModel.Name = item.Split(':')[1].Trim('"');
cityModel.PID = pID;
string cID = item.Split(':')[0].Trim('"');
cityModel.CID = cID;
list.Add(cityModel);
}
});
if (list.Count > 0)
{
m_CityDAL.SaveCityCode(list);
}
}
/// <summary>
/// 批量添加天气查询省会或地级市代码表
/// </summary>
/// <param name="list">省会或地级市代码表实体集</param>
public void SaveCityCode(List<Weather_CityModel> list)
{
SqlBulkCopy sqlBc = null;
DataTable dt = new DataTable();
try
{
sqlBc = new SqlBulkCopy(Common.WebConfig.WeatherDBConnString, SqlBulkCopyOptions.UseInternalTransaction);
sqlBc.DestinationTableName = "Weather_City";
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(String));
dt.Columns.Add("PID", typeof(int));
dt.Columns.Add("CID", typeof(String));
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
list.ForEach(entity =>
{
DataRow dr = dt.NewRow();
dr["Name"] = entity.Name;
dr["PID"] = entity.PID;
dr["CID"] = entity.CID;
dt.Rows.Add(dr);
});
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
}
catch (Exception ex)
{
string mayLoseData = Common.JsonHelp.SerializeJson(dt);
Common.Log4NetHelp.LoseDataLog("CityDAL", "SaveCityCode", string.Format("批量添加天气查询省会或地级市代码表异常,异常信息:{0}",ex.Message),mayLoseData);
}
finally
{
if (sqlBc != null)
{
sqlBc.Close();
}
}
}
七. 获取区或县代码数据
/// <summary>
/// 获取省会或地级市代码表所有数据
/// </summary>
/// <returns></returns>
public DataSet GetAllCity()
{
String strSql = "select * from Weather_City order by PID asc,CID asc";
return DbHelperSQL.Query(strSql);
}
/// <summary>
/// 生成天气查询区县代码表
/// </summary>
private void CreateDistrictCode()
{
m_DistrictBLL.TruncateDistrict();
DataSet ds = m_CityBLL.GetAllCity();
if (ds != null && ds.Tables.Count > 0 & ds.Tables[0].Rows.Count > 0)
{
ds.Tables[0].Rows.Cast<DataRow>().ToList().ForEach(dr =>
{
int pID = 0;
int.TryParse(dr["PID"].ToString(), out pID);
String cID = dr["CID"].ToString();
if (pID > 0&&!string.IsNullOrEmpty(cID))
{
string url = string.Format("http://www.weather.com.cn/data/citydata/city/{0}{1}.html", pID, cID);
var responseText = HttpRequestOpt.SendRequestByGetMethod(url,System.Text.Encoding.UTF8);
if (!String.IsNullOrEmpty(responseText))
{
m_DistrictBLL.SaveDistrictCode(pID,cID,responseText);
}
}
else
{
Log4NetHelp.ErrorLog("GetCode", "CreateDistrictCode", string.Format("Weather_City表存在非法数据ID={0} PID={0} CID={1}", dr["ID"].ToString(), pID.ToString(),cID));
}
});
}
}
/// <summary>
/// 添加天气查询区县代码表
/// </summary>
/// <param name="pID">省ID</param>
/// <param name="cID">省会或地区市ID</param>
/// <param name="responseText">查询结果文本</param>
public void SaveDistrictCode(int pID, String cID, String responseText)
{
responseText = responseText.TrimStart('{').TrimEnd('}');
List<Weather_DistrictModel> list = new List<Weather_DistrictModel>();
responseText.Split(',').ToList().ForEach(item =>
{
Weather_DistrictModel districtModel = new Weather_DistrictModel();
if (!String.IsNullOrEmpty(item) && item.Split(':').Count() == 2 && !String.IsNullOrEmpty(item.Split(':')[0]) && !String.IsNullOrEmpty(item.Split(':')[1]))
{
string name = item.Split(':')[1].Trim('"');
districtModel.Name = name;
districtModel.PID = pID;
districtModel.CID = cID;
var dID=item.Split(':')[0].Trim('"');
districtModel.DID = dID;
int code = 0;
//海南的DID=Code,无语啊,对比地址:
//http://www.weather.com.cn/data/citydata/city/1013101.html
//http://www.weather.com.cn/data/citydata/city/1011101.html
// 湖北荆州的沙市DID=Code
//http://www.weather.com.cn/data/citydata/city/1012008.html
if (pID == 10131 || name == "沙市")
{
code = int.Parse(dID);
}
else if (pID < 10105)
{
//注意:直辖市所属的区县市代码拼接方式与非直辖市不通
int.TryParse(String.Format("{0}{1}{2}", pID.ToString(), dID, cID), out code);
}
else
{
int.TryParse(String.Format("{0}{1}{2}", pID.ToString(), cID, dID), out code);
}
districtModel.Code = code;
list.Add(districtModel);
}
});
if (list.Count > 0)
{
m_DistrictDAL.SaveDistrictCode(list);
}
}
/// <summary>
/// 批量添加天气查询区县代码表
/// </summary>
/// <param name="list">区县码表实体集</param>
public void SaveDistrictCode(List<Weather_DistrictModel> list)
{
SqlBulkCopy sqlBc = null;
DataTable dt = new DataTable();
try
{
sqlBc = new SqlBulkCopy(Common.WebConfig.WeatherDBConnString, SqlBulkCopyOptions.UseInternalTransaction);
sqlBc.DestinationTableName = "Weather_District";
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(String));
dt.Columns.Add("PID", typeof(int));
dt.Columns.Add("CID", typeof(String));
dt.Columns.Add("DID", typeof(String));
dt.Columns.Add("Code", typeof(int));
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
list.ForEach(entity =>
{
DataRow dr = dt.NewRow();
dr["Name"] = entity.Name;
dr["PID"] = entity.PID;
dr["CID"] = entity.CID;
dr["DID"] = entity.DID;
dr["Code"] = entity.Code;
dt.Rows.Add(dr);
});
if (dt.Rows.Count > 0)
{
sqlBc.WriteToServer(dt);
dt.Clear();
}
}
catch (Exception ex)
{
string mayLoseData = Common.JsonHelp.SerializeJson(dt);
Common.Log4NetHelp.LoseDataLog("DistrictDAL", "SaveDistrictCode", string.Format("批量添加天气查询区县代码表异常,异常信息:{0}", ex.Message), mayLoseData);
}
finally
{
if (sqlBc != null)
{
sqlBc.Close();
}
}
}
八. 生成天气查询城市代码XML
/// <summary>
/// 获取直辖市、省会、地级市及区县的天气查询代码及市名称+区县名称的全称
/// </summary>
/// <returns></returns>
public DataSet GetNameCodeInfo()
{
string strSql = @"select d.Name as Name,p.Name+d.Name as FullName,d.Code as Code from Weather_District d
left join Weather_Province p on d.PID=p.PID";
return DBUtility.DbHelperSQL.Query(strSql);
}
说明:为何要全称FullName,因为存在两个城市同名的情况,例如:北京有朝阳,辽宁也有朝阳,所以通过全称来提示用户录入更准确的城市信息,如下:
private static String savePath = string.Format("{0}config/weatherConfig.xml", AppDomain.CurrentDomain.BaseDirectory);
/// <summary>
/// 生成xml文档
/// </summary>
public void CreateWeatherXML()
{
var ds = GetNameCodeInfo();
if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
XElement root = new XElement("Weather");
ds.Tables[0].Rows.Cast<DataRow>().ToList().ForEach(dr =>
{
root.Add(new XElement("City",
new XAttribute("Name", dr["Name"].ToString()),
new XAttribute("FullName", dr["FullName"].ToString()),
new XAttribute("Code", dr["Code"].ToString())
));
});
root.Save(savePath);
}
}
生成天气查询城市代码的xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<Weather>
<City Name="北京" FullName="北京北京" Code="101010100" />
<City Name="海淀" FullName="北京海淀" Code="101010200" />
<City Name="朝阳" FullName="北京朝阳" Code="101010300" />
<City Name="顺义" FullName="北京顺义" Code="101010400" />
<City Name="怀柔" FullName="北京怀柔" Code="101010500" />
<City Name="通州" FullName="北京通州" Code="101010600" />
<City Name="昌平" FullName="北京昌平" Code="101010700" />
<City Name="延庆" FullName="北京延庆" Code="101010800" />
<City Name="丰台" FullName="北京丰台" Code="101010900" />
<City Name="石景山" FullName="北京石景山" Code="101011000" />
<City Name="大兴" FullName="北京大兴" Code="101011100" />
<City Name="房山" FullName="北京房山" Code="101011200" />
<City Name="密云" FullName="北京密云" Code="101011300" />
<City Name="门头沟" FullName="北京门头沟" Code="101011400" />
未完,更多数据
九. 天气查询
/// <summary>
/// weatherConfig.xml文档
/// </summary>
private static XElement docRoot
{
get
{
try
{
string key = "WeatherBLL_docRoot";
var cache = WebCache.GetCache(key);
if (cache != null)
{
return (XElement)cache;
}
else
{
AsynReCreateCodeAndXml();
var result = XElement.Load(savePath);
WebCache.SetCache(key, result, DateTime.Now.AddDays(7));
return result;
}
}
catch
{
return XElement.Load(savePath);
}
}
}
/// <summary>
/// 天气查询
/// </summary>
/// <param name="keyWord">关键字</param>
/// <returns></returns>
public string QueryFutureWeather(String keyWord)
{
keyWord = HandleKeyWord(keyWord);
if (keyWord.Length < 2)
{
return string.Empty;
}
else
{
var queryResult = from d in docRoot.Elements("City")
where (d.Attribute("Name").Value == keyWord || d.Attribute("FullName").Value == keyWord)
select d;
if (queryResult.Count() > 1)
{
List<String> fullNames=new List<string>();
foreach(var q in queryResult)
{
fullNames.Add(q.Attribute("FullName").Value);
}
return String.Format("您要查询的是:{0},请输入上述全称之一!", string.Join("、", fullNames.ToArray()));
}
else if (queryResult.Count() == 1)
{
String code = queryResult.First().Attribute("Code").Value;
try
{
var weatherResult = RequestWeatherResult(code);
return string.Format("今日{0}天气:{1} {2},{3},{4} 洗车指数:{5}。紫外线指数:{6}。晨练指数:{7}.舒适指数:{8}。",
weatherResult.city, weatherResult.temp1, weatherResult.weather1,
weatherResult.wind1, weatherResult.index_d, weatherResult.index_xc,
weatherResult.index_uv, weatherResult.index_cl, weatherResult.index_co);
}
catch (System.Net.WebException ex)
{
Log4NetHelp.ErrorLog("WeatherBLL", "QueryFutureWeather", string.Format("查询天气异常,调用代码为为:{0}", code), ex);
return string.Format("网速繁忙,请您再次查询!");
} }
else
{
return String.Format("抱歉!暂无{0}天气信息", keyWord);
}
}
}
/// <summary>
/// 请求天气查询结果
/// </summary>
/// <param name="cityCode">城市代码</param>
/// <returns></returns>
private WeatherinfoModel RequestWeatherResult(String cityCode)
{
String key = string.Format("WeatherBLL_RequestWeatherResult_{0}", cityCode);
var cache= WebCache.GetCache(key);
if (cache != null)
{
return (WeatherinfoModel)cache;
}
else
{
String url = String.Format("http://m.weather.com.cn/data/{0}.html", cityCode);
String result = HttpRequestOpt.SendRequestByGetMethod(url,System.Text.Encoding.UTF8);
result = GetJsonContent(result);
WeatherinfoModel info = (WeatherinfoModel)JsonHelp.DeserializeJson<WeatherinfoModel>(result);
if (info != null)
{
//相同地址查询结果缓存一小时
WebCache.SetCache(key, info, 60);
}
return info;
}
}
/// <summary>
/// 获取天气查询结果里面的JSON内容
/// </summary>
/// <param name="weatherQueryResult">天气查询结果</param>
/// <returns></returns>
private String GetJsonContent(String weatherQueryResult)
{
string pattern = "{\"weatherinfo\":(.*)}";
var result = Regex.Match(weatherQueryResult,pattern,RegexOptions.IgnoreCase).Groups;
if (result.Count > 1)
{
return result[1].Value;
}
return string.Empty;
}
/// <summary>
/// 获取包含省市区县关键字的城市
/// </summary>
/// <returns></returns>
private List<String> GetExpectWords()
{
string key = "WeatherBLL_GetExpectWords";
var cache = WebCache.GetCache(key);
if (cache != null)
{
return (List<String>)cache;
}
else
{
List<String> expectionWords = new List<String>();
var ds = m_WeatherDAL.GetExpectWords();
if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
ds.Tables[0].Rows.Cast<DataRow>().ToList().ForEach(dr =>
{
expectionWords.Add(dr["Name"].ToString());
});
}
WebCache.SetCache(key,expectionWords,savePath);
return expectionWords;
}
}
/// <summary>
/// 关键字处理,忽略省市区县的关键字,如:北京市>北京
/// </summary>
/// <param name="keyWord">用户录入关键字</param>
/// <returns></returns>
private String HandleKeyWord(String keyWord)
{
List<String> expectWords = GetExpectWords();
if (expectWords.Count > 0)
{
foreach (String s in expectWords)
{
if (keyWord == s)
{
return keyWord;
}
}
}
List<String> delWords = new List<String>() { "省","市","区","县"};
delWords.ForEach(delWord =>
{
keyWord=keyWord.Replace(delWord, "");
});
return keyWord;
}
/// <summary>
/// 获取区县代码表中包含省市区县关键字的城市
/// </summary>
/// <returns></returns>
public DataSet GetExpectWords()
{
string strSql = @"select Name from Weather_District
where (Name like '%省%' or Name like '%市%' or Name like '%区%' or Name like '县')";
return DBUtility.DbHelperSQL.Query(strSql);
}
十、异步生成城市代码XML
private delegate void ReCreateCodeAndXml(); /// <summary>
/// 异步重新生成城市代码和XML信息
/// </summary>
private static void AsynReCreateCodeAndXml()
{
ReCreateCodeAndXml re = new ReCreateCodeAndXml(ReCreateCodeAndXmlInfo);
IAsyncResult asyn = re.BeginInvoke(new AsyncCallback(CompletedCal), null);
}
/// <summary>
/// 重新生成城市代码和XML信息
/// </summary>
private static void ReCreateCodeAndXmlInfo()
{
string url = string.Format("{0}CreateCodeAndXml.ashx", WebConfig.Domain);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Timeout = 120000;//两分钟
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream(),Encoding.UTF8);
var result = sr.ReadToEnd();
if (result != "success")
{
Log4NetHelp.ErrorLog("WeatherBLL", "ReCreateCodeAndXmlInfo", string.Format("重新获取省市县代码表及重新生天气xml异常,异常信息:{0}",result));
}
}
private static void CompletedCal(IAsyncResult isa)
{ }
用途:异步更新XML,第一次生成XML的时候使用同步操作,之后更新该XML使用异步,这样可减少http请求时间。
十一、示例代码
代码结构图
生成各级代码表及创建xml
天气查询
示例源码下载:【点击此处下载】
说明:调试时,接口http://m.weather.com.cn/data/101010100.html已不可用