微信支付教程系列之公衆號支付

 目錄

(一)微信公衆號開發之VS遠程調試
(二)微信公衆號開發之基礎梳理
(三)微信公衆號開發之自動消息回覆和自定義菜單
(四)微信公衆號開發之網頁受權獲取用戶基本信息
(五)微信公衆號開發之網頁中及時獲取當前用戶Openid及注意事項
(六)微信公衆號開發之掃碼支付
(七)微信公衆號開發之公衆號支付
(八)微信公衆號開發之現金紅包
(九)微信公衆號開發之回覆圖文消息(被動)

  

       今天,咱們接着講微信支付的系列教程,前面,咱們講了這個微信紅包和掃碼支付。如今,咱們講講這個公衆號支付。公衆號支付的應用環境常見的用戶經過公衆號,而後再經過公衆號裏面的菜單連接,進入公衆號的商城,而後在裏面完成購買和支付功能,咱們能夠看看官方對這個公衆號支付的場景的解釋,連接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,經過這個官方的解釋,那咱們大概清楚這個公衆號的用途了,下面,我就說說,作這個公衆號支付的準備工做有哪些了。javascript

         一、下載微信web開發者工具,工具的使用方式,也看連接,地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_CN
         二、配置「微信支付」環境,以下圖:

         三、受權獲取用戶信息,以下圖:

 
 
         下面開始,一步一步往下走。
         1、咱們先開發程序,首先,新建一個MVC工程(asp.net的話,官方給的demo就是asp.net的,能夠下載來參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1),名爲:微信支付之公衆號支付,以下圖:
 
 
         而後右鍵項目,咱們修改一下屬性,以下圖:
 

 
而後咱們再把程序自動生成的HomeController.cs和View裏面的刪掉,再新建一個HomeController.cs和添加View,代碼以下:
 
複製代碼
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Web.Controllers { public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } } } 
複製代碼

 

 
View代碼:
複製代碼
@{
    Layout = null;
}

<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> </div> </body> </html>
複製代碼

 

 
        嗯,沒錯,目前仍是空的,如今咱們開始寫前臺,代碼以下(我先貼上代碼,後續再解釋爲啥這麼作,由於若是一步步的寫下去,按照前面兩個的篇幅來,我以爲均可以開課了,因此,我先上代碼,而後再一步步解釋。): 
複製代碼
@{
    Layout = null;
}

<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>電錶充值服務</title> <link href="~/Scripts/jquery-easyui-1.4.5/themes/bootstrap/easyui.css" rel="stylesheet" /> <link href="~/Scripts/jquery-easyui-1.4.5/themes/mobile.css" rel="stylesheet" /> <link href="~/Scripts/jquery-easyui-1.4.5/themes/icon.css" rel="stylesheet" /> <style type="text/css"> body{ margin:0; padding:0; } .logo { width: 100%; height: 70px; background: url(/Images/EleLogo.png) 0 0 no-repeat; background-size: 100% 100%; padding: 0; margin: 0; } .line { width: 100%; float: left; height: auto; text-align: center; margin-top: 10px; } .lineText { width: 100%; float: left; height: auto; text-indent: 5%; text-align: left; font-size: x-large; margin: 0; } .function { height: 60pt; line-height: 60pt; width: 45%; float: left; border-radius: 10px; background-color: #990000; margin-left: 8pt; } .title { font-family: "微軟雅黑"; font-size: x-large; color: white; } a { text-decoration: none; color: white; } input { vertical-align: central; } label { vertical-align: central; } .lbBlock { border: 1px solid #808080; background-color: grey; width: 90%; margin-left: 5%; font-size: x-large; border-radius: 10px; text-align: left; text-indent: 10pt; height: 30pt; padding-top: 5pt; } .btn { width: 90%; height: 35pt; font-size: x-large; background-color: #990000; color: white; background: url(/Images/red.png) 0 0 repeat; border: none; border-radius: 10px; margin: 10px 0 0 0; } .input { height: 30pt; width: 90%; font-size: x-large; border-radius: 10px; margin: 0; padding: 0; } </style> </head> <body> <div class="logo"> </div> <form id="ChargeForm"> <div class="line"> <div class="lineText"> 充值金額: </div> </div> <div class="line"> <input type="number" id="ChargeVal" name="ChargeVal" class="input" placeholder="單位:元" /> </div> </form> <div class="line"> <input type="button" class="btn" value="當即充值" onclick="fCharge()" style="margin-top: 20px;" /> </div> <div class="line"> <input type="button" id="btnHome" class="btn" value="返回主頁" onclick="fBackHome()" /> </div> <script src="~/Scripts/jquery-easyui-1.4.5/jquery.min.js"></script> <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.min.js"></script> <script src="~/Scripts/jquery-easyui-1.4.5/jquery.easyui.mobile.js"></script> <script src="~/Scripts/jquery-easyui-1.4.5/easyloader.js"></script> <script type="text/javascript"> $(function () { var vCode = getQueryString("code"); if (vCode != "" && vCode != null) { //alert(vCode); $.ajax({ type: 'post', data: { code: vCode }, url: '/Home/getWxInfo', success: function (sjson) { //alert(sjson); //var vData = JSON.stringify(sjson); //alert(vData); $.messager.show({ title: '提示', msg: '歡迎您來到微信端充值中心。' }); } }) } else { $.ajax({ type: 'post', url: '/Home/getCode', success: function (sjson) { //alert(sjson); location.href = sjson; } }) } }) //獲取url的參數 function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; } //初始化微信支付環境 function fCharge() { if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } } else { fPostCharge(); } } //提交充值數據 function fPostCharge() { var vChargeVal = $("#ChargeVal").val(); vChargeVal = parseFloat(vChargeVal); if (vChargeVal > 0) { $.messager.progress({ title: "", msg: "正在調用微信支付接口,請稍後..." }); $.ajax({ type: "post", data: "totalfee=" + vChargeVal, url: "/Home/MeterRecharge", success: function (json) { $.messager.progress('close');//記得關閉 //var json = eval("(" + msg + ")");//轉換後的JSON對象 onBridgeReady(json); }, error: function () { $.messager.progress('close');//記得關閉 $.messager.alert("提示", '調用微信支付模塊失敗,請稍後再試。', 'info') } }) } else { alert("房間名或者充值金額不能夠爲空或者爲負數,請確認後再試.") } } //調用微信支付模塊 function onBridgeReady(json) { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId": json.appId, //公衆號名稱,由商戶傳入 "timeStamp": json.timeStamp, //時間戳,自1970年以來的秒數 "nonceStr": json.nonceStr, //隨機串 "package": json.packageValue, "signType": "MD5", //微信簽名方式: "paySign": json.paySign //微信簽名 }, function (res) { if (res.err_msg == "get_brand_wcpay_request:ok") { //alert("支付成功,請稍後查詢餘額,若有疑問,請聯繫管理員."); fAlreadyPay(); } // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。 } ); } function fBackHome() { location.href = "/"; } </script> </body> </html>
複製代碼

 

 
後臺代碼以下:
 
複製代碼
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Web.Models; using WxPayAPI; namespace Web.Controllers { public class HomeController : Controller { JsApiPay jsApiPay = new JsApiPay(); // GET: Home public ActionResult Index() { if (Session["openid"] == null) { try { //調用【網頁受權獲取用戶信息】接口獲取用戶的openid和access_token  GetOpenidAndAccessToken(); } catch (Exception ex) { //Response.Write(ex.ToString()); //throw;  } } return View(); } /** * * 網頁受權獲取用戶基本信息的所有過程 * 詳情請參看網頁受權獲取用戶基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html * 第一步:利用url跳轉獲取code * 第二步:利用code去獲取openid和access_token * */ public void GetOpenidAndAccessToken() { if (Session["code"] != null) { //獲取code碼,以獲取openid和access_token string code = Session["code"].ToString(); Log.Debug(this.GetType().ToString(), "Get code : " + code); jsApiPay.GetOpenidAndAccessTokenFromCode(code); } else { //構造網頁受權獲取code的URL string host = Request.Url.Host; string path = Request.Path; string redirect_uri = HttpUtility.UrlEncode("http://" + host + path); //string redirect_uri = HttpUtility.UrlEncode("http://gzh.lmx.ren"); WxPayData data = new WxPayData(); data.SetValue("appid", WxPayConfig.APPID); data.SetValue("redirect_uri", redirect_uri); data.SetValue("response_type", "code"); data.SetValue("scope", "snsapi_base"); data.SetValue("state", "STATE" + "#wechat_redirect"); string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl(); Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url); Session["url"] = url; } } /// <summary> /// 獲取code /// </summary> /// <returns></returns>  [HttpPost] public ActionResult getCode() { object objResult = ""; if (Session["url"] != null) { objResult = Session["url"].ToString(); } else { objResult = "url爲空。"; } return Json(objResult); } /// <summary> /// 經過code換取網頁受權access_token和openid的返回數據 /// </summary> /// <returns></returns>  [HttpPost] public ActionResult getWxInfo() { object objResult = ""; string strCode = Request.Form["code"]; if (Session["access_token"] == null || Session["openid"] == null) { jsApiPay.GetOpenidAndAccessTokenFromCode(strCode); } string strAccess_Token = Session["access_token"].ToString(); string strOpenid = Session["openid"].ToString(); objResult = new { openid = strOpenid, access_token = strAccess_Token }; return Json(objResult); } /// <summary> /// 充值 /// </summary> /// <returns></returns> [HttpPost] public ActionResult MeterRecharge() { object objResult = ""; string strTotal_fee = Request.Form["totalfee"]; string strFee = (double.Parse(strTotal_fee) * 100).ToString(); //若傳遞了相關參數,則調統一下單接口,得到後續相關接口的入口參數 jsApiPay.openid = Session["openid"].ToString(); jsApiPay.total_fee = int.Parse(strFee); //JSAPI支付預處理 try { string strBody = "南宮蕭塵微信支付";//商品描述 WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult(strBody); WxPayData wxJsApiParam = jsApiPay.GetJsApiParameters();//獲取H5調起JS API參數,注意,這裏引用了官方的demo的方法,因爲原方法是返回string的,因此,要對原方法改成下面的代碼,代碼在下一段 ModelForOrder aOrder = new ModelForOrder() { appId = wxJsApiParam.GetValue("appId").ToString(), nonceStr = wxJsApiParam.GetValue("nonceStr").ToString(), packageValue = wxJsApiParam.GetValue("package").ToString(), paySign = wxJsApiParam.GetValue("paySign").ToString(), timeStamp = wxJsApiParam.GetValue("timeStamp").ToString(), msg = "成功下單,正在接入微信支付." }; objResult = aOrder; } catch (Exception ex) { ModelForOrder aOrder = new ModelForOrder() { appId = "", nonceStr = "", packageValue = "", paySign = "", timeStamp = "", msg = "下單失敗,請重試,屢次失敗,請聯繫管理員." }; objResult = aOrder; } return Json(objResult); } } } 
複製代碼

 這裏就是上面修改了的代碼,童鞋們請注意php

複製代碼
        /** * * 從統一下單成功返回的數據中獲取微信瀏覽器調起jsapi支付所需的參數, * 微信瀏覽器調起JSAPI時的輸入參數格式以下: * { * "appId" : "wx2421b1c4370ec43b", //公衆號名稱,由商戶傳入 * "timeStamp":" 1395712654", //時間戳,自1970年以來的秒數 * "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //隨機串 * "package" : "prepay_id=u802345jgfjsdfgsdg888", * "signType" : "MD5", //微信簽名方式: * "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名 * } * @return string 微信瀏覽器調起JSAPI時的輸入參數,json格式能夠直接作參數用 * 更詳細的說明請參考網頁端調起支付API:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7 * */ public WxPayData GetJsApiParameters() { Log.Debug(this.GetType().ToString(), "JsApiPay::GetJsApiParam is processing..."); WxPayData jsApiParam = new WxPayData(); jsApiParam.SetValue("appId", unifiedOrderResult.GetValue("appid")); jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp()); jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr()); jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id")); jsApiParam.SetValue("signType", "MD5"); jsApiParam.SetValue("paySign", jsApiParam.MakeSign()); string parameters = jsApiParam.ToJson(); Log.Debug(this.GetType().ToString(), "Get jsApiParam : " + parameters); return jsApiParam; }
複製代碼

 

 
 
 
ModelForOrder類的代碼:
 
複製代碼
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Web.Models { public class ModelForOrder { public string appId { get; set; } public string timeStamp { get; set; } public string nonceStr { get; set; } public string packageValue { get; set; } public string paySign { get; set; } public string msg { get; set; } } } 
複製代碼

 

 
還有一個地方須要注意,修改一下的就是這裏WxLib/business/JsApiPay.cs,以下圖:
 
最後,把程序發佈出來,此次我們把Web發佈在 http://gzh.lmx.ren ,而後再把接口權限,改成這樣的,以下圖:

 
 
        注意,這裏面的域名和上面咱們發佈的域名要一致。
 
         除此之外,咱們還須要改這裏:
        就是必定要受權這裏,不然,支付的時候,會提示其餘錯誤,具體,我就不測試了。
         
         另外,這裏其實已經完成了這個公衆號的支付的流程了,可是,咱們頁面上,會友善的提醒(其實不友善,提示是紅色的,在頭部,提示別輸入密碼什麼),這是由於,咱們還沒把我們這個http://gzh.lmx.ren域名設置爲安全域名,設置以後,就不會在提示了。設置方法以下圖:
 
在這裏面加入我們的域名,就完美了。。。
 
         個人代碼都儘可能精簡,多餘的,我都會丟掉,就是爲了不混淆視聽。若是代碼裏面,有寫的不清楚的,能夠私信問我,或羣裏來問我,羣號在文章末端。
 
 
如今,我開始一一解釋我上面的作法。
         首先,在後端,頁面加載的時候,他會先執行
        
複製代碼
public ActionResult Index() { if (Session["openid"] == null) { try { //調用【網頁受權獲取用戶信息】接口獲取用戶的openid和access_token  GetOpenidAndAccessToken(); } catch (Exception ex) { //Response.Write(ex.ToString()); //throw;  } } return View(); } 
複製代碼

 

這裏面就是爲了獲取用戶的Openid和Access_token,這個用途很大,還有就是,咱們經過代碼能夠知道,咱們經過這個方法,能夠獲取到微信的一些相關信息,獲取完了以後,他會返回到咱們的頁面上來,url就存在一個session裏面,以下:
Session["url"] = url;        
 
接着 ,在前端:
         當頁面加載完畢以後,會執行如下JS方法,以下:
      
複製代碼
  $(function () { var vCode = getQueryString("code"); if (vCode != "" && vCode != null) { //alert(vCode);  $.ajax({ type: 'post', data: { code: vCode }, url: '/Home/getWxInfo', success: function (sjson) { //alert(sjson); //var vData = JSON.stringify(sjson); //alert(vData);  $.messager.show({ title: '提示', msg: '歡迎您來到微信端充值中心。' }); } }) } else { $.ajax({ type: 'post', url: '/Home/getCode', success: function (sjson) { //alert(sjson); location.href = sjson; } }) } }) 
複製代碼

 

 
他會先獲取瀏覽器的url,而後獲取code,就是通常url後面的xxx.com?code=xxx,這裏面就是首先判斷有無code,若是沒有code,則,咱們去後臺請求這個code。爲何請求這個code呢?咱們來看這個方法:  getWxInfo,以下圖:
       
複製代碼
 /// <summary> /// 獲取code /// </summary> /// <returns></returns>  [HttpPost] public ActionResult getCode() { object objResult = ""; if (Session["url"] != null) { objResult = Session["url"].ToString(); } else { objResult = "url爲空。"; } return Json(objResult); } 
複製代碼

 

 
他就會返回url到前端,前端經過js去訪問那個網址,那個網址就是微信端獲取到咱們的信息以後,給咱們按照規則再返回一個url,這rul就是咱們後面須要後去的code的url。這個code對咱們相當重要,由於後面咱們要作跟支付有關的工做,都用到的。有了code,咱們才能拿到openid和access_token。具體看代碼邏輯也能夠明瞭。
        好,走到這一步,咱們已經知道openid和access_token了,這個時候,咱們就負責處理前端的東西。
        前端,我就一個金額輸入框,而後一個提交,實際應用中,咱們確定還須要傳入商品的參數,我這裏面就不寫那些多餘的了,後續大家本身加進去就能夠了。這裏面在點擊提交的時候,會調用微信的環境,看下面的代碼:
      
複製代碼
  //初始化微信支付環境 function fCharge() { if (typeof WeixinJSBridge == "undefined") { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } } else { fPostCharge(); } } 
複製代碼

 

他會初始化一下環境,若是初始化成功,表明,這個頁面是在微信客戶端裏面運行的,那麼咱們就給他運行咱們真正的充值代碼提交,因此,就會執行: fPostCharge();
 
提交以後,就會進入後臺,後臺須要組織咱們前臺須要用到的參數,其中包括以下:
        
 
複製代碼
/// <summary> /// 充值 /// </summary> /// <returns></returns>  [HttpPost] public ActionResult MeterRecharge() { object objResult = ""; string strTotal_fee = Request.Form["totalfee"]; string strFee = (double.Parse(strTotal_fee) * 100).ToString(); //若傳遞了相關參數,則調統一下單接口,得到後續相關接口的入口參數 jsApiPay.openid = Session["openid"].ToString(); jsApiPay.total_fee = int.Parse(strFee); //JSAPI支付預處理 try { string strBody = "南宮蕭塵微信支付";//商品描述 WxPayData unifiedOrderResult = jsApiPay.GetUnifiedOrderResult(strBody); WxPayData wxJsApiParam = jsApiPay.GetJsApiParameters();//獲取H5調起JS API參數  ModelForOrder aOrder = new ModelForOrder() { appId = wxJsApiParam.GetValue("appId").ToString(), nonceStr = wxJsApiParam.GetValue("nonceStr").ToString(), packageValue = wxJsApiParam.GetValue("package").ToString(), paySign = wxJsApiParam.GetValue("paySign").ToString(), timeStamp = wxJsApiParam.GetValue("timeStamp").ToString(), msg = "成功下單,正在接入微信支付." }; objResult = aOrder; } catch (Exception ex) { ModelForOrder aOrder = new ModelForOrder() { appId = "", nonceStr = "", packageValue = "", paySign = "", timeStamp = "", msg = "下單失敗,請重試,屢次失敗,請聯繫管理員." }; objResult = aOrder; } return Json(objResult); } 
複製代碼

 

 
咱們主要須要提供的就是這個類 ModelForOrder 裏面的參數,而後再把這些參數返回給前臺調用,以下:
       
複製代碼
 //調用微信支付模塊 function onBridgeReady(json) { WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId": json.appId, //公衆號名稱,由商戶傳入 "timeStamp": json.timeStamp, //時間戳,自1970年以來的秒數 "nonceStr": json.nonceStr, //隨機串 "package": json.packageValue, "signType": "MD5", //微信簽名方式: "paySign": json.paySign //微信簽名  }, function (res) { if (res.err_msg == "get_brand_wcpay_request:ok") { //alert("支付成功,請稍後查詢餘額,若有疑問,請聯繫管理員.");  fAlreadyPay(); } // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。  } ); } 
複製代碼

 

 
這樣,他就會彈出一個微信支付的窗口,以下:
而後咱們確認付款以後,是否付款成功,若是付款成功,咱們在執行:  fAlreadyPay();
 
這個方法已經被我刪掉了,用途是用於,咱們收到用戶的款以後,咱們須要同步一些數據到咱們的數據庫裏面去,因此,該怎麼操做,本身自行修改了。
 
原文地址:http://www.cnblogs.com/nangong/p/50ab3c60f0d1ae5b551373cf96cd060d.html
相關文章
相關標籤/搜索