.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
 
 
 
 
 
 
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM