嗨,歡迎好學的小夥伴們,今天我們來一起攻克微信支付所以遇到的各種坑,歡迎大家共同留言討論,本節將的是微信的支付功能-----JAVA版
首先,我們先要去微信官方申請【公衆號】支付接口開通:https://mp.weixin.qq.com,注意,訂閱號是沒有開通支付接口的能力,所以注意下,一定是公衆號才能行的哦,然後去講商戶號和公衆號綁定:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F,提供一系列的證書,材料之類的,提交後,需要微信官方進行審覈,慢的話,大概就7個工作日,快也就半天都可能的,通過後,即可開通公衆號支付接口,還有就是需要一個域名,而且這個域名是在備案過的哈,一定要是備案過的,不然不能使用哦。
其次,我們要準備下我們開發中需要的參數(這些參數在申請通過後,都能查看):appid 應用id 支付接口開通後可查看、
openid 後期可以用微信每次的code獲取、
mch_id 商戶id也叫商戶號 支付接口開通後可查看 、
key key爲商戶平臺設置的密鑰key 32位數 由操作密碼和自定義密碼32生成、
secret 第三方用戶唯一憑證密鑰
然後,去看下微信支付的時序圖,當然微信的官方文檔寫的很詳細,不過有幾個細節沒有說到位,這裏我們來看下我自己整理的下的流程圖吧,感覺簡單好懂些
時序思維圖
說明:首先是訪問微信授權連接進行授權以及獲取到openid還有code,然後就是統一下單,統一下單分爲兩次,第一次是簽名獲取pepay_id,也就是預支付id,通過發送xml報文給微信連接,獲取這個預支付id,然後第二次簽名就是,拿到預支付id在加上第二次的報文,發送給微信,生成預支付訂單,於支付訂單生成好了後,返回前臺,利用微信自帶的接口,然後將後臺返回來的簽名和一系列參數去請求這個接口,將會釣起微信支付的預支付界面,然後這個接口會返回參數res.err_msg,從這個裏面我們可以判斷出用戶是付款了還是取消了,返回get_brand_wcpay_request:ok,就是成功,不過這個可能會有延遲,所以只是用來提示用戶付款成功,最後的邏輯判斷我們還是得到回調界面裏面寫,保險點,因爲有時候有網絡延遲,然後基本上流程就是這樣了,其他都是就是後續事情
然後,我們來上最重要的東西,也是最關心的東西代碼和jar包,以及帶着jar和代碼來走一遍流程
第一:首先,我們到商品詳情界面點擊下單按鈕,來到一個微信接口jsp,進行授權下圖,
序號1,是商品詳情界面穿進來的參數,金額,訂單id,以及訂單描述,
序號2,是上面說的開通微信支付後,會收到的幾個參數,這裏我們先給其封裝到session裏面,方便後續拿值,
序號3,則是微信授權的鏈接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=<%=session.getAttribute("appid")%>&redirect_uri=http://new.nbtongtai.com/weixin/wxPay/orderPayDeail.jsp&response_type=code&scope=snsapi_userinfo&state='+order_money+'#wechat_redirect,訪問該鏈接即可授權,如授權通過,則會跳往支付詳細界面,進行進一步確認 orderPayDeail.jsp 就是授權後跳往的界面
第二:來到授權後的界面orderPayDeail.jsp,然後就是獲取授權後,微信返給我們的參數,
通過這個上面JS拿到微信返回的參數列表,然後則可以拿到返回的code
獲取到code後,我們就可以更加code去拿到openid
前臺訪問:
後臺根據code拿到openid,然後將openid和code存session裏面,最後在返回前臺,注意這裏的appid還有secret都是授權那裏存session裏面的,所以這裏可以直接拿出來用
前臺將返回來的openid,存界面上,然後就可以進行統一下單了,如下圖:再次去後臺,將前面準備的參數,傳後臺,請求微信接口,生成預支付訂單,第一個參數就是訂單id,第二個就是金額也就是之前授權前商品界面返回來的金額,第三個就是code,每次訪問coe都不一樣,所以這裏要從請求裏面獲取。
序號1則是在上一步的js方法返回過來的請求,並且獲取的參數信息
序號2則是獲取到金額,還有訂單金額,已經code後,我們就可以生成預支付訂單了,也就是說統一下單流程,通過post方法將金額,openid,訂單id去請求後臺,進行預支付統一下單
來到後臺統一下單後臺,先獲取金額,openid,訂單id,然後進行兩次簽名,第一次通過封裝restata集合,然後請求微信預支付連接,得到預支付id,第二次在將獲取的預支付id封裝,再次請求微信生成微信預支付訂單
//得到前臺傳過來的金額,消費者id
String order_money=JspUtilCode.unescape(JspUtil.changeNull(request.getParameter("order_money"))); //應收金額
String openId=JspUtilCode.unescape(JspUtil.changeNull(request.getParameter("openId"))); //openId //openId="owFJm07ds2P0MAKoezy3qF9EfN2k";
String gm_id=JspUtilCode.unescape(JspUtil.changeNull(request.getParameter("gm_id"))); //商品id
//得到商戶的支付金額,單位爲分,這裏換算爲元
Double _money=Double.parseDouble(order_money)*100;
int money=_money.intValue();
Random rand = new Random(); //生成隨機數,因爲訂單號不能太短
int r1=rand.nextInt(10000);
/****************************第一次簽名,獲取預支付id*******************************/
Map<String, String> restData=new HashMap<String, String>();
restData.put("appid",session.getAttribute("appid").toString()); //應用ID 第三方用戶唯一憑證
restData.put("openid",openId); //消費者id
restData.put("body",session.getAttribute("body").toString()); //商品描述 寄存續費充值
restData.put("mch_id",session.getAttribute("mch_id").toString());//商戶號
restData.put("notify_url","http://new.nbtongtai.com/weixin/wxPay/BackMessage.jsp"); //通知地址 不管支付成功還是失敗都會返回到這個界面
restData.put("nonce_str",WXPayUtil.generateNonceStr()); //隨機字符串
restData.put("out_trade_no",(r1+""+r1)+"O"+gm_id); //訂單號,不能太短O 後面纔是我們想要的訂單id
restData.put("sign_type","MD5"); //簽名類型
restData.put("total_fee",money+""); //交易金額
restData.put("trade_type","JSAPI"); //交易類型 NATIVE二維碼
restData.put("spbill_create_ip","47.114.88.38"); //瀏覽器ip地址,可以不寫
String oneSign = WXPayUtil.generateSignature(restData,session.getAttribute("cusid").toString()); //第二個參數是商戶id裏面的那個key 32位數
restData.put("sign",oneSign); //拼接簽名
//將map集合轉成xml報文,方便請求微信接口獲取 預支付定單id
String xml = WXPayUtil.mapToXml(restData);
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //預支付請求連接
String response2 = HttpUtil.doPost(unifiedorder_url, xml); //通過帶有簽名的xml報文,和預支付連接獲取到響應結果
String prepay_id = "";// 預支付id
if(response2.indexOf("SUCCESS") != -1) { //若響應結果成功,則取出預支付id
Map<String, String> map = WXPayUtil.xmlToMap(response2);
prepay_id = (String) map.get("prepay_id");
}
/****************************第一次簽名,獲取預支付id*******************************/
/****************************第二次簽名,生成預支付訂單*******************************/
SortedMap<String, String> finalpackage = new TreeMap<String, String>();
String packages="prepay_id="+prepay_id; //預支付id
String timeStamp=""+System.currentTimeMillis(); //預支付訂單時間戳
finalpackage.put("appId",session.getAttribute("appid").toString()); //應用ID 第三方用戶唯一憑證
finalpackage.put("timeStamp",timeStamp);
finalpackage.put("nonceStr", WXPayUtil.generateNonceStr()); //隨機字符串
finalpackage.put("package", packages);
finalpackage.put("signType", "MD5");
//調用簽名接口,進行支付
String twoSign = WXPayUtil.generateSignature(finalpackage,session.getAttribute("cusid").toString());
/****************************第二次簽名,生成預支付訂單*******************************/
//生成預支付訂單
json=new JsonUtil();
json.addJsons();
json.addJsonData("gm_id",gm_id);
json.addJsonData("appid",session.getAttribute("appid").toString());
json.addJsonData("packages",packages);
json.addJsonData("timeStamp",timeStamp);
json.addJsonData("nonceStr",finalpackage.get("nonceStr"));
json.addJsonData("finalsign",twoSign);//根據第二次簽名,返回前臺,然後釣起支付面板
json.addJsonData("status","ok");
message=json.getJson();
前臺收到你返回的狀態,進行判斷,訂單預支付生成成功後,則跳往微信的釣起支付面板界面
來到支付面板界面,要做到事情就通過簽名,openid還有等參數,去請求微信,調用微信的微信支付界面即可支付,參數就是上面返回的,將其傳給下圖即可,然後就可以釣起來微信預支付界面,若用戶支付成功,則跳往自己寫的成功界面,失敗也是一樣,寫個失敗的界面,然後就是這裏注意下,下面的這個js界面釣起的微信支付,成功有延遲,所以最好不在這裏做最終的支付成功判斷
(function ($, doc, $$) {
$.init();
mui.plusReady(function(){
// 在這裏調用plus api
//獲取數據
},false);
wx.config({
debug: false, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
appId: $$("#appid").val(), // 必填,公衆號的唯一標識
timestamp: $$("#timestampJsp").val() , // 必填,生成簽名的時間戳
nonceStr: $$("#nonceStrJsp").val(), // 必填,生成簽名的隨機串
signature: $$("#signatureJsp").val(), // 必填,簽名,見附錄1
jsApiList: ['getBrandWCPayRequest'] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
});
wx.ready(function(){
function onBridgeReady(){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId":$$("#appid").val(), //公衆號名稱,由商戶傳入
"timeStamp":$$("#timeStamp").val(), //時間戳,自1970年以來的秒數
"nonceStr":$$("#nonceStr").val(), //隨機串
"package":$$("#packages").val(),
"signType":"MD5", //微信簽名方式:
"paySign":$$("#finalsign").val() //微信簽名
},function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) { // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回 ok,但並不保證它絕對可靠。
//下單完成後,跳往邏輯的界面,向但與同步通知
mui.openWindow({
url:"/weixin/wxPay/successOrder.jsp?gm_id="+$$("#gm_id").val(),
id:"xufeidengPaydeail"
})
}else{
//取消了訂單
mui.openWindow({
url:"/weixin/wxPay/faildOrder.jsp?gm_id="+$$("#gm_id").val(),
id:"xufeidengPaydeail"
})
}
});
}
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{
onBridgeReady();
}
});
wx.error(function (res) {
alert("支付狀態:"+res.errMsg);
});
})(mui, document, jQuery);
然後我們將最後邏輯寫在回調界面裏面,也就是第一次簽名那個回調界面
然後得到微信支付成功的數據對象,根據這個對象,然後判斷到底支付成功還是失敗
如支付成功,則可以將自己的業務邏輯寫到這裏面即可
最後,爲大家提供參考,我將demo已經打包,歡迎隨便下載
com,爲後臺,
jar需要的jar包,
wxPay前端
注意:1,微信支付,同一個訂單號,不能頻繁支付而且還不能太長,爲了解決這個問題,所以們在第一次簽名生成預支付訂單的時候,可以將商品id,使用隨機數,然後中間拼一個字母,後面再根據這個字母去獲取我們需要訂單id
2,舊版本的支付類是一個接口,新版本是一個抽象類,所以這裏如果自己去下載的話,需要重新寫一下那個類,不過我這裏是寫好了,下載下來只需要改裏面幾個參數,即可
3,微信支付需要httpclient4.5,httpcore4.3及以上版本,不然會報錯哦
歡迎大家有問題,諮詢,1693940631,有問題的話,也歡迎及時溝通哦,