今天我们来讲一下一个非常重要的消息:GPS位置消息。
一、应用举例
基于位置的应用太多太多了,比如:
查找附近的人;
查找附近的商家;
计算与指定的人或商家的距离;
使用百度地图、腾讯地图、阿里地图的api接口,在地图上打标,实现可视化地图;
计算配送费等等等等。
二、获取微信用户位置信息方式
微信公众号可以通过两种方式获取微信用户的GPS位置,
一是普通消息方式,用户在微信app内主动向公众号发出位置信息,如下图所示:
二是微信app自动提醒微信用户是否上传位置信息,用户允许后,可以定时向公众号发送位置信息,如下图所示:
该种方式需要在微信公众号内配置接口权限(见下图),打开自动接受用户信息,可以选择每隔几分钟发送,也可以选择每次进入使用公众号时发送,具体看应用需要,粉丝量大时,发送越频繁,服务器负荷越大。
第二种方式在后续事件消息处理时详解,这里不多说。
三、微信服务器发送消息格式
用户发送的位置消息,经微信服务器处理后,形成如下XML格式发到你的服务器:
<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>1351776360</CreateTime><MsgType><![CDATA[location]]></MsgType><Location_X>23.134521</Location_X><Location_Y>113.358803</Location_Y><Scale>20</Scale><Label><![CDATA[位置信息]]></Label><MsgId>1234567890123456</MsgId></xml>
四、具体实现的源码
在接收到微信服务器发来的内容之后,首先由指定的接口网页AccessWx.aspx对信息类型进行判别,然后交给指定的消息处理类处理和回应。在本系列文章第1篇介绍的AccessWx.aspx.cs中开始部分引入命名空间using QinMing.Weixin.MessageHandlerLocation;
并完善下面这一段,增加本篇给出的位置消息处理环节。
else if(MsgType == "location"){LocationMessageDeal tmd = new LocationMessageDeal();Response.Write(tmd.DealResult(weixinXML));}
在命名空间QinMing.Weixin.MessageHandlerLocation下新建一个类LocationMessageDeal,用来处理微信服务器发来的视频消息。记得类源码文件要放在App_Code目录下!下面是位置消息处理源码:
QinMingWeixinMessageHandlerLocation.cs文件内容如下:
using System;using System.Web;using System.Xml;using System.Text;using System.Data;using System.Data.SqlClient;using System.IO;using ;using QinMing.Config;using QinMing.Weixin.ReturnContent;//using QinMing.WeixinSendTemplateMessage;namespace QinMing.Weixin.MessageHandlerLocation{//视频消息处理public class LocationMessageDeal :System.Web.UI.Page{public string DealResult(string weixinXML){string content = DealLocation(weixinXML); return content;}public string DealLocation(string weixinXML){XmlDocument doc = new XmlDocument();doc.LoadXml(weixinXML);XmlNodeList list = doc.GetElementsByTagName("xml");XmlNode xn = list[0];string FromUserName = xn.SelectSingleNode("//FromUserName").InnerText; //关注用户的加密后openidstring ToUserName = xn.SelectSingleNode("//ToUserName").InnerText; //公众微信号原始IDstring strresponse = "";//用户通过向公众号发送位置上报地理位置信息string Latitude = xn.SelectSingleNode("//Location_X").InnerText;string Longitude = xn.SelectSingleNode("//Location_Y").InnerText;string ScaleW = xn.SelectSingleNode("//Scale").InnerText;string AddrLabel = xn.SelectSingleNode("//Label").InnerText;UpdateLocation(FromUserName, Latitude, Longitude, ScaleW, AddrLabel);ReturnMsg rm = new ReturnMsg();strresponse = rm.ReturnText(FromUserName, ToUserName, "您的位置信息已收录,后期如有变更,请重新发送位置。");//告知客服人员有微信用户更新位置消息//QinMingWeixinSendTemplateMessage SendTempMsg = new QinMingWeixinSendTemplateMessage();//SendTempMsg.SendTempMsgRemind("管理员openid", "客户发送位置消息", ""); return strresponse; }//更新微信用户表中的位置经纬度信息public void UpdateLocation(string FromUserName, string Latitude, string Longitude , string ScaleW, string AddrLabel){SqlConnection conn = new SqlConnection(QinMingConfig.DatabaseConnStr);conn.Open();SqlCommand cmd = new SqlCommand();cmd.Connection = conn;mandText = "update weixin_user_info set latitude='" + Latitude + "',longitude='" + Longitude + "',"+ "precision='" + ScaleW + "',addr_label='" + AddrLabel + "' where open_id='" + FromUserName + "'";cmd.ExecuteScalar();if (conn.State == ConnectionState.Open){conn.Close();conn.Dispose();}}}}
上段代码中用到的用户信息表weixin_user_info创建语句如下:(后面会频繁用到此表,这里先给出表结构)
CREATE TABLE weixin_user_info(open_id nvarchar(40) NULL,--公众号内微信用户唯一编码nickname nvarchar(60) NULL, --昵称sex int NULL, --性别language nvarchar(20) NULL, --语言city nvarchar(40) NULL, --城市province nvarchar(60) NULL, --省分country nvarchar(60) NULL,--乡镇headimgurl nvarchar(400) NULL,--头像图片链接unionid nvarchar(60) NULL,--公众号、小程序、网页扫码登录共用的用户唯一标识remark nvarchar(20) NULL, --备注groupid nvarchar(20) NULL,--用户所在编组subscribe_scene nvarchar(60) NULL, --关注来源qr_scene nvarchar(10) NULL, --扫码类型qr_scene_str nvarchar(100) NULL, --扫码类型描述remove_flag nvarchar(10) NULL,--是否取消关注latitude nvarchar(50) NULL, --GPS纬度longitude nvarchar(50) NULL, --GPS经度precision nvarchar(50) NULL, --GPS精度addr_label nvarchar(200) NULL,--GPS位置地址描述guishu_openid nvarchar(40) NULL, --推荐人openidguishu_mobile nvarchar(12) NULL, --推荐人手机号guishu_type nvarchar(20) NULL,--推荐来源类型join_time datetime NULL, --关注时间personal_score bigint NULL--用户积分)
五、位置信息应用举例之一:计算两个经纬度之间的米、千米数值
//获取两个GPS之间的距离,单位为米MapHelper mh1 = new MapHelper();double d1 = mh1.GetDistanceMeter(Lat1, Lon1, Lat2, Lon2);//获取两个GPS之间的距离,单位为米MapHelper mh2 = new MapHelper();double d2 = mh2.GetDistanceKilometre(Lat1, Lon1, Lat2, Lon2);
所用的MapHelper类源码如下:
public class MapHelper{private const double earth_radius = 6378.137;//地球半径private static double rad(double d){return d * Math.PI / 180.0;}/// <summary>/// 计算2个点之间的距离/// </summary>/// <param name="lat1">点A</param>/// <param name="lng1">点A</param>/// <param name="lat2">点B</param>/// <param name="lng2">点B</param>/// <returns>公里</returns>public double GetDistanceKilometre(double lat1, double lng1, double lat2, double lng2){double radLat1 = rad(lat1);double radLat2 = rad(lat2);double a = radLat1 - radLat2;double b = rad(lng1) - rad(lng2);double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));s = s * earth_radius;s = Math.Round(s * 10000) / 10000;return s;}/// <summary>/// 计算2个点之间的距离/// </summary>/// <param name="lat1">点A</param>/// <param name="lng1">点A</param>/// <param name="lat2">点B</param>/// <param name="lng2">点B</param>/// <returns>米</returns>public double GetDistanceMeter(double lat1, double lng1, double lat2, double lng2){double radLat1 = rad(lat1);double radLat2 = rad(lat2);double a = radLat1 - radLat2;double b = rad(lng1) - rad(lng2);double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));s = s * earth_radius;s = Math.Round(s * 10000) / 10;return s;}}