• .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
     
     
     
     
     
     
     
     
  • 相关阅读:
    Postgresql HStore 插件试用小结
    postgres-xl 安装与部署 【异常处理】ERROR: could not open file (null)/STDIN_***_0 for write, No such file or directory
    GPDB 5.x PSQL Quick Reference
    postgresql 数据库schema 复制
    hive 打印日志
    gp与 pg 查询进程
    jquery table 发送两次请求 解惑
    python 字符串拼接效率打脸帖
    postgresql 日期类型处理实践
    IBM Rational Rose软件下载以及全破解方法
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/6093316.html
Copyright © 2020-2023  润新知