1. 程式人生 > >Java-Web微信網頁支付開發流程以及各種坑

Java-Web微信網頁支付開發流程以及各種坑

微信網頁支付流程概覽

  • 生成Oauth2.0授權連結獲得code
  • 使用code獲得使用者資訊(OpenId)
  • 向微信統一下單介面提交訂單獲得PrepayID
  • 在JS頁面中向用戶發起支付請求
  • 使用者輸入支付密碼完成支付

使用weixin-java-tools工具可以快速完成以下開發


1.生成Oauth2.0授權連結

為什麼要生成授權連結:當要為某使用者提交支付訂單時必須要得到該使用者的OpenId(OpenId是加密後的微信帳號,同一個使用者在不同的公眾號內的該值是不同的)
而獲得使用者的OpenId,就需要使用者對你的公眾賬號進行授權(可以不需要關注),使用者授權之後微信將會發送一個code到你提供的頁面(redirect_uri)

你需要提供和關心的內容

引數 說明
appid 公眾號的唯一標識
redirect_uri 授權後重定向的回撥連結地址,請使用urlencode對連結進行處理
scope 應用授權作用域,snsapi_base (不彈出授權頁面,直接跳轉,只能獲取使用者openid),snsapi_userinfo (彈出授權頁面,可通過openid拿到暱稱、性別、所在地。並且,即使在未關注的情況下,只要使用者授權,也能獲取其資訊)

使用開源的“weixin-java-tools”可以方便地生成授權連結:

//首先配置你的公眾號資訊
WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();
config.setAppId("你的APPID");
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(config);
//輕鬆地拼接一個Oauth2.0授權連結
System.out.println(wxMpService.oauth2buildAuthorizationUrl("你的redirect_uri"
,"snsapi_userinfo","傳遞一個state引數(可為null)"));

例如這裡redirect_uri填寫: http://mytest.com/test/pay
執行後會生成類似如下連結:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx19c7c9777756d0cc&redirect_uri=http%3A%2F%2Fmytest.com%2Ftest%2Fpay&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
上述連結需要你放置在你的微信公眾號或者提交訂單時的H5頁面中,引導使用者點選進行授權。從而可以進行以後的支付操作。

使用者在該連結中選擇授權您的公眾號之後,微信會立即傳送code值和state(你自己設定的欄位)到你的redirect_uri中:
http://mytest.com/test/pay?code=CODE&state=STATE

因此你的redirect_uri應當指向一個服務而不是一個靜態頁面,這裡使用tomcat+Java Servlet實現後續步驟

本章節會遇到的坑:
1.實際測試點選授權頁面時提示redirect_uri引數錯誤
這裡需要在微信公眾號後臺-介面許可權-網頁授權獲取使用者基本資訊-修改 中新增你的redirect_uri的域名,注意是域名哦!此時會獲得一個授權檔案(txt)需要將該檔案放置到你站點的根目錄下。

2.使用code獲得使用者資訊(OpenId)

上一步結束之後我們已經在Servlet中拿到code值,接下來我們需要去請求Access_Token和使用者的OpenId(關鍵是要得到OpenId)(注意此處的Access_Token不同於微信開發中的Access_Token並不混用也不會互相重新整理。code的有效期限為5分鐘,且每申請一次只能使用一次)

//同樣需要先配置公眾號資訊,但本次要求的引數為4個
WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage(); 
config.setAppId("你的APPID");
config.setSecret("你的APPSECRET");
config.setPartnerId("你的商戶ID");
config.setPartnerKey("你的商戶SecretKey");
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(config);
//使用已經得到的code獲取AccessToken和OpenId
WxMpOAuth2AccessToken wxMpOAuth2AccessToken= null;
WxMpUser wxMpUser = null;
try {
wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
//下面的方法會獲得使用者的詳細資訊,本例用不到但是如有需要之前的步驟也是這麼進行
wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, null); 
        } catch (WxErrorException e) {
            e.printStackTrace();
        }
String Openid=wxMpOAuth2AccessToken.getOpenId();
System.out.println("已經獲得獲得使用者Openid:"+ Openid);

3.向微信統一下單介面提交訂單

在下單之前我們需要組織引數

官方:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
下述例項將只進行關鍵必要引數的設定

WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
//由於我們前面的config配置 因此各種ID會被預設配置進去,NonceStr生成方法是System.currentTimeMillis()也已經預設新增。MD5簽名加密問題也無需考慮,其內建的簽名方法已經搞定。
orderRequest.setBody("商品描述");
orderRequest.setOutTradeNo("訂單ID"); //商戶唯一訂單號
orderRequest.setTotalFee(1);//價格單位為‘分’
orderRequest.setOpenid(Openid);
orderRequest.setNotifyURL("http://www.weixin.qq.com/wxpay/pay.php");//微信回撥地址 使用者支付成功後微信會向該介面推送結果
orderRequest.setTradeType("JSAPI");//不要修改
orderRequest.setSpbillCreateIp("172.168.1.1");//當前使用者的IP
WxMpPayService wxMpPayService = wxMpService.getPayService();
String mypackage="";
String nonceStr="";
try {           mypackage=""+wxMpPayService.getPayInfo(orderRequest).get("package");
nonceStr=""+wxMpPayService.getPayInfo(orderRequest).get("nonceStr");
System.out.println("prepayID:"+mypackage);
     } catch (WxErrorException e) {
            e.printStackTrace();
     }

我們現在已經在微信上建立了一筆訂單,並且返回我們需要的關鍵資訊為package(包含prepayId),當然nonce_str是之前weixin-java-tools生成的,此時微信也會返回該值直接取得即可。

萬事俱備,只欠從介面向用戶發起支付請求

4.在JS頁面中向用戶發起支付請求

我們需要準備一個JSP請求支付的頁面,並且在Servlet向其轉發剛才獲取的關鍵訂單資訊

<%@ page import="java.sql.Timestamp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title><link rel="stylesheet" href="js/weui/css/weui.min.css" type="text/css">
<script type="text/javascript" src="js/weui/js/zepto.min.js"></script>
<script type="text/javascript" src="js/weui/js/jweixin.js"></script>
<script type="text/javascript" src="js/weui/js/weui.min.js"></script>
</head>

<body ontouchstart>
<div>
    <div class="page">
        <a href="javascript:;" class="weui-btn weui-btn_primary" id="btnPay">立即支付</a>
    </div>
</div>
<script type="text/javascript">
    $("#btnPay").on('click',function(){
        console.log("TEST");
    });
function onBridgeReady(){
        WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                    "appId" : "${APPID}",     //公眾號名稱,由商戶傳入
                    "timeStamp":"${TIMEST}",         //時間戳,自1970年以來的秒數
                    "nonceStr" : "${NOCESTR}", //隨機串
                    "package" : "${PREPAYID}",
                    "signType" : "MD5",         //微信簽名方式:
                    "paySign" : "${MYMD5}" //微信簽名
                },
                function(res){
                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {}
                }
        );
    }
    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{
        alert('呼叫WeiXin支付');
        onBridgeReady();
    }
</script>
</body>
</html>

本章節會遇到的坑:
1.實際測試時頁面提示當前URL頁面未註冊
這裡需要在微信公眾號後臺-微信支付-授權測試目錄裡面新增你當前支付JSP頁面的目錄。
比如我的支付頁面是 http://a.com/test/pay/pay.jsp
那麼我就需要填寫 http://a.com/test/pay/
然而這裡有一個坑就是,在實際發起支付的時候他會檢查你發起支付的路徑是什麼,也就是說如果你如果之前使用servler獲取資料後向JSP轉發資料的話,那麼使用者在支付的時候url就不是http://a.com/test/pay/pay.jsp
而可能變成了http://a.com/test/pay?key=value
如此一來你填寫的支付測試路徑就出現了錯誤。因此需要修改測試路徑為 http://a.com/test/ 即可通過。

至此使用者在微信中訪問第一步的授權連結後,會提示授權,然後跳轉到JSP進行支付

歡迎到我的部落格裡坐坐 http://www.xiaomilu.top