zoukankan      html  css  js  c++  java
  • 订餐系统之微信点餐

      经过几天的开发、测试微信点餐demo终于完成了,特在此分享下,不好的地方请大家多指正下哈!一开始,就想这东西出来这么久了,网上应该有很多现成的东西,于是,baidu、google了半天,基本没发现现成的东西,也许是我搜索不得其道,也有可能大家都不愿意分享吧...于是,还得自己动手,丰衣足食!

      还是先交代下背景:所谓“微信点餐”,其实就是用户通过微信app,关注公众号,发送指定类型的信息,如地理位置信息,网站返回相关链接到微信上,通过这些链接进入wap或者html5网站,然后开始选择商家、点餐、提交订单等。关于微信app,与订餐网站的关系,我简单的画了一个图,比较潦草,请别喷得太厉害了!如图1,说简单点:微信app通过微信服务器,传给订餐网站(申请公众号时,会输入一个地址,微信服务器就是通过此地址post,get消息的),网站根据收到的消息,返回具体信息,再通过某些信息的链接进入wap或者html5站点。微信公众平台地址:https://mp.weixin.qq.com/ ,这几天好像升级了,不叫公众号了,叫订阅号。

        

                                      (图1)

      至于,如何申请、如何关注,这里就不赘述了,你懂的。要说明的是:关注后,订餐网站会收到一个用户关注的消息,网站返回一段说明文字,提示如何操作等信息,如图2:

              

                                                     (图2)

      

      下面,我就把我自己设计的处理微信消息的代码介绍下吧,不好的地方,请大伙儿多给我指正指正。还是先上一张UML模型图吧,关于依赖和关联的关系,真不怎么弄得明白,所以都有依赖的关系表示了下,这张图片不是很清晰,有兴趣的可以下载源文件看下uml.rar,见图3:

          

      

      下面还是简单对几个类进行说明下吧,这样大家看得明白点。

      BaseNotice.cs,此类表示消息基类,因为每个消息都有几个字段是相同的,如ToUserName、FromUserName、CreateTime、MsgType等,所有抽象出一个基类,此类还有一个抽象方法LoadXml,根据xml返回类的对像的实例。其他具体消息继承此类,加上自己特定的信息。

         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;
            }
        }
    View Code

      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();
            
        }
    View Code

      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("
    订单号:");
                            ordermsg.Append("
    " + item.OrderID);
                            ordermsg.Append("
    订单时间:" + item.orderTime.ToShortTimeString());
                            ordermsg.Append("
    订单状态:" + ConfigHelper.TurnOrderState(item.State));
    
                            IList<FoodInOrderInfo> foodlist = new EOrderFood().GetAllByOrderID(item.OrderID);
                            foreach (var food in foodlist)
                            {
                                ordermsg.Append("
    " + food.FoodName + "(" + food.FoodPrice + "x" + food.Num + ")");
                            }
    
                            ordermsg.Append("
    ==================");
                        }
                       
                    }
                    else
                    {
                        ordermsg.Append("您今天还没有订餐点哦");
                        ordermsg.Append("
    ==================");
                    }
                    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();
            }
        }
    View Code

      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;
            }
        }
    View Code

     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();
            }
    View Code

      客户端(指在公众平台设置的那个链接)代码就相对简单了(不过判断是否网站接入的不知道是什么时间调用的),代码如下:

    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;
            }
    
        }
    View Code

      通过返回的链接,进入网站后,就全是html5的事儿了,第一次写,还真是用了不少时间。写得不好,代码就不贴了,上几个截图吧【html5界面为我家妞妞制作,妞妞辛苦了^_^】:

           

      以上就是微信点餐相关内容了,其实也就那点事儿,写得不好,见谅,有兴趣的就扫一扫吧,如果你也开发这方便的,一起交流下:

                            

        

  • 相关阅读:
    hdu 5115 Dire Wolf 区间DP
    泛型兼容的注意事项
    maven web项目不能创建src/main/java等文件夹的问题
    error the @annotation pointcut expression is only supported at Java 5
    HashSet重复元素判断
    oracle 分库分表(sharding)
    关系型数据库分库分表解决方案
    JDK7中匿名内部类中使用局部变量要加final,JDK8中不需要,但jdk会默认加上final
    eclipse中更改配置使得switch语句不出错
    java io流中怎么在一个文本中追加字符串
  • 原文地址:https://www.cnblogs.com/jijunjian/p/3246767.html
Copyright © 2011-2022 走看看