• 微信APP支付完整版


    关于微信支付,网上太多例子,由于步骤比较繁琐,对于小白来说坑较多,现总结一下完整流程

    1.首先要到微信开放平台创建移动应用,提交审核,通过后得到AppID和AppSecret

    2.申请开发者资质认证。

    3.申请微信支付

    申请成功会收到邮件,包含商户号wxPay_mchId和密码,用这个登录商户平台,开通APP支付,同时在商户平台->账户设置->API安全里填写的密钥得到wxPay_partnerKey

    自此需要用到的AppID,AppSecret,mchId,partnerKey,notifyUrl(后台网站地址,自己设置)都获取完成,可将其放到配置文件或数据库。下面进入正式代码:

    1.用户点击生成订单,APP将信息提交后台,后台生成完整订单返回APP,APP显示订单

     PayOrder payOrder = new PayOrder();
                payOrder.cname = cname;
                payOrder.curUmno = curUmno;
                payOrder.thisPay = Convert.ToDecimal(thispay);
                payOrder.payType = payType;
                payOrder.orderStatus = 0;
                payOrder.orderNumber=WeiXinUtil.CreateNonce();//商户后台订单号,随机生成
                payOrder.tradeType=tradeType;
                payOrder.isDelete=0;
               // payOrder.transactionId=;微信订单号支付完成后台异步填写
                
                //payOrder.payDate支付完成后台异步填写
                //payOrder.bankType支付完成后台异步填写

    2.用户点击付款,将信息提交后台,后台组件下单对象(付款信息有APP传入,配置信息从配置文件或数据库读取),至少包含以下10个参数:

                order.body
                order.appid 
                order.mch_id
                order.notify_url
                order.attach
                order.nonce_str
                order.out_trade_no
                order.total_fee
                order.spbill_create_ip
                order.trade_type

    3.获取预支付订单id:getPrepay_id :string prepayid =getPrepay_id(order, pdd.getWxKey("wxPay_partnerKey"));//(wxPay_partnerKe重数据库或配置文件获取)

     ///


            /// 获取prepay_id
            ///

            public string getPrepay_id(Order order, string key)
            {
                string prepay_id = "";
                string post_data = getUnifiedOrderXML(order, key);
                string request_data = WeiXinUtil.PostXmlToUrl("https://api.mch.weixin.qq.com/pay/unifiedorder", post_data);
                SortedDictionary requestXML = WeiXinUtil.GetInfoFromXml(request_data);
                foreach (KeyValuePair k in requestXML)
                {
                    if (k.Key == "prepay_id")
                    {
                        prepay_id = k.Value;
                        break;
                    }
                }
                return prepay_id;
            }

     //获取统一下单数据
            public static string getUnifiedOrderXML(Order order, string key)
            {
                string return_string = string.Empty;
     
                Dictionary sParams = new Dictionary();
                sParams.Add("appid", order.appid);
                sParams.Add("attach", order.attach);
                sParams.Add("body", order.body);
                sParams.Add("mch_id", order.mch_id);
                sParams.Add("nonce_str", order.nonce_str);
                sParams.Add("notify_url", order.notify_url);
                sParams.Add("out_trade_no", order.out_trade_no);
                sParams.Add("spbill_create_ip", order.spbill_create_ip);
                sParams.Add("total_fee", order.total_fee.ToString());
                sParams.Add("trade_type", order.trade_type);
                order.sign = CreateSign(sParams, key);
                sParams.Add("sign", order.sign);
     
                //拼接成XML请求数据
                StringBuilder sbPay = new StringBuilder();
                foreach (KeyValuePair k in sParams)
                {
                    if (k.Key == "attach" || k.Key == "body" || k.Key == "sign")
                    {
                        sbPay.Append("<" + k.Key + ">");
                    }
                    else
                    {
                        sbPay.Append("<" + k.Key + ">" + k.Value + "");
                    }
                }
                return_string = string.Format("{0}", sbPay.ToString());
                byte[] byteArray = Encoding.UTF8.GetBytes(return_string);
                return_string = Encoding.GetEncoding("UTF-8").GetString(byteArray);
           
                return return_string;
     
            }

    ///


            /// post数据到指定接口并返回数据
            ///

            public static string PostXmlToUrl(string url, string postData)
            {
                string returnmsg = "";
                using (System.Net.WebClient wc = new System.Net.WebClient())
                {
                    wc.Encoding = System.Text.Encoding.UTF8;
                    returnmsg = wc.UploadString(url, "POST", postData);
                }
                return returnmsg;
            }

     ///


            /// 把XML数据转换为SortedDictionary集合
            ///

            ///
            ///
            public static SortedDictionary GetInfoFromXml(string xmlstring)
            {
                SortedDictionary sParams = new SortedDictionary();
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(xmlstring);
                    XmlElement root = doc.DocumentElement;
                    int len = root.ChildNodes.Count;
                    for (int i = 0; i < len; i++)
                    {
                        string name = root.ChildNodes[i].Name;
                        if (!sParams.ContainsKey(name))
                        {
                            sParams.Add(name.Trim(), root.ChildNodes[i].InnerText.Trim());
                        }
                    }
                }
                catch { }
                return sParams;
            }

    //获取时间戳
            public static string GetTimeStamp()
            {
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                return Convert.ToInt64(ts.TotalSeconds).ToString();
            }
            //创建随机字符串32位
            public static string CreateNonce()
            {
                char[] constant = new char[]{   
                    '0','1','2','3','4','5','6','7','8','9'
                };
                StringBuilder newRandom = new StringBuilder(constant.Length);
                Random rd = new Random(Guid.NewGuid().GetHashCode());
                for (int i = 0; i < 16; i++)
                {
                    newRandom.Append(constant[rd.Next(constant.Length)]);
                }
                return newRandom.ToString();
            }
            //md5加密
            public static string MD5(string data)
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
                bytes = md5.ComputeHash(bytes);
                md5.Clear();
                string s = string.Empty;
                for (int i = 0; i < bytes.Length; i++)
                {
                    s += Convert.ToString(bytes[i], 16).PadLeft(2, '0');
                }
                return s.PadLeft(32, '0');
            }
             ///


        /// Builds the return XML.
        ///

        /// The code.
        /// The return MSG.
        ///
        public static string BuildReturnXml(string code, string returnMsg)
        {
            return "";
        }

    4.//获取到prepayid,在APP调起模块进行支付

    交易完成后,异步后台处理(交易完成后回调地址会接收到微信异步通知,后台收到通知,需给微信回确认信息,否则微信会通知多次,异步通知的作用是确认订单缴费成功,不能有前台确认,为防止假冒信息只能后台确认,后台确认成功后才可以处理业务逻辑,比如发送短信通知等。)

    public class NotifyHandlewx : IHttpHandler, IRequiresSessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            Para_Comm CurMsg = new Para_Comm();
            var request = context.Request;
            var requestXml = WeiXinUtil.GetRequestXmlData(request);
            var dic = WeiXinUtil.FromXml(requestXml);
            var returnCode = WeiXinUtil.GetValueFromDic(dic, "return_code");
            pay_dictionaryDAL pdd=new pay_dictionaryDAL();
            var key = pdd.getInfoByPayCode("wxKey");
            var appid = pdd.getInfoByPayCode("wxAppId");
            var mchid=pdd.getInfoByPayCode("wxTenamtNo");
            var ReturnXml="";
            if (!string.IsNullOrEmpty(returnCode) && returnCode == "SUCCESS")//通讯成功
            {
                var result = WeiXinUtil.WePayNotifyValidation(dic, key);
                if (result)
                {
                    var transactionid = WeiXinUtil.GetValueFromDic(dic, "transaction_id");

                    if (!string.IsNullOrEmpty(transactionid))
                    {
                        //对数据表payOrder加锁
                        //查询业务状态,如果已经处理直接返回成功
                        PayOrderDAL pd = new PayOrderDAL();
                        bool handleStatus = pd.SearchStatus(transactionid);
                        if (handleStatus)
                        {
                            ReturnXml = WeiXinUtil.BuildReturnXml("SUCCESS", "OK");
                            context.Response.Write(ReturnXml);
                            return;
                        }
                        var queryXml = WeiXinUtil.BuildQueryRequest(transactionid, dic, key, appid, mchid);
                        var queryResult = WeiXinUtil.PostXmlToUrl("https://api.mch.weixin.qq.com/pay/orderquery", queryXml);
                        var queryReturnDic = WeiXinUtil.GetInfoFromXml(queryResult);

                        if (WeiXinUtil.ValidatonQueryResult(queryReturnDic))//查询成功
                        {
                           
                            var status = WeiXinUtil.GetValueFromDic(dic, "result_code");

                            if (!string.IsNullOrEmpty(status) && status == "SUCCESS")
                            {
                                //根据订单编号更新订单状态
                                string OrderNumber = WeiXinUtil.GetValueFromDic(dic, "out_trade_no");
                                string PayDate = WeiXinUtil.GetValueFromDic(dic, "time_end");
                                string BankType = WeiXinUtil.GetValueFromDic(dic, "bank_type");
                                PayOrderDAL payOrderDAL = new PayOrderDAL();
                                if(payOrderDAL.updateOrderStatus(1, transactionid, PayDate, BankType, OrderNumber)){
                                    Task task = new Task(() => {
                                        List list=payOrderDAL.GetListByOrderNumber(OrderNumber,1);
                                        if(null==list){
                                            CurMsg.success=false;
                                        }
                                        else
                                        {
                                            string curUmno = list[0].curUmno;
                                            long umno = Convert.ToInt32(curUmno.Substring(2, 8));
                                            Advances advances = new Advances();
                                            advances.umno = umno;
                                            ut_umrelateDAL ud = new ut_umrelateDAL();
                                            Object obj=ud.serchCidByUmno(umno);
                                            if (null != obj)
                                            {
                                                advances.CustID = Convert.ToInt32(obj);
                                            }
                                            else
                                            {
                                                advances.CustID = 0;
                                            }
                                            advances.AdminID = "wx";
                                            advances.debt = list[0].remain;
                                            advances.PayMoney = list[0].thisPay;
                                            advances.sumpay = list[0].sumMoney;
                                            int lastbuyno = 0;
                                            Para_Comm CurMsg1 = new Para_Comm();
                                            AdvancesBLL.getLastsumpayByUmno(out CurMsg1, umno);
                                            if(CurMsg1.success){
                                                string[] sArray = CurMsg1.rcvdata.Split(':');
                                                lastbuyno = Convert.ToInt32(sArray[1]);
                                            }
                                            advances.buyno = lastbuyno + 1;
                                            advances.remark = "微信收费";
                                            AdvancesBLL.Save_Advances(out CurMsg, advances, "insert");
                                            //充值成功了,发送短信给客户
                                        }
                                     });
                                    task.Start();
                                }
                              ReturnXml = WeiXinUtil.BuildReturnXml("SUCCESS", "OK");
                            }
                        }
                        else
                            ReturnXml=WeiXinUtil.BuildReturnXml("FAIL", "订单查询失败");
                    }
                    else
                        ReturnXml=WeiXinUtil.BuildReturnXml("FAIL", "支付结果中微信订单号不存在");
                }
                else
                    ReturnXml=WeiXinUtil.BuildReturnXml("FAIL", "签名失败");
            }
            else
            {
                string returnmsg;
                dic.TryGetValue("return_msg", out returnmsg);
                throw new Exception("异步通知错误:" + returnmsg);
            }
            context.Response.Write(ReturnXml);
        }

    5.支付交易完成,需到微信后台查询实际支付结果

    public bool searchResult(string orderNumber)
            {
                pay_dictionaryDAL pdd = new pay_dictionaryDAL();
                string key = pdd.getInfoByPayCode("wxKey");
                string appid = pdd.getInfoByPayCode("wxAppId");
                string mchid = pdd.getInfoByPayCode("wxTenamtNo");
                string queryXml = WeiXinUtil.BuildQueryRequestByOrderNumber(orderNumber, key, appid, mchid);
                string queryResult = WeiXinUtil.PostXmlToUrl("https://api.mch.weixin.qq.com/pay/orderquery", queryXml);
                SortedDictionary queryReturnDic = WeiXinUtil.GetInfoFromXml(queryResult);
                if (WeiXinUtil.ValidatonQueryResult(queryReturnDic))//查询成功
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

     public static string BuildQueryRequestByOrderNumber(string orderNumber, string key, string appid, string mchid)
            {
                var dicParam = CreateQueryParamByOrderNumber(orderNumber, appid, mchid);
                var signString = CreateURLParamString(dicParam);
                var preString = signString + "&key=" + key;
                var sign = Sign(preString, "utf-8").ToUpper();
                dicParam.Add("sign", sign);

                return BuildForm(dicParam);
            }

    ///


            /// Creates the query parameter.
            ///

            /// The transaction identifier.
            ///
            private static SortedDictionary CreateQueryParam(string transactionId,string appid,string mchid)
            {
                var dic = new SortedDictionary
            {
                {"appid", appid},//公众账号ID
                {"mch_id", mchid},//商户号
                {"nonce_str", Guid.NewGuid().ToString().Replace("-", "")},//随机字符串
                {"transaction_id", transactionId}//微信订单号
            };
                return dic;
            }
            ///
            /// Creates the query parameter.
            ///

            /// The transaction identifier.
            ///
            private static SortedDictionary CreateQueryParamByOrderNumber(string orderNumber, string appid, string mchid)
            {
                var dic = new SortedDictionary
            {
                {"appid", appid},//公众账号ID
                {"mch_id", mchid},//商户号
                {"nonce_str", Guid.NewGuid().ToString().Replace("-", "")},//随机字符串
                {"out_trade_no", orderNumber}//微信订单号
            };
                return dic;
            }

    6.返回支付结果,显示

  • 相关阅读:
    nginx根据request_uri进行转发
    gradle编译spring源码过程问题整理
    论文阅读--Energy efficiency in heterogeneous wireless access networks
    MATLAB中zp2tf函数用法
    女朋友让我深夜十二点催她睡觉,我有Python我就不干
    从Spring源码探究IOC初始化流程
    探索Web3:去中心化的互联网新时代
    数据库概论-MySQL的数据表的基本操作
    【含面试】解锁MySQL group_concat的无限可能性:解决长度限制并实现高效查询
    【接口自动化测试】第一节.接口自动化测试基础和框架介绍
  • 原文地址:https://blog.csdn.net/banshurenliyaping/article/details/84983684