1. 程式人生 > >訂餐系統之微信點餐

訂餐系統之微信點餐

  經過幾天的開發、測試微信點餐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("\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();
        }
    }
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介面為我家妞妞製作,妞妞辛苦了^_^】:

       

  以上就是微信點餐相關內容了,其實也就那點事兒,寫得不好,見諒,有興趣的就掃一掃吧,如果你也開發這方便的,一起交流下: