zoukankan      html  css  js  c++  java
  • C# 微信支付教程系列之扫码支付

    微信支付教程系列之扫码支付

      
            今天,我们来一起探讨一下这个微信扫码支付。何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添加好友的时候,可以通过输入对方的微信号,也可以扫一扫对方的二维码。扫码支付,作为,微信支付里面,不可或缺的一个功能,对商品的支付提供了极为方便的体验,用途也非常的多。例如我们在地铁、公交站常见的那些自动售货机(不错,就是那种投硬币,就可以自动出货的那种机器)中都用到。以前,那种机器,只能通过投硬币或者纸币,但是,这里面也有一定的风险,例如:假币,盗窃(真有人把机器砸了,把机器里面的钱偷走的),所以,微信(支付宝)的扫码支付的出现,大大的减少了这方面的风险,近些年来,二维码的应用越来越广,甚至有些地方,直接用来自动售票(就是把起始点设定好,票价设定好,直接把二维码贴出来,让乘客自动扫相关的二维码,完成购票,上车的时候,只需要提供自己的支付凭证给乘车员验证即可),这样,不仅绿色环保了,还大大的提高了售票的速度(去过大车站购票的人应该深有体验,排队买个票,好歹半个小时以上,心里也是万头草泥马在奔腾的)。
            
            咱就不扯远了,说回咱么今天要做的微信支付之扫码支付。微信官方的文档,这个扫码支付(NativePay)分为两种,一种是“生成扫描支付模式”,另外一种是“生成直接支付url,支付url有效期为2小时”,至于这里面,两种扫码模式,怎么灵活利用呢,官方也没有一个明确的说明。个人理解为,第一种(生成扫描支付模式),适用于固定二维码的,就是永久使用的那种,例如一些商家的公众号的二维码,是永久的,什么时候扫,都是关注这个公众号的,但是,这种的话,我记得微信是有限量的,貌似是一个公众号,限量10w,个人观点,觉得这个限量,是足够我们使用的。第二种(生成直接支付url,支付url有效期为2小时),这种的话,因为有有效期这种时间限制,超过了2个小时,该二维码就失效,但是对生成的二维码数量没有限制,所以,这种个人观点觉得适用于那种临时根据实际情况生成的二维码,例如:公众平台登陆的时候二次验证的二维码,自定义生成,仅为一次性缴费使用的二维码,等等)。接下来,我们就开始讲讲实际例子,首先将的就是第一种模式。
     
                       扫码支付之模式一生成扫描支付模式
       首先,我们新建一个“MVC”的项目(asp.net的官方的demo就是了,要asp.net的自己看demo吧,demo地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1),然后把系统自动生成的HomeControler和View中的Home都删了。
     
            然后自己新建一个HomeControler,代码如下:
    1  // GET: Home
    2         public ActionResult Index()
    3         {
    4             return View();
    5         } 

      再添加一个View,代码如下:

     1 @{
     2     Layout = null;
     3 }
     4 <!DOCTYPE html>
     5 <html>
     6 <head>
     7     <meta name="viewport" content="width=device-width" />
     8     <title>首页</title>
     9 </head>
    10 <body>
    11     <div> 
    12     </div>
    13 </body>
    14 </html>

    接下来,我们先把官方的demo的一些我们会用到的东西拷贝过来,其中包括以下几个文件夹,如下图:

    就这个lib和business两个,把这两个文件夹,支付复制到咱们的新项目中,并且包含在项目中,如下:

    然后我们再“重新生成”以下项目,或者快捷键:ctrl+shift+b,这时候,会提下如下错误:

    这时候,我们去添加引用,把lib文件夹中的LitJson.dll 添加上即可,如下图:

    到这里,我们就基本把官方的demo的环境给搭建好了,接下来,我们就要开始编写代码了。
     
            首先,我的逻辑是,从前到后,就是从前端到后端。前端是显示二维码的地方,那么我们就先给他一个div(本文使用到的是jquery的二维码生成插件,全名叫:jquery.qrcode.min.js,我会传到附件上),然后在页面加载完毕的时候,会请求后台,让他返回二维码字符串,然后再通过jquery的二维码生成插件,让他生成二维码并显示在前台,代码如下:
     
    前端:
     1 @{
     2     Layout = null;
     3 }
     4 <!DOCTYPE html>
     5 <html>
     6 <head>
     7     <meta name="viewport" content="width=device-width" />
     8     <title>首页</title>
     9     <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" />
    10     <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" />
    11     <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" />
    12 </head>
    13 <body>
    14     <p>
    15         模式一:生成扫描支付模式
    16         <br />
    17         <div id="QRCode1">
    18         </div>
    19     </p>
    20     <p>
    21         模式二:生成直接支付url,支付url有效期为2小时
    22         <br />
    23         <div id="QRCode2">
    24         </div>
    25     </p>
    26     <script src="~/Scripts/jquery-1.10.2.js"></script>
    27     <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script>
    28     <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script>
    29     <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script>
    30     <script src="~/Scripts/jquery.qrcode.min.js"></script>
    31     <script type="text/javascript">
    32         $(function () {
    33             fGetQRCode1();
    34         })
    35         function fGetQRCode1() {
    36             $.messager.progress({
    37                 title: "",
    38                 msg: "正在生成二维码:模式一,请稍后..."
    39             });
    40             $.ajax({
    41                 type: "post",
    42                 url: "/Home/GetQRCode1",
    43                 data: {
    44                     time: new Date(),
    45                     productId:7788
    46                 },
    47                 success: function (json) {
    48                     $.messager.progress('close');//记得关闭
    49                     if (json.result) {
    50                         $('#QRCode1').qrcode(json.str); //生成二维码
    51                     }
    52                     else {
    53                         $('#QRCode1').html("二维码生成失败");
    54                     }
    55                 }
    56             })
    57         }
    58     </script>
    59 </body>
    60 </html>

    后端:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Mvc;
     6 using WxPayAPI;
     7 namespace WxPay.Controllers
     8 {
     9     public class HomeController : Controller
    10     {
    11         // GET: Home
    12         public ActionResult Index()
    13         {
    14             return View();
    15         }
    16         /// <summary>
    17         /// 模式一
    18         /// </summary>
    19         /// <returns></returns>
    20         [HttpPost]
    21         public ActionResult GetQRCode1()
    22         {
    23             object objResult = "";
    24             string strProductID = Request.Form["productId"];
    25             string strQRCodeStr = GetPrePayUrl(strProductID);
    26             if (!string.IsNullOrWhiteSpace(strProductID))
    27             {
    28                 objResult = new { result = true, str = strQRCodeStr };
    29             }
    30             else
    31             {
    32                 objResult = new { result = false };
    33             }
    34             return Json(objResult);
    35         }
    36         /**
    37         * 生成扫描支付模式一URL
    38         * @param productId 商品ID
    39         * @return 模式一URL
    40         */
    41         public string GetPrePayUrl(string productId)
    42         {
    43             WxPayData data = new WxPayData();
    44             data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
    45             data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
    46             data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
    47             data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
    48             data.SetValue("product_id", productId);//商品ID
    49             data.SetValue("sign", data.MakeSign());//签名
    50             string str = ToUrlParams(data.GetValues());//转换为URL串
    51             string url = "weixin://wxpay/bizpayurl?" + str;
    52             return url;
    53         }
    54         /**
    55        * 参数数组转换为url格式
    56        * @param map 参数名与参数值的映射表
    57        * @return URL字符串
    58        */
    59         private string ToUrlParams(SortedDictionary<string, object> map)
    60         {
    61             string buff = "";
    62             foreach (KeyValuePair<string, object> pair in map)
    63             {
    64                 buff += pair.Key + "=" + pair.Value + "&";
    65             }
    66             buff = buff.Trim('&');
    67             return buff;
    68         }
    69     }
    70 }
    这时候,模式一是不是感觉就完成了?那么我们现在试试,我们浏览该页面,如下:
     
    然后用微信扫一扫功能扫一下,发现提示如下:
     
    这是什么鬼,是不是,你心里面是不是想知道为啥,那我来告诉你,这是为啥,这是因为,你还没有设置回调页面或者回调页面有问题,这个时候,我们再新建一个Control,命名为:NativeNotifyController.cs,代码如下:
      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Web;
      6 using System.Web.Mvc;
      7 using WxPayAPI;
      8 namespace WxPay.Controllers
      9 {
     10     public class NativeNotifyController : Controller
     11     {
     12         // GET: NativeNotify
     13         public ActionResult Index()
     14         {
     15             string strData = ProcessNotify();
     16             Response.Write(strData);
     17             return View();
     18         }
     19         public string ProcessNotify()
     20         {
     21             WxPayData notifyData = GetNotifyData();
     22             //检查openid和product_id是否返回
     23             if (!notifyData.IsSet("openid") || !notifyData.IsSet("product_id"))
     24             {
     25                 WxPayData res = new WxPayData();
     26                 res.SetValue("return_code", "FAIL");
     27                 res.SetValue("return_msg", "回调数据异常");
     28                 return res.ToXml();
     29             }
     30             //调统一下单接口,获得下单结果
     31             string openid = notifyData.GetValue("openid").ToString();
     32             string product_id = notifyData.GetValue("product_id").ToString();
     33             WxPayData unifiedOrderResult = new WxPayData();
     34             try
     35             {
     36                 unifiedOrderResult = UnifiedOrder(openid, product_id);
     37             }
     38             catch (Exception ex)//若在调统一下单接口时抛异常,立即返回结果给微信支付后台
     39             {
     40                 WxPayData res = new WxPayData();
     41                 res.SetValue("return_code", "FAIL");
     42                 res.SetValue("return_msg", "统一下单失败");
     43                 return res.ToXml();
     44             }
     45             //若下单失败,则立即返回结果给微信支付后台
     46             if (!unifiedOrderResult.IsSet("appid") || !unifiedOrderResult.IsSet("mch_id") || !unifiedOrderResult.IsSet("prepay_id"))
     47             {
     48                 WxPayData res = new WxPayData();
     49                 res.SetValue("return_code", "FAIL");
     50                 res.SetValue("return_msg", "统一下单失败");
     51                 return res.ToXml();
     52             }
     53             //统一下单成功,则返回成功结果给微信支付后台
     54             WxPayData data = new WxPayData();
     55             data.SetValue("return_code", "SUCCESS");
     56             data.SetValue("return_msg", "OK");
     57             data.SetValue("appid", WxPayConfig.APPID);
     58             data.SetValue("mch_id", WxPayConfig.MCHID);
     59             data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());
     60             data.SetValue("prepay_id", unifiedOrderResult.GetValue("prepay_id"));
     61             data.SetValue("result_code", "SUCCESS");
     62             data.SetValue("err_code_des", "OK");
     63             data.SetValue("sign", data.MakeSign());
     64             return data.ToXml();
     65         }
     66         /// <summary>
     67         /// 接收从微信支付后台发送过来的数据并验证签名
     68         /// </summary>
     69         /// <returns>微信支付后台返回的数据</returns>
     70         public WxPayData GetNotifyData()
     71         {
     72             //接收从微信后台POST过来的数据
     73             System.IO.Stream s = Request.InputStream;
     74             int count = 0;
     75             byte[] buffer = new byte[1024];
     76             StringBuilder builder = new StringBuilder();
     77             while ((count = s.Read(buffer, 0, 1024)) > 0)
     78             {
     79                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
     80             }
     81             s.Flush();
     82             s.Close();
     83             s.Dispose();
     84             //转换数据格式并验证签名
     85             WxPayData data = new WxPayData();
     86             try
     87             {
     88                 data.FromXml(builder.ToString());
     89             }
     90             catch (WxPayException ex)
     91             {
     92                 //若签名错误,则立即返回结果给微信支付后台
     93                 WxPayData res = new WxPayData();
     94                 res.SetValue("return_code", "FAIL");
     95                 res.SetValue("return_msg", ex.Message);
     96             }
     97             return data;
     98         }
     99         private WxPayData UnifiedOrder(string openId, string productId)
    100         {
    101             //统一下单
    102             WxPayData req = new WxPayData();
    103             req.SetValue("body", "广东XXXX股份有限公司");
    104             req.SetValue("attach", "附加信息,用于后台或者存入数据库,做自己的判断");
    105             req.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());
    106             req.SetValue("total_fee", 1);
    107             req.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
    108             req.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
    109             req.SetValue("goods_tag", "商品的备忘,可以自定义");
    110             req.SetValue("trade_type", "NATIVE");
    111             req.SetValue("openid", openId);
    112             req.SetValue("product_id", productId);
    113             WxPayData result = WxPayApi.UnifiedOrder(req);
    114             return result;
    115         }
    116     }
    117 }

    记得,也要新建一个View,就是在Index那里,右键添加一个View,View的代码如下(你没眼花,就是空的,不管他):

     1 @{
     2     Layout = null;
     3 }
     4 <!DOCTYPE html>
     5 <html>
     6 <head>
     7     <meta name="viewport" content="width=device-width" />
     8     <title>Index</title>
     9 </head>
    10 <body>
    11     <div> 
    12     </div>
    13 </body>
    14 </html>


    接着,把这个项目,发布出来,放到服务器的iis上,这里面,我把他发布在http://sm.lmx.ren/上面(必须要发布到网上哈,如果不懂发布的,你可以自己去学习基础知识先了),这还没完,还需要把到公众平台上,设置回调页面,操作如下:

     
     
    这样,就大功告成了。这时候,我们再试试扫码,发现已经得到以下提示了,这样子,就代表,我们的模式一,已经成功完成了。如下图:
     
     
            这时候,细心的朋友就会提问了,我这都支付成功了,怎么页面没啥提示呀,这页面不交互很不友好啊。嗯,没错,童鞋,你有前途,现在我就告诉你,怎么做交互,但是,为了你日后更加有前途,我只告诉你逻辑,具体怎么实现,自己来想,多动脑。
     
           那么逻辑是怎么的呢?常规逻辑下,我们微信扫页面上的这个二维码的时候,这个时候,他已经把我们二维码里面的参数,传到微信服务器,然后有他们开始统一下单(如果对逻辑不清晰,可以看看官方的文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3):他们在统一下单的时候,就会生成一个product_id,这个家伙的作用呢 ,就是告诉你现在微信服务器,已经生成了一个单号,劳资已经收到你的支付请求了,赶紧给老子付款,O(∩_∩)O哈哈~。。。停,停,停。这时候,思路不能继续往下走了。记得,前面有个叫做“统一下单“,那既然有这个步骤,那我们可以利用一下,就是当他统一下单成功的时候,我们可以在页面更新一下状态,告诉客户:您已成功扫描,并下单成功,请支付。是不是,我们可以提示他们这个。然后等用户在手机上,支付成功的时候,这个时候,页面是不是也要反馈给用户,告诉他,小子,你的钱已经到我的口袋了,你可以走了(你走,我没有你这样的宝宝)。O(∩_∩)O哈哈~,但是,你还要停,停住,停下来。我们服务公司怎么知道这个微信用户已经付款成功了呢?来,我们把视线回到代码上,找到lib/Config.cs,如下图:
     
    然后打开config.cs,找到以下代码:
     
    对了,你很聪明。微信的处理逻辑就是,等用户支付成功之后,他会给这个链接发送支付结果,默认是以前那个aspx的页面,现在我换成mvc,所以,我们得手动新建一个control了,命名为:ResultNotifyController,然后代码如下:
      1 using LmxPublic.Log;
      2 using System;
      3 using System.Collections.Generic;
      4 using System.Linq;
      5 using System.Text;
      6 using System.Web;
      7 using System.Web.Mvc;
      8 using WxPayAPI;
      9 namespace WxPay.Controllers
     10 {
     11     public class ResultNotifyController : Controller
     12     {
     13         // GET: ResultNotify
     14         public ActionResult Index()
     15         {
     16             string strData = ProcessNotify();
     17             Response.Write(strData);
     18             return View();
     19         }
     20         public string ProcessNotify()
     21         {
     22             WxPayData notifyData = GetNotifyData();
     23             //检查支付结果中transaction_id是否存在
     24             if (!notifyData.IsSet("transaction_id"))
     25             {
     26                 //若transaction_id不存在,则立即返回结果给微信支付后台
     27                 WxPayData res = new WxPayData();
     28                 res.SetValue("return_code", "FAIL");
     29                 res.SetValue("return_msg", "支付结果中微信订单号不存在");
     30                 return res.ToXml();
     31             }
     32             string transaction_id = notifyData.GetValue("transaction_id").ToString();
     33             //查询订单,判断订单真实性
     34             if (!QueryOrder(transaction_id))
     35             {
     36                 //若订单查询失败,则立即返回结果给微信支付后台
     37                 WxPayData res = new WxPayData();
     38                 res.SetValue("return_code", "FAIL");
     39                 res.SetValue("return_msg", "订单查询失败");
     40                 return res.ToXml();
     41             }
     42             //查询订单成功
     43             else
     44             {
     45                 WxPayData res = new WxPayData();
     46                 res.SetValue("return_code", "SUCCESS");
     47                 res.SetValue("return_msg", "OK");
     48                 Log.Info(this.GetType().ToString(), "order query success : " + res.ToXml());
     49                 string strXml = res.ToXml();
     50                 FileLog.WriteLog(strXml);
     51                 return res.ToXml();//如果我们走到这一步了,那就代表,用户已经支付成功了,所以,该干嘛干嘛了。
     52             }
     53         }
     54         /// <summary>
     55         /// 接收从微信支付后台发送过来的数据并验证签名
     56         /// </summary>
     57         /// <returns>微信支付后台返回的数据</returns>
     58         public WxPayData GetNotifyData()
     59         {
     60             //接收从微信后台POST过来的数据
     61             System.IO.Stream s = Request.InputStream;
     62             int count = 0;
     63             byte[] buffer = new byte[1024];
     64             StringBuilder builder = new StringBuilder();
     65             while ((count = s.Read(buffer, 0, 1024)) > 0)
     66             {
     67                 builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
     68             }
     69             s.Flush();
     70             s.Close();
     71             s.Dispose();
     72             Log.Info(this.GetType().ToString(), "Receive data from WeChat : " + builder.ToString());
     73             //转换数据格式并验证签名
     74             WxPayData data = new WxPayData();
     75             try
     76             {
     77                 data.FromXml(builder.ToString());
     78             }
     79             catch (WxPayException ex)
     80             {
     81                 //若签名错误,则立即返回结果给微信支付后台
     82                 WxPayData res = new WxPayData();
     83                 res.SetValue("return_code", "FAIL");
     84                 res.SetValue("return_msg", ex.Message);
     85                 Log.Error(this.GetType().ToString(), "Sign check error : " + res.ToXml());
     86                 return res;
     87             }
     88             
     89             return data;
     90         }
     91         //查询订单
     92         private bool QueryOrder(string transaction_id)
     93         {
     94             WxPayData req = new WxPayData();
     95             req.SetValue("transaction_id", transaction_id);
     96             WxPayData res = WxPayApi.OrderQuery(req);
     97             if (res.GetValue("return_code").ToString() == "SUCCESS" &&
     98                 res.GetValue("result_code").ToString() == "SUCCESS")
     99             {
    100                 return true;
    101             }
    102             else
    103             {
    104                 return false;
    105             }
    106         }
    107     }
    108 }

    前台,对,也是要新建一个View,代码如下(没错,也是空的)

     1 @{
     2     Layout = null;
     3 }
     4 <!DOCTYPE html>
     5 <html>
     6 <head>
     7     <meta name="viewport" content="width=device-width" />
     8     <title>Index</title>
     9 </head>
    10 <body>
    11     <div> 
    12     </div>
    13 </body>
    14 </html>
    好,模式一就到这里了,呼呼。。。没想到啊,一个模式一,让我从上午写到下午,真心累。。。还有一个模式二呢。。。喝口水先,咱,接着来。
     
     
    好,喝完水,接着干,下面是模式二:
     

    模式二生成直接支付url,支付url有效期为2小时

     
    由于有了上面模式一的详细说明,模式二,我就简单一点的来说了,如果又不懂的,到群里来问我吧。
     
    模式二,前端,增加一些代码,如下(完整的,包括模式一的代码了):
     1 @{
     2     Layout = null;
     3 }
     4 <!DOCTYPE html>
     5 <html>
     6 <head>
     7     <meta name="viewport" content="width=device-width" />
     8     <title>首页</title>
     9     <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" />
    10     <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" />
    11     <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" />
    12 </head>
    13 <body>
    14     <p>
    15         模式一:生成扫描支付模式
    16         <br />
    17         <div id="QRCode1">
    18         </div>
    19     </p>
    20     <p>
    21         模式二:生成直接支付url,支付url有效期为2小时
    22         <br />
    23         <div id="QRCode2">
    24         </div>
    25     </p>
    26     <script src="~/Scripts/jquery-1.10.2.js"></script>
    27     <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script>
    28     <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script>
    29     <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script>
    30     <script src="~/Scripts/jquery.qrcode.min.js"></script>
    31     <script type="text/javascript">
    32         $(function () {
    33             fGetQRCode1();
    34         })
    35         function fGetQRCode1() {
    36             $.messager.progress({
    37                 title: "",
    38                 msg: "正在生成二维码:模式一,请稍后..."
    39             });
    40             $.ajax({
    41                 type: "post",
    42                 url: "/Home/GetQRCode1",
    43                 data: {
    44                     time: new Date(),
    45                     productId:7788
    46                 },
    47                 success: function (json) {
    48                     $.messager.progress('close');//记得关闭
    49                     if (json.result) {
    50                         $('#QRCode1').qrcode(json.str); //生成二维码
    51                     }
    52                     else {
    53                         $('#QRCode1').html("二维码生成失败");
    54                     }
    55                     fGetQRCode2();
    56                 },
    57                 error: function (json) {
    58                     $('#QRCode1').html("二维码生成失败");
    59                     fGetQRCode2();
    60                 }
    61             })
    62         }
    63         function fGetQRCode2() {
    64             $.messager.progress({
    65                 title: "",
    66                 msg: "正在生成二维码:模式二,请稍后..."
    67             });
    68             $.ajax({
    69                 type: "post",
    70                 url: "/Home/GetQRCode2",
    71                 data: {
    72                     time: new Date(),
    73                     productId: 7788
    74                 },
    75                 success: function (json) {
    76                     $.messager.progress('close');//记得关闭
    77                     if (json.result) {
    78                         $('#QRCode2').qrcode(json.str); //生成二维码
    79                     }
    80                     else {
    81                         $('#QRCode2').html("二维码生成失败");
    82                     }
    83                 },
    84                 error: function (json) {
    85                     $('#QRCode2').html("二维码生成失败");
    86                 }
    87             })
    88         }
    89     </script>
    90 </body>
    91 </html>

    后端:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Web;
      5 using System.Web.Mvc;
      6 using WxPayAPI;
      7 namespace WxPay.Controllers
      8 {
      9     public class HomeController : Controller
     10     {
     11         // GET: Home
     12         public ActionResult Index()
     13         {
     14             return View();
     15         }
     16         /// <summary>
     17         /// 模式一
     18         /// </summary>
     19         /// <returns></returns>
     20         [HttpPost]
     21         public ActionResult GetQRCode1()
     22         {
     23             object objResult = "";
     24             string strProductID = Request.Form["productId"];
     25             string strQRCodeStr = GetPrePayUrl(strProductID);
     26             if (!string.IsNullOrWhiteSpace(strProductID))
     27             {
     28                 objResult = new { result = true, str = strQRCodeStr };
     29             }
     30             else
     31             {
     32                 objResult = new { result = false };
     33             }
     34             return Json(objResult);
     35         }
     36         /// <summary>
     37         /// 模式二
     38         /// </summary>
     39         /// <returns></returns>
     40         [HttpPost]
     41         public ActionResult GetQRCode2()
     42         {
     43             object objResult = "";
     44             string strProductID = Request.Form["productId"];
     45             string strQRCodeStr = GetPayUrl(strProductID);
     46             if (!string.IsNullOrWhiteSpace(strProductID))
     47             {
     48                 objResult = new { result = true, str = strQRCodeStr };
     49             }
     50             else
     51             {
     52                 objResult = new { result = false };
     53             }
     54             return Json(objResult);
     55         }
     56         /**
     57         * 生成扫描支付模式一URL
     58         * @param productId 商品ID
     59         * @return 模式一URL
     60         */
     61         public string GetPrePayUrl(string productId)
     62         {
     63             WxPayData data = new WxPayData();
     64             data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
     65             data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
     66             data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
     67             data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
     68             data.SetValue("product_id", productId);//商品ID
     69             data.SetValue("sign", data.MakeSign());//签名
     70             string str = ToUrlParams(data.GetValues());//转换为URL串
     71             string url = "weixin://wxpay/bizpayurl?" + str;
     72             return url;
     73         }
     74         /**
     75        * 参数数组转换为url格式
     76        * @param map 参数名与参数值的映射表
     77        * @return URL字符串
     78        */
     79         private string ToUrlParams(SortedDictionary<string, object> map)
     80         {
     81             string buff = "";
     82             foreach (KeyValuePair<string, object> pair in map)
     83             {
     84                 buff += pair.Key + "=" + pair.Value + "&";
     85             }
     86             buff = buff.Trim('&');
     87             return buff;
     88         }
     89         /**
     90        * 生成直接支付url,支付url有效期为2小时,模式二
     91        * @param productId 商品ID
     92        * @return 模式二URL
     93        */
     94         public string GetPayUrl(string productId)
     95         {
     96             WxPayData data = new WxPayData();
     97             data.SetValue("body", "广东XXXX股份有限公司");//商品描述
     98             data.SetValue("attach", "附加信息,用于后台或者存入数据库,做自己的判断");//附加数据
     99             data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//随机字符串
    100             data.SetValue("total_fee", 1);//总金额
    101             data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始时间
    102             data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易结束时间
    103             data.SetValue("goods_tag", "商品的备忘,可以自定义");//商品标记
    104             data.SetValue("trade_type", "NATIVE");//交易类型
    105             data.SetValue("product_id", productId);//商品ID
    106             WxPayData result = WxPayApi.UnifiedOrder(data);//调用统一下单接口
    107             string url = result.GetValue("code_url").ToString();//获得统一下单接口返回的二维码链接
    108             
    109             return url;
    110         }
    111     }
    112 }

    由于模式二是没有支付结果回调的,所以,我们要查询支付成功与否,需要自己写方法来查询,官方提供的查询支付成功与否的方法有以下,

     1 /***
     2         * 订单查询完整业务流程逻辑
     3         * @param transaction_id 微信订单号(优先使用)
     4         * @param out_trade_no 商户订单号
     5         * @return 订单查询结果(xml格式)
     6         */
     7         public static string Run(string transaction_id, string out_trade_no)
     8         {
     9             Log.Info("OrderQuery", "OrderQuery is processing...");
    10             WxPayData data = new WxPayData();
    11             if(!string.IsNullOrEmpty(transaction_id))//如果微信订单号存在,则以微信订单号为准
    12             {
    13                 data.SetValue("transaction_id", transaction_id);
    14             }
    15             else//微信订单号不存在,才根据商户订单号去查单
    16             {
    17                 data.SetValue("out_trade_no", out_trade_no);
    18             }
    19             WxPayData result = WxPayApi.OrderQuery(data);//提交订单查询请求给API,接收返回数据
    20             Log.Info("OrderQuery", "OrderQuery process complete, result : " + result.ToXml());
    21             return result.ToPrintStr();
    22         }
    可以通过这个微信订单号(transaction_id)来查询,也可以通过商户订单号(out_trade_no),所以,我们要合理利用这里面的技巧,上述模式二,我用的

    out_trade_no 是一个随机字符串,我们可以把这个字符串记录好,放数据库还是放哪里,你自己喜欢,然后写一个ajsx长轮询来,定时查询这个商户订单号,看看有没有支付成功,来做支付确认。

     
  • 相关阅读:
    Docker虚拟机配置手札(centos)
    Nginx配置手札
    登录的顶号功能实现
    苹果登录服务端JWT算法验证-PHP
    mac Read-Only filesystem (转载)
    ssh公私钥登录/git公私钥认证
    crontab 定时访问指定url,定时脚本
    网站通用 敏感词列表
    游戏行业术语一览(2)--游戏运营转化率[转载]
    <转载>为什么VR不可能成功?
  • 原文地址:https://www.cnblogs.com/hanqishihu/p/5542570.html
Copyright © 2011-2022 走看看