• .Net版微信支付


    一. 案例介绍

    这里模拟一个实际业务场景,进行介绍微信支付,业务功能包括:登录、注册、充值、查看充值记录。

      

    页面图:

            

    二. 概要设计

    1.数据库设计

      这里数据库包括两张表:用户表和订单表。

      用户表: 主键id、用户名、密码、openid、注册时间

      订单表: 主键id、用户id,商品名称、订单状态(0代表下单了未支付,1代表支付成功)、商品价钱、下单时间

      

    2.微信支付流程

      这里结合该案例,来说明微信支付流程。

      该流程中涉及到4种角色,分别是微信用户、微信客户端、商户系统(自己的系统)、微信支付系统。

      流程1:

      ①用户登录微信客户端系统→②进入主页→③去支付→④生成商户系统订单→⑤调用微信统一下单API,在微信支付系统里生成预支付订单,并返回预支付订单信息→

      ⑥商户系统拿到返回的预支付订单信息,进行签名,便按照一定的格式返给微信客户端(JSAPI页面)→⑦微信客户端JSAPI页面拿到参数,请求支付,输入密码,进行支付→

      ⑧这时会进行2个并行处理→异步通知商户支付结果,商户系统接到通知后,需要修改订单的业务逻辑(该案例修改订单状态0改为1),商户系统需要告知微信系统处理结果

      →给微信客户端发送支付结果,并发微信消息提示 

      ⑨微信客户端跳转到商户H5页面,查询商户后台支付结果

      ⑩ 这时候分两种情况

        A. 商户后台系统,已经接到通知,进行了业务修改,直接返回成功。

        B. 商户后台系统,没有接到通知,这时去查询微信支付系统,如果微信支付系统成功,说明确实付款成功,只是因为网络延迟造成商户后台暂时没有接到通知,如果查询后发现未付款成功,则返回付款失败。

    微信支付业务流程图:
           

    3.代码配置

    (1).参数配置

    (2).前端页面代码

     1    $(function () {
     2             // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
     3             document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
     4                 //公众号支付
     5                 document.getElementById("pay").onclick = function () {
     6                     //1.前端验证
     7                     var money = $('#num').val();
     8                     if (money == "") {
     9                         alert('请将信息输入完整');
    10                         return;
    11                     }
    12                     mui('#pay').button('loading');
    13                     //2.进行下单
    14                     $.ajax({
    15                         type: 'POST',
    16                         url: '/WeiXinGz/GetAPI',
    17                         data: { "money": money },
    18                         cache: false,
    19                         dataType: 'json',
    20                         success: function (jsonData) {
    21                             if (jsonData.status == "1") {
    22                                 //公众号支付
    23                                 WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
    24                                     // 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
    25                                     //【因此微信团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
    26                                     //若收到通知,前端展示交易成功的界面;
    27                                     //若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
    28                                     if (res.err_msg == "get_brand_wcpay_request:ok") {
    29                                         //JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回
    30                                         $.ajax({
    31                                             type: 'POST',
    32                                             url: '/WeiXinGz/QueryOrder',
    33                                             data: {
    34                                                 orderId: jsonData.orderId
    35                                             },
    36                                             cache: false,
    37                                             dataType: 'text',
    38                                             success: function (jsonData) {
    39                                                 if (jsonData == "ok") {
    40                                                     alert("支付成功", "提示", function () {
    41                                                         alert("页面跳转等业务处理");
    42                                                     });
    43                                                     mui('#pay').button('reset');
    44                                                 } else {
    45                                                     alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付1!");
    46                                                     mui('#pay').button('reset');
    47                                                 }
    48                                             },
    49                                             error: function (XMLHttpRequest, textStatus, errorThrown) {
    50                                                 alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付2!");
    51                                                 mui('#pay').button('reset');
    52                                             }
    53                                         });
    54                                     } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
    55                                         //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
    56                                         alert("您放弃了支付");
    57                                         mui('#pay').button('reset');
    58                                     } else {
    59                                         //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
    60                                         alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付3!");
    61                                         mui('#pay').button('reset');
    62                                     }
    63                                 });
    64                             } else {
    65                                 alert(jsonData.promptInfor);
    66                                 mui('#pay').button('reset');
    67                             }
    68                         },
    69                         error: function (XMLHttpRequest, textStatus, errorThrown) {
    70                             alert("微信订单提交失败,请稍后重试4!");
    71                             mui('#pay').button('reset');
    72                         }
    73                     });
    74 
    75                 }
    76             }, false);
    77         });

    (3).统一下单接口

     1    /// <summary>
     2         /// 统一下单接口
     3         /// </summary>
     4         /// <param name="money">钱数</param>
     5         /// <returns></returns>
     6         public ActionResult GetAPI(string money)
     7         {
     8             try
     9             {
    10                 //一.系统本身自有的业务处理
    11                 //1.必要信息的初始化
    12                 string userId = Session["userId"].ToString();    //用户主键
    13                 UserInfor userInfor = db.Set<UserInfor>().Where(a => a.id == userId).FirstOrDefault();
    14                 string orderId = GenerateOrderNum(); //生成订单号
    15                 string totalFee = money;//设置默认商品费用为【1分】
    16                 string nonceStr = TenPayV3Util.GetNoncestr();   //获取 随机字符串
    17                 string openid = userInfor.openId;
    18                 //2.自己商户系统下单
    19                 OrderInfor orderInfor = new OrderInfor();
    20                 orderInfor.id = orderId;
    21                 orderInfor.uid = userInfor.id;
    22                 orderInfor.goodName = "测试商品";
    23                 orderInfor.goodPrice = totalFee;
    24                 orderInfor.addTime = DateTime.Now;
    25                 orderInfor.status = "0";  //已经下单,但未付款
    26                 db.Set<OrderInfor>().Add(orderInfor);
    27                 db.SaveChanges();
    28 
    29 
    30                 //二.微信系统下单
    31                 //1.创建支付应答对象并初始化
    32                 RequestHandler packageReqHandler = new RequestHandler(null);
    33                 packageReqHandler.Init();
    34                 //1.1设置统一下单的参数
    35                 packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId"));     //公众账号ID
    36                 packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId"));     //商户号
    37                 packageReqHandler.SetParameter("nonce_str", nonceStr);    //随机字符串
    38                 packageReqHandler.SetParameter("body", "科技-服务");    //商品描述
    39                 packageReqHandler.SetParameter("out_trade_no", orderId);     //商户订单号
    40                 packageReqHandler.SetParameter("total_fee", totalFee);     //商品金额,以分为单位
    41                 packageReqHandler.SetParameter("spbill_create_ip", Request.UserHostAddress);   //终端IP
    42                 packageReqHandler.SetParameter("notify_url", ConfigHelp.AppSettings("notify_url"));    //微信支付异步通知回调地址
    43                 packageReqHandler.SetParameter("trade_type", "JSAPI");     //交易类型 代表公众号支付
    44                 packageReqHandler.SetParameter("openid", openid);    //用户标识
    45                 string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //预支付签名
    46                 packageReqHandler.SetParameter("sign", sign);
    47                 //1.2 下单数据格式转换
    48                 string data = packageReqHandler.ParseXML();
    49                 //1.3 进行下单
    50                 string result = TenPayV3.Unifiedorder(data);
    51                 //2.对下单返回结果进行分析
    52                 XDocument res = XDocument.Parse(result);
    53                 //2.1 对返回结果进行判断
    54 
    55                 //2.2 成功的情况下获取必要的参数
    56                 string prepayId = res.Element("xml").Element("prepay_id").Value;   //获取预支付订单编号prepayId
    57                 //3. 获取支付参数并签名
    58                 string timeStamp = TenPayV3Util.GetTimestamp(); //获取时间戳
    59                 //设置支付参数
    60                 RequestHandler paySignReqHandler = new RequestHandler(null);
    61                 paySignReqHandler.SetParameter("appId", ConfigHelp.AppSettings("AppId"));
    62                 paySignReqHandler.SetParameter("timeStamp", TenPayV3Util.GetTimestamp());
    63                 paySignReqHandler.SetParameter("nonceStr", nonceStr);
    64                 paySignReqHandler.SetParameter("package", string.Format("prepay_id={0}", prepayId));
    65                 paySignReqHandler.SetParameter("signType", "MD5"); //签名【MD5】
    66                 string paySign = paySignReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key")); //JSAPI支付签名
    67                 var payData = new
    68                 {
    69                     appId = ConfigHelp.AppSettings("AppId"),
    70                     timeStamp = timeStamp,
    71                     nonceStr = nonceStr,
    72                     package = string.Format("prepay_id={0}", prepayId),
    73                     signType = "MD5",
    74                     paySign = paySign,
    75                 };
    76                 return Json(new
    77                 {
    78                     status = "1",
    79                     promptInfor = "微信下单成功",
    80                     payData = payData,
    81                     orderId = orderId
    82                 });
    83             }
    84             catch (Exception ex)
    85             {
    86                 string a = ex.Message;
    87 
    88                 return Json(new
    89                 {
    90                     status = "0",
    91                     promptInfor = a
    92                 });
    93             }
    94         }

    (4).微信异步通知接口

     1   public ActionResult PayNotifyUrl()
     2         {
     3             //获取当前http请求
     4             HttpContext httpContext = System.Web.HttpContext.Current;
     5             ResponseHandler notifyDataHandler = new ResponseHandler(httpContext);
     6             //返回状态码【SUCCESS/FAIL】此字段是通信标识
     7             string return_code = notifyDataHandler.GetParameter("return_code");
     8             //返回信息【如非空,为错误原因】
     9             string return_msg = notifyDataHandler.GetParameter("return_msg");
    10             //表示通信成功
    11             if (return_code == "SUCCESS")
    12             {
    13                 //获取业务结果【交易是否成功(SUCCESS/FAIL)】
    14                 string result_code = notifyDataHandler.GetParameter("result_code");
    15                 //表示业务结果成功
    16                 if (result_code == "SUCCESS")
    17                 {
    18                     //设置签名密钥
    19                     notifyDataHandler.SetKey(ConfigHelp.AppSettings("key"));
    20                     //验证请求是否从微信发过来(安全)【验证签名】
    21                     if (notifyDataHandler.IsTenpaySign())
    22                     {
    23                         //获取订单编号
    24                         string out_trade_no = notifyDataHandler.GetParameter("out_trade_no");
    25                         //检查是否返回商户订单号
    26                         if (!string.IsNullOrEmpty(out_trade_no))
    27                         {
    28                             try
    29                             {
    30                                 OrderInfor orderInfor = db.Set<OrderInfor>().Where(a => a.id == out_trade_no).FirstOrDefault();
    31                                 if (orderInfor != null)
    32                                 {
    33                                     //这里需要根据订单号更改系统的业务
    34                                     //这里模拟测试记录订单号
    35                                     orderInfor.status = "1"; //表示付款成功,成功回调
    36                                     db.Entry(orderInfor).State = EntityState.Modified;
    37                                     db.SaveChanges();
    38 
    39                                     return_code = "SUCCESS";
    40                                     return_msg = "OK";
    41                                 }
    42                                 else
    43                                 {
    44                                     return_code = "FAIL";
    45                                     return_msg = "商户系统中不存在该订单";
    46                                 }
    47                             }
    48                             catch (Exception ex)
    49                             {
    50                                 //系统异常
    51                                 return_code = "FAIL";
    52                                 return_msg = ex.Message;
    53                             }
    54                         }
    55                         else
    56                         {
    57                             //支付结果中商户订单号不存在
    58                             return_code = "FAIL";
    59                             return_msg = "支付结果中商户订单号不存在";
    60                         }
    61                     }
    62                     else
    63                     {
    64                         //签名失败
    65                         return_code = "FAIL";
    66                         return_msg = "签名失败";
    67                     }
    68                 }
    69                 else
    70                 {
    71                     //交易失败
    72                     return_code = "FAIL";
    73                     return_msg = "交易失败";
    74                 }
    75             }
    76             //商户处理后同步返回给微信参数
    77             string xml = string.Format(@"<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", return_code, return_msg);
    78             //返回处理结果
    79             return Content(xml, "text/xml");
    80         }

    (5).JSAPI接口请求

     1  //公众号支付
     2                                 WeixinJSBridge.invoke('getBrandWCPayRequest', jsonData.payData, function (res) {
     3                                     // 使用以下方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
     4                                     //【因此微信团队建议:】当收到ok返回时,向商户后台询问是否收到交易成功的通知,
     5                                     //若收到通知,前端展示交易成功的界面;
     6                                     //若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
     7                                     if (res.err_msg == "get_brand_wcpay_request:ok") {
     8                                         //JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回
     9                                         $.ajax({
    10                                             type: 'POST',
    11                                             url: '/WeiXinGz/QueryOrder',
    12                                             data: {
    13                                                 orderId: jsonData.orderId
    14                                             },
    15                                             cache: false,
    16                                             dataType: 'text',
    17                                             success: function (jsonData) {
    18                                                 if (jsonData == "ok") {
    19                                                     alert("支付成功", "提示", function () {
    20                                                         alert("页面跳转等业务处理");
    21                                                     });
    22                                                     mui('#pay').button('reset');
    23                                                 } else {
    24                                                     alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付1!");
    25                                                     mui('#pay').button('reset');
    26                                                 }
    27                                             },
    28                                             error: function (XMLHttpRequest, textStatus, errorThrown) {
    29                                                 alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付2!");
    30                                                 mui('#pay').button('reset');
    31                                             }
    32                                         });
    33                                     } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
    34                                         //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
    35                                         alert("您放弃了支付");
    36                                         mui('#pay').button('reset');
    37                                     } else {
    38                                         //由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
    39                                         alert("支付失败,请稍后重试!如果收到支付通知,切勿重复支付3!");
    40                                         mui('#pay').button('reset');
    41                                     }
    42                                 });
     
    (6).微信订单查询接口
     
     1  /// <summary>
     2         /// 微信订单查询接口
     3         /// </summary>
     4         /// <param name="orderId">订单编号id</param>
     5         /// <returns></returns>
     6         //[WeixinInternalRequest("无法访问!")]
     7         public ActionResult QueryOrder(string orderId)
     8         {
     9             try
    10             {
    11                 //一.先查商户后台的订单状态,判断微信端是否异步通知商户后台了!!!
    12                 OrderInfor orderInfor = db.Set<OrderInfor>().Where(a => a.id == orderId).FirstOrDefault();
    13                 //判断订单状态
    14                 if (orderInfor.status == "1")
    15                 {
    16                     //表示查询成功
    17                     return Content("ok");
    18                 }
    19                 else if (orderInfor == null || orderInfor.status != "1")
    20                 {
    21                     //二.进行调用下面的微信查询api进行查询
    22                     //生成随机字符串
    23                     string nonceStr = TenPayV3Util.GetNoncestr();
    24                     RequestHandler packageReqHandler = new RequestHandler(null);
    25                     //设置package订单参数
    26                     packageReqHandler.SetParameter("appid", ConfigHelp.AppSettings("AppId")); //公众账号ID
    27                     packageReqHandler.SetParameter("mch_id", ConfigHelp.AppSettings("MchId"));    //商户号 
    28                     packageReqHandler.SetParameter("out_trade_no", orderId);  //填入商家订单号
    29                     packageReqHandler.SetParameter("nonce_str", nonceStr); //随机字符串
    30                     string sign = packageReqHandler.CreateMd5Sign("key", ConfigHelp.AppSettings("key"));//参数进行签名
    31                     packageReqHandler.SetParameter("sign", sign); //参数中添加签名字符串                        
    32                     string data = packageReqHandler.ParseXML(); //将传的参数转化为XML格式字符串
    33                     var result = TenPayV3.OrderQuery(data); //调用订单查询接口
    34                     var res = XDocument.Parse(result);
    35                     //返回状态码【SUCCESS/FAIL】此字段是通信标识
    36                     string return_code = res.Element("xml").Element("return_code").Value;
    37                     if (return_code == "SUCCESS")
    38                     {
    39                         //获取业务结果【交易是否成功(SUCCESS/FAIL)】
    40                         string result_code = res.Element("xml").Element("result_code").Value;
    41                         if (result_code == "SUCCESS")
    42                         {
    43                             //交易状态 
    44                             /**SUCCESS—支付成功 
    45                               *REFUND—转入退款 
    46                               *NOTPAY—未支付 
    47                               *CLOSED—已关闭 
    48                               *REVOKED—已撤销(刷卡支付) 
    49                               *USERPAYING--用户支付中 
    50                               *PAYERROR--支付失败(其他原因,如银行返回失败)
    51                             */
    52                             string trade_state = res.Element("xml").Element("trade_state").Value;
    53                             if (return_code == "SUCCESS")
    54                             {
    55                                 return Content("ok");
    56                             }
    57                         }
    58                     }
    59 
    60                 }
    61                 //未查询到该订单或者该订单交易状态不相符
    62                 return Content("error");
    63             }
    64             catch (Exception ex)
    65             {
    66                 //抛异常信息,返回异常消息
    67                 return Content(ex.Message);
    68             }
    69         }
    View Code

    上述代码中,用到的openid,需要事先获取

     亲测好用,如有问题,可联系QQ 604649488
     
     
     
     
     
     
     
     
  • 相关阅读:
    【Linux】【Services】【Configuration】puppet
    【Linux】【Services】【Web】Haproxy
    【Linux】【Services】【Project】Haproxy Keepalived Postfix实现邮件网关Cluster
    【Linux】【Services】【Web】Nginx基础
    【Linux】【Services】【Project】Cobbler自动化装机
    【Linux】【Services】【Package】rpm包制作
    【Linux】【Services】【nfs】nfs安装与配置
    Bootstrap框架--DataTables列表示例--添加判断
    安全整改相关内容
    tomcat禁用PUT,DELETE等一些不必要的HTTP方法
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/6093316.html
Copyright © 2020-2023  润新知