通过几天的开发、测试微信点餐demo终于完成了,特在此分享下,很差的地方请你们多指正下哈!一开始,就想这东西出来这么久了,网上应该有不少现成的东西,因而,baidu、google了半天,基本没发现现成的东西,也许是我搜索不得其道,也有可能你们都不肯意分享吧...因而,还得本身动手,丰衣足食!html
仍是先交代下背景:所谓“微信点餐”,其实就是用户经过微信app,关注公众号,发送指定类型的信息,如地理位置信息,网站返回相关连接到微信上,经过这些连接进入wap或者html5网站,而后开始选择商家、点餐、提交订单等。关于微信app,与订餐网站的关系,我简单的画了一个图,比较潦草,请别喷得太厉害了!如图1,说简单点:微信app经过微信服务器,传给订餐网站(申请公众号时,会输入一个地址,微信服务器就是经过此地址post,get消息的),网站根据收到的消息,返回具体信息,再经过某些信息的连接进入wap或者html5站点。微信公众平台地址:https://mp.weixin.qq.com/ ,这几天好像升级了,不叫公众号了,叫订阅号。html5
(图1)服务器
至于,如何申请、如何关注,这里就不赘述了,你懂的。要说明的是:关注后,订餐网站会收到一个用户关注的消息,网站返回一段说明文字,提示如何操做等信息,如图2:
微信
(图2)app
下面,我就把我本身设计的处理微信消息的代码介绍下吧,很差的地方,请大伙儿多给我指正指正。仍是先上一张UML模型图吧,关于依赖和关联的关系,真不怎么弄得明白,因此都有依赖的关系表示了下,这张图片不是很清晰,有兴趣的能够下载源文件看下uml.rar,见图3:微信公众平台
下面仍是简单对几个类进行说明下吧,这样你们看得明白点。ide
BaseNotice.cs,此类表示消息基类,由于每一个消息都有几个字段是相同的,如ToUserName、FromUserName、CreateTime、MsgType等,全部抽象出一个基类,此类还有一个抽象方法LoadXml,根据xml返回类的对像的实例。其余具体消息继承此类,加上本身特定的信息。post
text.cs ,此类表示文本消息类,除了有BaseNotice中有的属性外,还有一个Content,表示文本信息内容。且实现LoadXml方法,返回一个text实例,代码以下:测试
/// <summary> /// 文本消息 /// </summary> public class text : BaseNotice { /// <summary> /// 根据xml返回对像 /// </summary> /// <param name="xml"></param> /// <returns></returns> public override BaseNotice LoadXml(string xml) { text notice = new text(); //<xml> //<ToUserName><![CDATA[toUser]]></ToUserName> //<FromUserName><![CDATA[fromUser]]></FromUserName> //<CreateTime>1348831860</CreateTime> //<MsgType><![CDATA[text]]></MsgType> //<Content><![CDATA[this is a test]]></Content> //<MsgId>1234567890123456</MsgId> //</xml> System.Xml.XmlDocument d = new System.Xml.XmlDocument(); d.LoadXml(xml); System.Xml.XmlCDataSection n = d.SelectSingleNode("/xml/ToUserName").FirstChild as System.Xml.XmlCDataSection; notice.ToUserName = n.Value; n = d.SelectSingleNode("/xml/FromUserName").FirstChild as System.Xml.XmlCDataSection; notice.FromUserName = n.Value; //n = d.SelectSingleNode("/xml/CreateTime").FirstChild as System.Xml.XmlCDataSection; //notice.CreateTime = n.Value; n = d.SelectSingleNode("/xml/MsgType").FirstChild as System.Xml.XmlCDataSection; notice.MsgType = n.Value; n = d.SelectSingleNode("/xml/Content").FirstChild as System.Xml.XmlCDataSection; notice.Content = n.Value; //n = d.SelectSingleNode("/xml/MsgId").FirstChild as System.Xml.XmlCDataSection; //notice.MsgId = n.Value; return notice; } /// <summary> /// 消息内容 /// </summary> public string Content { get; set; } }
location.cs,此类表示地理位置消息类,除了有BaseNotice中有的属性外,还有Location_X(纬度),Location_Y(经度)等信息。实现代码与text.cs差很少,这里就再也不贴了。网站
BaseHandler.cs,表示处理消息的基类,定义了一个抽象方法HandleNotice,由具体处理类,去实现,代码比较简单,以下:
/// <summary> /// 处理消息基类 /// </summary> public abstract class BaseHandler { protected BaseNotice notice; public BaseHandler(BaseNotice _notice) { notice = _notice; } /// <summary> /// 处理消息,每一个子类重写此法 /// </summary> /// <returns></returns> public abstract string HandleNotice(); }
TextHandler.cs,此类表示处理文本信息的类,对用户发送的文本进行处理,而后返回相关信息。按上面的描述,发送“d”或者“订单”,返回今天的订单,其余文本,直接返回说明信息。代码以下:
/// <summary> /// 文本信息处理类 /// </summary> public class TextHandler : BaseHandler { public TextHandler(BaseNotice _notice) : base(_notice) { } /// <summary> /// 文本信息处理方法,若是文本信息 = d,返回今天订单 /// </summary> /// <returns></returns> public override string HandleNotice() { StringBuilder backmsg = new StringBuilder(); text model = (text)base.notice; backmsg.Append("<xml>"); backmsg.Append("<ToUserName><![CDATA[" + model.FromUserName + "]]></ToUserName>"); backmsg.Append("<FromUserName><![CDATA[" + model.ToUserName + "]]></FromUserName>"); backmsg.Append("<CreateTime>" + DateTime.Now.Ticks + "</CreateTime>"); string Content = ""; if (model.Content.ToLower().Trim() == "d" || model.Content.ToLower().IndexOf("订单") >= 0) { ETogoOrder dal = new ETogoOrder(); StringBuilder ordermsg = new StringBuilder(""); IList<ETogoOrderInfo> orderlist = dal.GetList(3, 1, " tempcode='" + model.ToUserName + "' and ordertime > '"+DateTime.Now.ToShortDateString()+"' ", "dataid", 1); if (orderlist.Count > 0) { ordermsg.Append("今日订单"); foreach (var item in orderlist) { ordermsg.Append("\r\n订单号:"); ordermsg.Append("\r\n" + item.OrderID); ordermsg.Append("\r\n订单时间:" + item.orderTime.ToShortTimeString()); ordermsg.Append("\r\n订单状态:" + ConfigHelper.TurnOrderState(item.State)); IList<FoodInOrderInfo> foodlist = new EOrderFood().GetAllByOrderID(item.OrderID); foreach (var food in foodlist) { ordermsg.Append("\r\n" + food.FoodName + "(" + food.FoodPrice + "x" + food.Num + ")"); } ordermsg.Append("\r\n=================="); } } else { ordermsg.Append("您今天尚未订餐点哦"); ordermsg.Append("\r\n=================="); } Content = ordermsg.ToString(); } else//其余地方返回原信息 { Content = ConfigHelper.GetConfigBackMsg(); } backmsg.Append("<Content><![CDATA[" + Content.ToString() + "]]></Content>"); backmsg.Append(" <MsgType><![CDATA[text]]></MsgType>"); backmsg.Append(" </xml> "); return backmsg.ToString(); } }
LocationHandler.cs,此类用于处理地理位置信息,和TextHandler.cs代码差很少,就是实现了HandleNotice方法。
NoticeFactory.cs,此类表示根据消息类型,返回具体处理类,用了简单工厂,每次要增长具体消息处理类,这还要加个分支,有点纠结,代码以下:
/// <summary> /// 根据消息类型,返回对像 /// </summary> public class NoticeFactory { const string AssemblyPath = "Hangjing.Weixin";//用于反射 public static BaseHandler CreateInstance(string xml) { BaseHandler handler = null; //解析数据 System.Xml.XmlDocument d = new System.Xml.XmlDocument(); d.LoadXml(xml); System.Xml.XmlCDataSection n = d.SelectSingleNode("/xml/MsgType").FirstChild as System.Xml.XmlCDataSection; HJlog.toLog("MsgType=" + n.Value); Type type = Type.GetType(string.Format(AssemblyPath + ".{0}," + AssemblyPath, n.Value.Trim()), false, true); BaseNotice noticemodel = (BaseNotice)Activator.CreateInstance(type); if (noticemodel != null) { noticemodel = noticemodel.LoadXml(xml); switch (noticemodel.MsgType) { case "text": handler = new TextHandler(noticemodel); break; case "event": handler = new EventHandler(noticemodel); break; case "location": handler = new LocationHandler(noticemodel); break; default: break; } } else { HJlog.toLog("noticemodel=mull"); } return handler; } }
weixinHelper.cs,此类封装了一些基本操做,如验证消息是否来来自微信服务器,获取微信服务器post来的消息,最主要的仍是处理消息的地方,无论添加多少消息类型,这里都不用修改,代码以下:
/// <summary> /// 根据接到的信息,返回内容 /// </summary> /// <returns></returns> public string HandleData() { string userdata = reciveData(); string backmsg = ""; BaseHandler handler = NoticeFactory.CreateInstance(userdata);//根据不一样消息类型,返回具体处理类, if (handler != null) { backmsg = handler.HandleNotice(); HJlog.toLog("handler != null " + backmsg); } else { HJlog.toLog("handler == null "); } return backmsg.ToString(); }
客户端(指在公众平台设置的那个连接)代码就相对简单了(不过判断是否网站接入的不知道是什么时间调用的),代码以下:
protected void Page_Load(object sender, EventArgs e) { weixinHelper wx = new weixinHelper(Context); if (wx.isJoin())//若是是网站接入 { Response.Write(wx.isValidRequest()); Response.End(); //HJlog.toLog("若是是网站接入"); return; } else//接收消息 { Response.Write(wx.HandleData()); //HJlog.toLog("接收消息"); Response.End(); return; } }
经过返回的连接,进入网站后,就全是html5的事儿了,第一次写,还真是用了很多时间。写得很差,代码就不贴了,上几个截图吧【html5界面为我家妞妞制做,妞妞辛苦了^_^】:
以上就是微信点餐相关内容了,其实也就那点事儿,写得很差,见谅,有兴趣的就扫一扫吧,若是你也开发这方便的,一块儿交流下: