zoukankan      html  css  js  c++  java
  • 饿了么订单--快到碗里来

    引子   

         坚持了20天,终于还是做了一个艰难的决定--把媳妇和娃送到了丈母娘家。

       前些时间,老妈有事儿回了四川,给了我和媳妇独自抚养娃的机会,我知道这将是一个巨大的挑战。

       因为一些知道的和不知道的原因,娃的湿疹比较严重,晚上老睡不踏实,得整晚拍着,哄着,实在没辙了,就得抱着睡,不然就不停的挠头呀,肚子的。。

       白天除非抱着,根本睡不了一会儿,醒了没人看着,也是有事儿没事儿挠自己。根本离不开人...看着娃身上的湿疹,以及来不及好的挠痕,心里真是奔溃的。

       还得到处寻医问诊,泡中药,涂药膏,抹茶油...官方的,民间的... 都是3个字:然并卵。

       又值搬新家,更是忙得不可开交,与媳妇在杭州奋斗了6-7年,总算是有了自己的家,只是全然没空喜悦一下,反倒时房贷的压力总记在心上。

       媳妇几度落泪,这不是矫情,一则是为自己孕期没管牢嘴,满月又吃了虾而自责;二则吃不好,睡不好,身心都是承受巨大压力,就是上个洗手间都得把娃哄睡了。

       话说回来,也是正是这短短的20天,方才对“当家才知柴米贵,养儿方知父母恩”,有了切身的感受,对父母的嘘寒问暖不再厌烦,而真正心怀感恩。这个认知与媳妇的意见终于空前的一致了 :)。

       跨出了丈母娘家门,挥手告别妻儿时,心头一紧,眼眶微酸,眼泪几乎夺眶而出...是了,这就是离别。也终于理解了,母亲每次送我出远门时,总是忍不住的哭泣。

       —————————— 生活感悟,借此叨叨,回归主题——————————

    背景

      之前写过一篇关于同步饿了么订单的文章《订餐系统之同步饿了么商家订单》,是介绍如何通过 饿了么OpenAPI 同步饿了么商家订单。此版本最大的弊端便是每次要绑定商家都需要发邮件给他们,绑定商家是一个频繁的操作,但是他们邮件处理的速度又较为缓慢,有鉴于此对接人的几乎都是望而却步,像早期的淘点点,及新开美团外卖开放平台,都是以商家登录授权方式绑定,完全是开发商与商家自助就可以完成。前些天,饿了么OpenAPI2.0 总算是千呼万唤始出来了。赶紧注册,认证。于是有了这篇文章。

    申请

      先上开放平台网址, https://open.shop.ele.me/openapi《饿了么开放平台》,  首先,你得注册成为开放者,这个过程不用截图了吧。然后 开发者资质认证,这个按要求填写相关信息,上传相关资料等他们审核了。

      

      几个工作日审核通过后,你们会看如下信息,就可开始进入下一步操作了。

      

      

    创建应用

       对接了美团后,才知道可以创建应用是多么方便一个功能,不然来一个客户,又得重新注册账号,走申请的流程,漫长而痛苦。饿了么OpenAPI2.0 可以创建多个应用,每个应用独立运行,减少了很多不必要的麻烦。

    进入开发都中心,即可开始新建应用,输入几个基本信息,应用就创建好了。

      

      

      接下来可以配置沙箱环境了,点击查看应用,进入“沙箱环境”选项卡。设置好 回调地址URL(商家授权后回调通知地址),推送URL(新订单,订单状态变化等通知地址),推送消息(选择要接收的通知类型)。配置部分到现在就结束了,接下变是上代码了。

      

    商户授权

      准备写代码之前,还是习惯性的去找下SDK,有SDK肯定会事半功倍的,只是不看不知道,一看真又感觉被默默的鄙视了一下下。提供了5种语言,都没有.net。好吧,别的咱不敢说,写代码还是会的。

      

       初略看了文档知道授权流程采用国际通用的OAuth2.0标准协议作为商户身份验证与授权协议,之前对接QQ登录,微信公从平台,流程几乎类似,轻车熟路,已经有代码修改几个配置与json对应的实体,分分钟就完成了前面4个流程,流程图如下,核心代码也贴上来了

       

    /// <summary>
            /// 授权
            /// </summary>
            /// <param name="callbackurl"></param>
            public ELEAuth(HttpContext _context)
            {
                context = _context;
                parameters = new Hashtable();
                singparameters = new Hashtable();
            }
    
            /// <summary>
            /// 返回授权url
            /// </summary>
            /// <param name="shopid"></param>
            /// <returns></returns>
            public string GetAuthURL(int shopid)
            {
                string callbackurl = appconfig.authcallbackURL;
                string OAuthurl = appconfig.authurl + "?response_type=code&client_id=" + Hangjing.EleAPIV2.appconfig.Key + "&redirect_uri=" + context.Server.UrlEncode(Hangjing.EleAPIV2.appconfig.authcallbackURL) + "&state=" + shopid + "&scope=all";
                return OAuthurl;
            }
    
            public access_tokenInfo getToken()
            {
                access_tokenInfo token = new access_tokenInfo();
    
                parameters.Add("grant_type", "authorization_code");
                parameters.Add("code", context.Request["code"]);
                parameters.Add("redirect_uri", appconfig.authcallbackURL);
                parameters.Add("client_id", appconfig.Key);
    
                string Authorization = appconfig.Key + ":" + appconfig.Secret;
                byte[] bytes = Encoding.UTF8.GetBytes(Authorization);
    
                HttpItem objHttpItem = new HttpItem()
                {
                    Authorization = "Basic " + Convert.ToBase64String(bytes),
                    URL = appconfig.tokenurl,
                    Encoding = "utf-8",
                    Method = "POST",
                    Postdata = getPostDatan()
                };
    
                HttpHelper objhttp = new HttpHelper();
                objhttp.isToLower = false;
    
    
                Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + "
    url=" + appconfig.tokenurl + "
    Authorization=" + Convert.ToBase64String(bytes));
    
                string returnmsg = objhttp.GetHtml(objHttpItem);
    
                Hangjing.AppLog.AppLog.Info("getToken:" + getPostDatan() + "
    msg=" + returnmsg + "
    Authorization=" + Convert.ToBase64String(bytes));
    
                token = JsonConvert.DeserializeObject<access_tokenInfo>(returnmsg);
                if (token != null)
                {
                    token.shopid = Convert.ToInt32(context.Request["state"]);
                }
    
                return token;
            }
    商户授权部分代码

      回调地址URL指向的地方 只要如下调用就可以了。

      ELEAuth auth = new EleAPIV2.ELEAuth(Context);
      access_tokenInfo token = auth.getToken();

      

      整个过程就一个地方要注意下:HTTP header中需要携带Authorization请求头,Basic值的算法如下(+号表示字符串连接)  base64_encode(key + ":" + secret),具体的写法在上面的代码已经有了。大伙儿稍微留意下就过了。

      话说回来,为什么是前面4个流程分分钟,独少了第五个呢,是了,第5个里面有一个计算签名的过程,几乎是第一次遇到这样的签名方式,过程较为麻烦,容易出错,之前也有几个园友也问到签名的事儿,所以这里单独拿出来。

    签名算法

       对接接口,签名总是较为麻烦的一点,相关文档如下点这里,如果想了解流程,可以自行查看。流程很长,这里就不写了,几个地方要注意的如下:

       1,签名的参数,只包含 JSON对像,metas和params 的属性。当然,params可能没有属性,忽略就可以了。

       2,使用"key=json_encode(value)"方式进行字符串拼接,这就得要求 参数的类型 要与文档里匹配,long与string  json_encode后的值是有区别的。比如  json_encode(123) = 123,而 json_encode(“123”) =“ 123”,这就直接导致用于加密的内容都不同了。

      其他的什么排序,action + token  + secret,md5等等按正常流程走就可以了,没有坑了。

      到这里,就只剩代码,签名算法代码如下:

      

    //构建签名参数,注意 timestamp 类型是 int64
    singparameters.Add("app_key", appconfig.Key);
    singparameters.Add("timestamp", Convert.ToInt64(Timestamp));
    
    
            /// <summary>
            /// 签名
            /// </summary>
            /// <returns></returns>
            public string createMD5Sign(string action, string token)
            {
                StringBuilder sb = new StringBuilder();
                ArrayList akeys = new ArrayList();
    
                foreach (var item in singparameters.Keys)
                {
                    akeys.Add(item + "=" + JsonConvert.SerializeObject(singparameters[item]) + "");
                }
                akeys.Sort();
    
                foreach (string k in akeys)
                {
                    sb.Append(k);
                }
    
                string signstep = action + token + sb.ToString() + appconfig.Secret;
    
                Hangjing.AppLog.AppLog.Info("createMD5Sign:oldsignstep=" + signstep);
    
                signstep = Utils.MD5(signstep).ToUpper();
    
                Hangjing.AppLog.AppLog.Info("createMD5Sign:signstep=" + signstep);
    
                return signstep;
            }
    签名实体,调用代码

      

      第5个流程的文档在这里,主要是获取商户信息,与系统商家对应好,我是通过state参数传系统商家编号,因为state会原样回传回来。

      计算好签名,这个流程就完成大半了,剩下注意如下:

      1, Content-Type = application/json;charset=utf-8,

      2, id 参数值为 Guid.NewGuid().ToString()

      3,post的参数要是josn 格式。参数在系统里是用 Hashtable 保存的,只要一句话就可以转成Json -- JsonConvert.SerializeObject(parameters); 

      做了以上操作,此流程80%的情况就OK了。最后上几个实际流程图

      

      

       

    接收订单参数,查询订单信息

      设置好接收推送的url,根据通知类型和内容进行相应的逻辑操作,比如收到商家确认订单通知,就把订单加入系统,订单取消通知就把系统中订单相应取消。

      完成了签名算法,其他的接口对接就是水到渠成的事儿了,根据json生成实体,替换参数,很快就可以完成其他接口了。

      接收通知代码如下,特别注意就是消息体是以流形式推送过来的。另外还有一个情况可能大家都会遇到:创建应用后,会生成测试商家,商家的商品全是1毛的,你测试几单后,饿了么会认为商家在刷单,以后提交订单就直接取消了,无法测试,后来咨询的了客服,说是商品要大于1元才不会自动取消,这样就可以测试新订单推送,商家接单推送,然后再把订单取消,支付的金额就自动退回来了,

      

     HJlog.toLog("
    ele2.0推送");
    
    
            System.IO.Stream stream = Request.InputStream;//这是你获得的流
            if (stream != null && stream.Length > 10)
            {
    
                Hangjing.AppLog.AppLog.Info("stream.Length :" + stream.Length);
                string jsondata = "";
                using (StreamReader reader = new StreamReader(stream))
                {
                    jsondata = reader.ReadToEnd(); ;
                }
    
                pushMessageInfo notice = JsonConvert.DeserializeObject<pushMessageInfo>(jsondata);
    
                switch (notice.type)
                {
                    case 14:
                    case 15:
                    case 17:
                    case 23:
                    case 25:
                    case 35:
                        ////订单取消
                        {
                            ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message);
                            string sys_orderid = "e" + pushorder.orderId;
                            new Custorder().AddOrderRecord("e" + sys_orderid, 5, "ele", "饿了么取消了订单");
    
                            string sql = "update Custorder set OrderStatus=5 where OrderID='" + sys_orderid + "';update shopeleCustorder set OrderStatus=5 where OrderID='" + sys_orderid + "'";
                            WebUtility.excutesql(sql);
    
                        }
                        break;
                    case 12: //接收订单
    
                        {
                            ordermessageinfo pushorder = JsonConvert.DeserializeObject<ordermessageinfo>(notice.message);
                            //获取token
                            taobaoAPIAcountInfo token = new taobaoAPIAcount().GetList(1, 1, "linkurl='"+notice.shopId+"'", "id", 1).FirstOrDefault();
                            if (token == null)
                            {
                                Hangjing.AppLog.AppLog.Info("商家:" + notice.shopId + "未找到授权信息,orderid=" + pushorder.orderId);
                            }
                            else
                            {
                                ELEShopV2 eleshop = new ELEShopV2(Context);
                                OrderResult rs = eleshop.getOrder(pushorder.orderId,token.pic);
    
    
    
                            }
    
                        }
    
                        break;
    
    
                    default:
                        break;
                }
    
    
    
    
    
            }
    接收推送代码

      

    上线

      对接完成后,在 设置好 正式环境 的相关参数,提交审核,至此对接就基本完成了。订单同步进入系统后,就是我们的调度系统派上用场了。通过自动调度规则,让配送员自己抢单,几乎都不用客服调度了,大家还抢的不亦乐乎。以下是某客户实时效果图。

      

      

      到此,终于实现了几个平台订单同步,总算是了了一件心事儿,还少百度外卖?直接忽略了,听商家说百度外卖半个月都不来个订单,连业务员都联系不上了。

      对接流程就完结了,希望对那些想要对接的人能有些帮助,所有流程都是亲测,绝对童叟无欺。

    结语

      又到夏天了,猛然发现大学4年,每天6点起来练出来的腹肌早已紧密的团结在了一块儿,确实做我们一行的,每天上班,加班加起的得坐10几个小时,如疏于锻炼,不出3年,基本都得长肉肉的。于是,趁着媳妇回娘家,我开始了找回腹肌计划,希望她回来时,看到一个不一样的我。【她一直想看我有8块腹肌的样子 :)】

      一,早上6:30起床,做好中午的饭,带去公司(外卖太贵了,也不是特别好吃),顺道在工商大学打30分钟篮球。去上班刚好。

      二,晚上22:30-23:00之间 从公司跑回家,全程4公里,绕一下可以有5-6公里。(再晚点,就只能骑车了)

      计划之初,内心也会抵触,反倒是执行2个月后,一切都变得自然而然,成了生活的一部分了。顺带还学会炒菜,当然了,我通常只放油盐,最多加点豆油,味道就那样了 :)。

      到现在跑5公里基本不费多少力,有时还故意再绕一圈小区。唯一麻烦的就是要背着早上带的两个饭盒,权当负重吧。下面是一张最近的跑步记录,下一步就是挑战10KM了,我的终极目前是全马(哈哈)。另外,如果你也要想跑起来,一定注意跑前热身,跑后拉伸。

      

      

      之前听别人的小密圈挺火,也下载玩了下把,创建了一个同步饿么订单的圈子,设置了付费50元加入(付费圈子最低50),抱着玩玩的心态,分享给了之前咨询饿了么接口微信好友,万万没想到,还真有几个人加入了,说是“作为支持你的分享”这也算是意外的惊喜吧,钱不多,背信任的感觉满好的。在此,也谢过几位了哈。

      

      

       成为一名优秀的程序员!

  • 相关阅读:
    为什么大多数IOC容器使用ApplicationContext,而不用BeanFactory
    重温Java泛型,带你更深入地理解它,更好的使用它!
    看完了这篇,面试的时候人人都能单手撸冒泡排序!
    JAVA基础4---序列化和反序列化深入整理(Hessian序列化)
    VS Code 变身小霸王游戏机!
    equals()方法和hashCode()方法详解
    openFeign远程调用时使用Mybatis-plus的IPage接口进行返回分页数据失败的记录
    通过express快速搭建一个node服务
    UML 类图
    jdk命令行工具系列——检视阅读
  • 原文地址:https://www.cnblogs.com/jijunjian/p/6884404.html
Copyright © 2011-2022 走看看