今天我们来讲一下一个非常重要的消息:GPS位置消息。
一、应用举例
基于位置的应用太多太多了,比如:
查找附近的人;
查找附近的商家;
计算与指定的人或商家的距离;
使用百度地图、腾讯地图、阿里地图的api接口,在地图上打标,实现可视化地图;
计算配送费等等等等。
二、获取微信用户位置信息方式
微信公众号可以通过两种方式获取微信用户的GPS位置,
一是普通消息方式,用户在微信app内主动向公众号发出位置信息,如下图所示:
二是微信app自动提醒微信用户是否上传位置信息,用户允许后,可以定时向公众号发送位置信息,如下图所示:
该种方式需要在微信公众号内配置接口权限(见下图),打开自动接受用户信息,可以选择每隔几分钟发送,也可以选择每次进入使用公众号时发送,具体看应用需要,粉丝量大时,发送越频繁,服务器负荷越大。
第二种方式在后续事件消息处理时详解,这里不多说。
三、微信服务器发送消息格式
用户发送的位置消息,经微信服务器处理后,形成如下XML格式发到你的服务器:
1351776360 23.134521 113.358803 20 1234567890123456
四、具体实现的源码
在接收到微信服务器发来的内容之后,首先由指定的接口网页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 System.Net;
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; //关注用户的加密后openid
string ToUserName = xn.SelectSingleNode("//ToUserName").InnerText; //公众微信号原始ID
string 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;
cmd.CommandText = "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, --推荐人openid guishu_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;
}
///
/// 计算2个点之间的距离
///
/// 点A
/// 点A
/// 点B
/// 点B
/// 公里
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;
}
///
/// 计算2个点之间的距离
///
/// 点A
/// 点A
/// 点B
/// 点B
/// 米
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;
}
}



