微信公眾號支付 (三、配置JS-SDK)
4.1微信JS-SDK是微信公眾平臺面向網頁開發者提供的基於微信內的網頁開發工具包,通過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特有的功能。
JS-SDK使用步驟:
1.登入微信公眾號平臺,進入公眾號設定,設定JS介面安全域名。支付介面要確保支付目錄在支付安全域名下。必須為1級域名
3.所有需要使用JS-SDK的頁面必須先注入配置資訊,否則將無法呼叫。
wx.config({ debug: true, // 開啟除錯模式,呼叫的所有api的返回值會在客戶端alert出來,若要檢視傳入的引數,可以在pc端開啟,引數資訊會通過log打出,僅在pc端時才會列印。 appId: '', // 必填,公眾號的唯一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名,見附錄1 jsApiList: [] // 必填,需要使用的JS介面列表,所有JS介面列表見附錄2 });
重點在於簽名。附錄1中詳細的解釋瞭如何獲取jsapi_ticket,有效時間為7200,通過access_token來獲取。公眾號調取jsapi_ticket有次數上限所以
要全域性快取做判斷。只給出方法獲取和判斷jsapi_ticket的方法。
連線:”https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=“
程式碼如下:
/* * 獲取jsSDK配置引數 */ public static Map<String, String> getJsSDKConfig(String url) throws Exception { String jsApiTicket = getJsApiTicket(); if (!jsApiTicket.equals("") && jsApiTicket != null) { return sign(jsApiTicket, url); } else { throw new Exception("獲取到的jsApiTicket為空"); } } /* * 獲取微信jsApiTicket */ public static String getJsApiTicket() throws Exception { if (jsApiTicket == null || System.currentTimeMillis() >= jsApiTicketExpiresTime) { return getNewJsApiTicket(); } else { return jsApiTicket; } } /* * 重新整理jsApiTicket */ public static String getNewJsApiTicket() throws Exception { long start = System.currentTimeMillis(); String accessToken = getAccessToken(); if (!accessToken.equals("") && accessToken != null) { String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi"; String result = null; try { result = Http.sendGet(url, "utf-8", 1000); } catch (Exception e) { e.printStackTrace(); throw new Exception("發起網路請求出錯"); } if (!result.equals("") && result != null) { JSONObject json = JSON.parseObject(result); if (json.getString("ticket") != null) { jsApiTicket = json.getString("ticket"); jsApiTicketExpiresTime = System.currentTimeMillis() + (json.getLongValue("expires_in") * 1000) - 120 * 1000; System.out.println("呼叫獲取jsApiTicket介面耗時-->" + (System.currentTimeMillis() - start) + "毫秒"); return jsApiTicket; } else { System.out.println("呼叫獲取jsApiTicket介面失敗-->" + result); throw new Exception(result); } } else { throw new Exception("呼叫獲取jsApiTicket介面返回資料為空"); } } else { throw new Exception("獲取到的accessToken為空"); } } /* * 獲取基本AccessToken */ public static String getAccessToken() throws Exception { if (accessToken == null || System.currentTimeMillis() >= accessTokenExpiresTime) { return getNewAccessToken(); } else { long expires = System.currentTimeMillis() - lastCheckaccessTokenTime; // 5分鐘檢查一次accessToken是否有效 if (expires < 300000 || checkAccessToken()) { return accessToken; } else { return getNewAccessToken(); } } } /* * 獲取最新accessToken */ public static String getNewAccessToken() throws Exception { long start = System.currentTimeMillis(); String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WeiXinUtils.APP_ID + "&secret=" + WeiXinUtils.AppSecret; String result = null; try { result = Http.sendGet(url, "utf-8", 1000); } catch (Exception e) { e.printStackTrace(); throw new Exception("發起網路請求出錯"); } if (!result.equals("") && result != null) { JSONObject json = JSON.parseObject(result); if (json.getString("access_token") != null) { accessToken = json.getString("access_token"); accessTokenExpiresTime = System.currentTimeMillis() + (json.getLongValue("expires_in") * 1000) - 120 * 1000; lastCheckaccessTokenTime = System.currentTimeMillis(); System.out.println("呼叫獲取公眾號accessToken介面耗時-->" + (System.currentTimeMillis() - start) + "毫秒"); return accessToken; } else { System.out.println("呼叫獲取公眾號accessToken介面失敗-->" + result); throw new Exception(result); } } else { throw new Exception("呼叫獲取公眾號accessToken介面返回資料為空"); } } /* * 獲取基本AccessToken */ public static String getAccessToken() throws Exception { if (accessToken == null || System.currentTimeMillis() >= accessTokenExpiresTime) { return getNewAccessToken(); } else { long expires = System.currentTimeMillis() - lastCheckaccessTokenTime; // 5分鐘檢查一次accessToken是否有效 if (expires < 300000 || checkAccessToken()) { return accessToken; } else { return getNewAccessToken(); } } }
獲取到jsapi_ticket就可以生成簽名。
簽名由jsapi_ticket,noncestr,timestamp,url組成
程式碼如下:
生成字串和時間戳的方法/* * 呼叫微信JSSDK文件必須生成簽名 * * 詳情請查閱微信API */ public static Map<String, String> sign(String jsapi_ticket, String url) { Map<String, String> ret = new HashMap<String, String>(); String nonce_str = create_nonce_str(); String timestamp = create_timestamp(); String string1; String signature = ""; // 注意這裡引數名必須全部小寫,且必須有序 string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "×tamp=" + timestamp + "&url=" + url; System.out.println(string1); try { MessageDigest crypt = MessageDigest.getInstance("SHA-1"); crypt.reset(); crypt.update(string1.getBytes("UTF-8")); signature = byteToHex(crypt.digest()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } ret.put("url", url); ret.put("jsapi_ticket", jsapi_ticket); ret.put("nonceStr", nonce_str); ret.put("timestamp", timestamp); ret.put("signature", signature); return ret; }
程式碼如下:
/*
* 微信JSSDK引數 隨機字串
*/
public static String create_nonce_str() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/*
* 微信JSSDK引數 時間戳
*/
public static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
填寫config介面引數。chooseWXPay 為微信支付介面。如需微信其他介面更改jsSpiList的引數即可。
程式碼如下:
Map<String, String> signData = WeiXinUtil.getJsSDKConfig(url);
if (signData != null) {
Map<String,Object> map = new HashMap<String, Object>();
// debug引數為除錯模式,開啟時會返回引數,除錯時開啟
map.put("debug", false);
map.put("appId",WeiXinUtils.APP_ID);
map.put("timestamp", signData.get("timestamp"));
map.put("nonceStr", signData.get("nonceStr"));
map.put("signature",signData.get("signature"));
map.put("jsApiList", "['chooseWXPay']");
// 寫入request 前端頁面取出
Struts2Utils.getRequest().setAttribute("wxconfig", JSON.toJSON(map));
}
前端取引數。wx.config(<%=request.getAttribute("wxconfig")%>);
配置好js後。回到微信支付方法中。返回SUCCESS後獲取到prepay_id。配置微信支付介面。
程式碼如下:
SortedMap<String, String> par = new TreeMap<String, String>();
par.put("appId", WeiXinUtils.APP_ID);
par.put("timeStamp", WeiXinUtil.create_timestamp());
par.put("nonceStr", WeiXinUtil.create_nonce_str());
par.put("package", "prepay_id=" + resultMap.get("prepay_id"));
par.put("signType", "MD5");
String signSuccess = Sign.sign(par);
par.put("paySign", signSuccess);
System.out.println(signSuccess);
System.out.println("prepay_id=" + resultMap.get("prepay_id"));
// 將SortedMap轉為json 前臺取引數
Struts2Utils.renderJson(par);
此時程式碼都已經結束。最後一個就是配置微信支付路徑。
在商戶平臺配置,比如說你的路徑是:http://www.asdf.com/abc/pay/abc 那你應該填為:http://www.asdf.com/abc/pay
這是微信支付公眾號的連線(裡面介紹了微信中需要配置的域名等):https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3