C# 微信支付教程系列之扫码支付
微信支付教程系列之掃碼支付
今天,我們來一起探討一下這個(gè)微信掃碼支付。何為掃碼支付呢?這里面,掃的碼就是二維碼了,就是我們經(jīng)常掃一掃的那種二維碼圖片,例如,我們自己添加好友的時(shí)候,可以通過輸入對方的微信號,也可以掃一掃對方的二維碼。掃碼支付,作為,微信支付里面,不可或缺的一個(gè)功能,對商品的支付提供了極為方便的體驗(yàn),用途也非常的多。例如我們在地鐵、公交站常見的那些自動售貨機(jī)(不錯(cuò),就是那種投硬幣,就可以自動出貨的那種機(jī)器)中都用到。以前,那種機(jī)器,只能通過投硬幣或者紙幣,但是,這里面也有一定的風(fēng)險(xiǎn),例如:假幣,盜竊(真有人把機(jī)器砸了,把機(jī)器里面的錢偷走的),所以,微信(支付寶)的掃碼支付的出現(xiàn),大大的減少了這方面的風(fēng)險(xiǎn),近些年來,二維碼的應(yīng)用越來越廣,甚至有些地方,直接用來自動售票(就是把起始點(diǎn)設(shè)定好,票價(jià)設(shè)定好,直接把二維碼貼出來,讓乘客自動掃相關(guān)的二維碼,完成購票,上車的時(shí)候,只需要提供自己的支付憑證給乘車員驗(yàn)證即可),這樣,不僅綠色環(huán)保了,還大大的提高了售票的速度(去過大車站購票的人應(yīng)該深有體驗(yàn),排隊(duì)買個(gè)票,好歹半個(gè)小時(shí)以上,心里也是萬頭草泥馬在奔騰的)。
咱就不扯遠(yuǎn)了,說回咱么今天要做的微信支付之掃碼支付。微信官方的文檔,這個(gè)掃碼支付(NativePay)分為兩種,一種是“生成掃描支付模式”,另外一種是“生成直接支付url,支付url有效期為2小時(shí)”,至于這里面,兩種掃碼模式,怎么靈活利用呢,官方也沒有一個(gè)明確的說明。個(gè)人理解為,第一種(生成掃描支付模式),適用于固定二維碼的,就是永久使用的那種,例如一些商家的公眾號的二維碼,是永久的,什么時(shí)候掃,都是關(guān)注這個(gè)公眾號的,但是,這種的話,我記得微信是有限量的,貌似是一個(gè)公眾號,限量10w,個(gè)人觀點(diǎn),覺得這個(gè)限量,是足夠我們使用的。第二種(生成直接支付url,支付url有效期為2小時(shí)),這種的話,因?yàn)橛杏行谶@種時(shí)間限制,超過了2個(gè)小時(shí),該二維碼就失效,但是對生成的二維碼數(shù)量沒有限制,所以,這種個(gè)人觀點(diǎn)覺得適用于那種臨時(shí)根據(jù)實(shí)際情況生成的二維碼,例如:公眾平臺登陸的時(shí)候二次驗(yàn)證的二維碼,自定義生成,僅為一次性繳費(fèi)使用的二維碼,等等)。接下來,我們就開始講講實(shí)際例子,首先將的就是第一種模式。
掃碼支付之模式一(生成掃描支付模式):
首先,我們新建一個(gè)“MVC”的項(xiàng)目(asp.net的官方的demo就是了,要asp.net的自己看demo吧,demo地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1),然后把系統(tǒng)自動生成的HomeControler和View中的Home都刪了。
然后自己新建一個(gè)HomeControler,代碼如下:
1 // GET: Home
2 public ActionResult Index()
3 {
4 return View();
5 }
再添加一個(gè)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的一些我們會用到的東西拷貝過來,其中包括以下幾個(gè)文件夾,如下圖:
就這個(gè)lib和business兩個(gè),把這兩個(gè)文件夾,支付復(fù)制到咱們的新項(xiàng)目中,并且包含在項(xiàng)目中,如下:
然后我們再“重新生成”以下項(xiàng)目,或者快捷鍵:ctrl+shift+b,這時(shí)候,會提下如下錯(cuò)誤:
這時(shí)候,我們?nèi)ヌ砑右茫?strong>lib文件夾中的LitJson.dll添加上即可,如下圖:
到這里,我們就基本把官方的demo的環(huán)境給搭建好了,接下來,我們就要開始編寫代碼了。
首先,我的邏輯是,從前到后,就是從前端到后端。前端是顯示二維碼的地方,那么我們就先給他一個(gè)div(本文使用到的是jquery的二維碼生成插件,全名叫:jquery.qrcode.min.js,我會傳到附件上),然后在頁面加載完畢的時(shí)候,會請求后臺,讓他返回二維碼字符串,然后再通過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小時(shí)
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');//記得關(guān)閉
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());//時(shí)間戳
47 data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//隨機(jī)字符串
48 data.SetValue("product_id", productId);//商品ID
49 data.SetValue("sign", data.MakeSign());//簽名
50 string str = ToUrlParams(data.GetValues());//轉(zhuǎn)換為URL串
51 string url = "weixin://wxpay/bizpayurl?" + str;
52 return url;
53 }
54 /**
55 * 參數(shù)數(shù)組轉(zhuǎn)換為url格式
56 * @param map 參數(shù)名與參數(shù)值的映射表
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 }
這時(shí)候,模式一是不是感覺就完成了?那么我們現(xiàn)在試試,我們?yōu)g覽該頁面,如下:
然后用微信掃一掃功能掃一下,發(fā)現(xiàn)提示如下:
這是什么鬼,是不是,你心里面是不是想知道為啥,那我來告訴你,這是為啥,這是因?yàn)椋氵€沒有設(shè)置回調(diào)頁面或者回調(diào)頁面有問題,這個(gè)時(shí)候,我們再新建一個(gè)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", "回調(diào)數(shù)據(jù)異常");
28 return res.ToXml();
29 }
30 //調(diào)統(tǒng)一下單接口,獲得下單結(jié)果
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)//若在調(diào)統(tǒng)一下單接口時(shí)拋異常,立即返回結(jié)果給微信支付后臺
39 {
40 WxPayData res = new WxPayData();
41 res.SetValue("return_code", "FAIL");
42 res.SetValue("return_msg", "統(tǒng)一下單失敗");
43 return res.ToXml();
44 }
45 //若下單失敗,則立即返回結(jié)果給微信支付后臺
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", "統(tǒng)一下單失敗");
51 return res.ToXml();
52 }
53 //統(tǒng)一下單成功,則返回成功結(jié)果給微信支付后臺
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 /// 接收從微信支付后臺發(fā)送過來的數(shù)據(jù)并驗(yàn)證簽名
68 /// </summary>
69 /// <returns>微信支付后臺返回的數(shù)據(jù)</returns>
70 public WxPayData GetNotifyData()
71 {
72 //接收從微信后臺POST過來的數(shù)據(jù)
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 //轉(zhuǎn)換數(shù)據(jù)格式并驗(yàn)證簽名
85 WxPayData data = new WxPayData();
86 try
87 {
88 data.FromXml(builder.ToString());
89 }
90 catch (WxPayException ex)
91 {
92 //若簽名錯(cuò)誤,則立即返回結(jié)果給微信支付后臺
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 //統(tǒng)一下單
102 WxPayData req = new WxPayData();
103 req.SetValue("body", "廣東XXXX股份有限公司");
104 req.SetValue("attach", "附加信息,用于后臺或者存入數(shù)據(jù)庫,做自己的判斷");
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 }
記得,也要新建一個(gè)View,就是在Index那里,右鍵添加一個(gè)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>
接著,把這個(gè)項(xiàng)目,發(fā)布出來,放到服務(wù)器的iis上,這里面,我把他發(fā)布在http://sm.lmx.ren/上面(必須要發(fā)布到網(wǎng)上哈,如果不懂發(fā)布的,你可以自己去學(xué)習(xí)基礎(chǔ)知識先了),這還沒完,還需要把到公眾平臺上,設(shè)置回調(diào)頁面,操作如下:
這樣,就大功告成了。這時(shí)候,我們再試試掃碼,發(fā)現(xiàn)已經(jīng)得到以下提示了,這樣子,就代表,我們的模式一,已經(jīng)成功完成了。如下圖:
這時(shí)候,細(xì)心的朋友就會提問了,我這都支付成功了,怎么頁面沒啥提示呀,這頁面不交互很不友好啊。嗯,沒錯(cuò),童鞋,你有前途,現(xiàn)在我就告訴你,怎么做交互,但是,為了你日后更加有前途,我只告訴你邏輯,具體怎么實(shí)現(xiàn),自己來想,多動腦。
那么邏輯是怎么的呢?常規(guī)邏輯下,我們微信掃頁面上的這個(gè)二維碼的時(shí)候,這個(gè)時(shí)候,他已經(jīng)把我們二維碼里面的參數(shù),傳到微信服務(wù)器,然后有他們開始統(tǒng)一下單(如果對邏輯不清晰,可以看看官方的文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3):他們在統(tǒng)一下單的時(shí)候,就會生成一個(gè)product_id,這個(gè)家伙的作用呢 ,就是告訴你現(xiàn)在微信服務(wù)器,已經(jīng)生成了一個(gè)單號,勞資已經(jīng)收到你的支付請求了,趕緊給老子付款,O(∩_∩)O哈哈~。。。停,停,停。這時(shí)候,思路不能繼續(xù)往下走了。記得,前面有個(gè)叫做“統(tǒng)一下單“,那既然有這個(gè)步驟,那我們可以利用一下,就是當(dāng)他統(tǒng)一下單成功的時(shí)候,我們可以在頁面更新一下狀態(tài),告訴客戶:您已成功掃描,并下單成功,請支付。是不是,我們可以提示他們這個(gè)。然后等用戶在手機(jī)上,支付成功的時(shí)候,這個(gè)時(shí)候,頁面是不是也要反饋給用戶,告訴他,小子,你的錢已經(jīng)到我的口袋了,你可以走了(你走,我沒有你這樣的寶寶)。O(∩_∩)O哈哈~,但是,你還要停,停住,停下來。我們服務(wù)公司怎么知道這個(gè)微信用戶已經(jīng)付款成功了呢?來,我們把視線回到代碼上,找到lib/Config.cs,如下圖:
然后打開config.cs,找到以下代碼:
對了,你很聰明。微信的處理邏輯就是,等用戶支付成功之后,他會給這個(gè)鏈接發(fā)送支付結(jié)果,默認(rèn)是以前那個(gè)aspx的頁面,現(xiàn)在我換成mvc,所以,我們得手動新建一個(gè)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 //檢查支付結(jié)果中transaction_id是否存在
24 if (!notifyData.IsSet("transaction_id"))
25 {
26 //若transaction_id不存在,則立即返回結(jié)果給微信支付后臺
27 WxPayData res = new WxPayData();
28 res.SetValue("return_code", "FAIL");
29 res.SetValue("return_msg", "支付結(jié)果中微信訂單號不存在");
30 return res.ToXml();
31 }
32 string transaction_id = notifyData.GetValue("transaction_id").ToString();
33 //查詢訂單,判斷訂單真實(shí)性
34 if (!QueryOrder(transaction_id))
35 {
36 //若訂單查詢失敗,則立即返回結(jié)果給微信支付后臺
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();//如果我們走到這一步了,那就代表,用戶已經(jīng)支付成功了,所以,該干嘛干嘛了。
52 }
53 }
54 /// <summary>
55 /// 接收從微信支付后臺發(fā)送過來的數(shù)據(jù)并驗(yàn)證簽名
56 /// </summary>
57 /// <returns>微信支付后臺返回的數(shù)據(jù)</returns>
58 public WxPayData GetNotifyData()
59 {
60 //接收從微信后臺POST過來的數(shù)據(jù)
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 //轉(zhuǎn)換數(shù)據(jù)格式并驗(yàn)證簽名
74 WxPayData data = new WxPayData();
75 try
76 {
77 data.FromXml(builder.ToString());
78 }
79 catch (WxPayException ex)
80 {
81 //若簽名錯(cuò)誤,則立即返回結(jié)果給微信支付后臺
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 }
前臺,對,也是要新建一個(gè)View,代碼如下(沒錯(cuò),也是空的)
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>
好,模式一就到這里了,呼呼。。。沒想到啊,一個(gè)模式一,讓我從上午寫到下午,真心累。。。還有一個(gè)模式二呢。。。喝口水先,咱,接著來。
好,喝完水,接著干,下面是模式二:
模式二(生成直接支付url,支付url有效期為2小時(shí))
由于有了上面模式一的詳細(xì)說明,模式二,我就簡單一點(diǎn)的來說了,如果又不懂的,到群里來問我吧。
模式二,前端,增加一些代碼,如下(完整的,包括模式一的代碼了):
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小時(shí)
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');//記得關(guān)閉
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');//記得關(guān)閉
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());//時(shí)間戳
67 data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//隨機(jī)字符串
68 data.SetValue("product_id", productId);//商品ID
69 data.SetValue("sign", data.MakeSign());//簽名
70 string str = ToUrlParams(data.GetValues());//轉(zhuǎn)換為URL串
71 string url = "weixin://wxpay/bizpayurl?" + str;
72 return url;
73 }
74 /**
75 * 參數(shù)數(shù)組轉(zhuǎn)換為url格式
76 * @param map 參數(shù)名與參數(shù)值的映射表
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小時(shí),模式二
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", "附加信息,用于后臺或者存入數(shù)據(jù)庫,做自己的判斷");//附加數(shù)據(jù)
99 data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//隨機(jī)字符串
100 data.SetValue("total_fee", 1);//總金額
101 data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));//交易起始時(shí)間
102 data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));//交易結(jié)束時(shí)間
103 data.SetValue("goods_tag", "商品的備忘,可以自定義");//商品標(biāo)記
104 data.SetValue("trade_type", "NATIVE");//交易類型
105 data.SetValue("product_id", productId);//商品ID
106 WxPayData result = WxPayApi.UnifiedOrder(data);//調(diào)用統(tǒng)一下單接口
107 string url = result.GetValue("code_url").ToString();//獲得統(tǒng)一下單接口返回的二維碼鏈接
108
109 return url;
110 }
111 }
112 }
由于模式二是沒有支付結(jié)果回調(diào)的,所以,我們要查詢支付成功與否,需要自己寫方法來查詢,官方提供的查詢支付成功與否的方法有以下,
1 /***
2 * 訂單查詢完整業(yè)務(wù)流程邏輯
3 * @param transaction_id 微信訂單號(優(yōu)先使用)
4 * @param out_trade_no 商戶訂單號
5 * @return 訂單查詢結(jié)果(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))//如果微信訂單號存在,則以微信訂單號為準(zhǔn)
12 {
13 data.SetValue("transaction_id", transaction_id);
14 }
15 else//微信訂單號不存在,才根據(jù)商戶訂單號去查單
16 {
17 data.SetValue("out_trade_no", out_trade_no);
18 }
19 WxPayData result = WxPayApi.OrderQuery(data);//提交訂單查詢請求給API,接收返回?cái)?shù)據(jù)
20 Log.Info("OrderQuery", "OrderQuery process complete, result : " + result.ToXml());
21 return result.ToPrintStr();
22 }
可以通過這個(gè)微信訂單號(transaction_id)來查詢,也可以通過商戶訂單號(out_trade_no),所以,我們要合理利用這里面的技巧,上述模式二,我用的
out_trade_no 是一個(gè)隨機(jī)字符串,我們可以把這個(gè)字符串記錄好,放數(shù)據(jù)庫還是放哪里,你自己喜歡,然后寫一個(gè)ajsx長輪詢來,定時(shí)查詢這個(gè)商戶訂單號,看看有沒有支付成功,來做支付確認(rèn)。
總結(jié)
以上是生活随笔為你收集整理的C# 微信支付教程系列之扫码支付的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 兰德酷路泽大保养一次多少钱(酷路泽大保养
- 下一篇: 桂林跟玉林哪个城市中央空调用的多