1.微信支付也有很多種方式,今天我們所介紹的是公眾號支付這種方式。這也是本人第一次進行微信開發,可能有一些地方介紹不到位,請見諒。
2.開發前准備,我們先去https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1將一些工具下載下來,其實也可以自己寫,只不過會有些麻煩,我們可以直接下載來使用。選擇
Java版本【微信支付】API對應的SDK和調用示例的工具下載。
3.生成超鏈接跳轉到我們的充值頁面。
4.前台調用js進行異步發起下單請求。
5.后台接收到前台發起的請求,獲取前台發過來的信息,將信息進行封裝進行統一下單,需要加入到Map的信息有:appid(公眾賬號ID)、mch_id(商戶號)、body(商品描述)、device_info(設備號)、out_trade_no(商戶訂單號)、fee_type(標價幣種)、total_fee(標價金額)、spbill_create_ip(終端IP)、notify_url(通知地址)、trade_type(交易類型)、openid(用戶標識)、nonce_str(隨機字符串);也可以加入其它的,可以參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1,其中的請求參數,其中必填是的屬於必須的,其它的可以視情況而定。調用wxpay.unifiedOrder(map)生成訂單。
6.獲取訂單中的appId、timeStamp、nonceStr、package(值為prepay_id:prepay_id就是指下單時生成的訂單id)、signType的值調用generateSignature(Map)生成簽名,將生成的簽名存放到五生成的訂單中使用json的格式返回到前台中,此時前台可以獲取后台傳過來的值,接着前台調用callpay();在onBridgeReady()中,需要獲取的值有:appId、timeStamp、nonceStr、package、signType、paySign(可能少一個都有可能回調不到微信輸入密碼頁面),當出現微信密碼輸入頁面的時候,我們就成功了一大半了。
7.支付成功后,接着開始處理后台回調,也就是notify_url里面的地址。注意:接收微信支付異步通知回調地址也是有要求:通知url必須為直接可訪問的url,不能攜帶參數。同時,我們可以獲取支付結果,我們們使用里面的參數生成一個本地簽名,同時和結果集里面的簽名比較,一樣我們就可以進行我們的業務處理。處理完成后我們還要給通知一個回應,不然它會每隔一段時間它會再請求。
8.開發結束。
代碼如下:
(1)、充值頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
<meta name="format-detection" content="telephone=no">
<title>微信充值</title>
</head>
<body>
<div class="vbox">
<div class="content">
<ul class="rechange-choose clearfix" id="rechange-choose">
<li class="active"><button class="btn btn-hollow-primary btn-w-per-100" data-value="30"><span class="money">30</span>元</button></li>
<li><button class="btn btn-hollow-primary btn-w-per-100" data-value="50"><span class="money">50</span>元</button></li>
<li><button class="btn btn-hollow-primary btn-w-per-100" data-value="100"><span class="money">100</span>元</button></li>
<li><button class="btn btn-hollow-primary btn-w-per-100" data-value="200"><span class="money">200</span>元</button></li>
</ul>
<div class="rechange-btn">
<button id="rechangeBtn" class="btn btn-primary btn-w-per-100">立即充值</button>
</div>
</div>
</div>
</body>
<script>
(function () {
var prepay_id,
paySign,
appId,
timeStamp,
nonceStr,
packageStr,
signType,
orderNo;
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : appId, //公眾號名稱,由商戶傳入
"timeStamp" : timeStamp, //時間戳數
"nonceStr" : nonceStr , //隨機串
"package":"prepay_id="+prepay_id,
"signType" : 'MD5', //微信簽名方式:
"paySign" : paySign //微信簽名
},
function(res){
var last = JSON.stringify(res); //將JSON對象轉化為JSON字符
if(res.err_msg === "get_brand_wcpay_request:ok" ) {
}
if (res.err_msg === "get_brand_wcpay_request:cancel") {
alert("交易取消");
}
if (res.err_msg === "get_brand_wcpay_request:fail") {
alert("支付失敗");
}
}
);
}
function callpay(){
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();
}
}
/*點擊支付*/
$('#rechangeBtn').on('click', function () {
payPublic();
});
function payPublic() {
var url = "支付處理地址";
Http.post(url, {
type : "add",
oppendId : '${oppendId!}',
total_fee:currentMoney
}, function (data) {
prepay_id = data.prepay_id;
paySign = data.sign;
appId = data.appid;
timeStamp = data.timeStamp;
nonceStr = data.nonce_str;
callpay();
}, function (err) {
});
}
}());
</script>
</html>
(2)、充值處理
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { String type = request.getParameter("type"); String oppendId = request.getParameter("oppendId"); if (type != null) { if (type.equals("toadd")) { return new ModelAndView("weixin/pay/add").addObject("oppendId",oppendId); } else if (type.equals("add")) { /** * 公眾號支付 下單 */ WXPayConfigImpl config =WXPayConfigImpl.getInstance(); WXPay wxpay = new WXPay(config); String totalFree=request.getParameter("total_fee"); String out_trade_no = UtilPramKey.getPriamKey("P");//訂單號 double free =Double.valueOf(totalFree); free=free*100; totalFree=(int)free+""; HashMap<String, String> data = new HashMap<String, String>(); data.put("appid",config.getAppID()); data.put("mch_id",config.getMchID()); data.put("body", "產品描述"); data.put("device_info", "WEB"); data.put("out_trade_no", out_trade_no); data.put("fee_type", "CNY"); data.put("total_fee", totalFree); data.put("spbill_create_ip", "123.12.12.123"); data.put("notify_url", "異步通知地址"); data.put("trade_type", "JSAPI"); data.put("openid", oppendId); data.put("nonce_str", "隨機數");//隨機數 try { Map<String, String> r = wxpay.unifiedOrder(data); JSONObject js222 =new JSONObject(r); Date d =new Date(); if(r.get("return_code").equals("SUCCESS") && r.get("result_code").equals("SUCCESS")){ //業務處理模塊點 }else{ //下單失敗 } String timestr= d.getTime()/1000+""; r.put("timeStamp", timestr); String prepay_id=r.get("prepay_id"); Map<String, String> payMap = new HashMap<String, String>(); payMap.put("appId", config.getAppID()); payMap.put("timeStamp", timestr); payMap.put("nonceStr", r.get("nonce_str")); payMap.put("package", "prepay_id="+prepay_id); payMap.put("signType", "MD5"); String paySign = WXPayUtil.generateSignature(payMap, config.getKey()); r.put("sign", paySign); JSONObject js =new JSONObject(r); writeStringToResponse(js.toString(),response); } catch (Exception e) { e.printStackTrace(); } } } } return null; }
(3)、異步回調處理
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { String re = getNotify(request); writeStringToResponse(re, response); return null; } public String getNotify(HttpServletRequest request) { String result = null; String inlength; String notifyXml = ""; try { while ((inlength = request.getReader().readLine()) != null) { notifyXml += inlength; } } catch (IOException e) {
//獲取XML錯誤 }if (StringUtils.isEmpty(notifyXml)) {
//xml為空 } try { Map<String, String> map = WXPayUtil.xmlToMap(notifyXml); String appid=map.get("appid"); String bank_type=map.get("bank_type"); String cash_fee=map.get("cash_fee"); String device_info=map.get("device_info"); String fee_type=map.get("fee_type"); String is_subscribe=map.get("is_subscribe"); String mch_id=map.get("mch_id"); String nonce_str=map.get("nonce_str"); String openid=map.get("openid"); String out_trade_no=map.get("out_trade_no"); String result_code = map.get("result_code"); String return_code = map.get("return_code"); String sign=map.get("sign"); String time_end=map.get("time_end"); String total_fee=map.get("total_fee"); String trade_type=map.get("trade_type"); String transaction_id=map.get("transaction_id"); Map<String, String> date=new HashMap<>(); date.put("appid", appid); date.put("bank_type", bank_type); date.put("cash_fee", cash_fee); date.put("device_info", device_info); date.put("fee_type", fee_type); date.put("is_subscribe", is_subscribe); date.put("mch_id", mch_id); date.put("nonce_str", nonce_str); date.put("openid", openid); date.put("out_trade_no", out_trade_no); date.put("result_code", result_code); date.put("return_code", return_code); date.put("time_end", time_end); date.put("total_fee", total_fee); date.put("trade_type", trade_type); date.put("transaction_id", transaction_id); WXPayConfigImpl config = WXPayConfigImpl.getInstance(); String localSign=WXPayUtil.generateSignature(date, config.getKey()); if(localSign.equals(sign)){if (result_code.equals("SUCCESS") && return_code.equals("SUCCESS")) { //業務模塊處理點 }else { //簽名失敗 } } catch (Exception e) { //轉化XML錯誤 e.printStackTrace(); } //正確的結果要分上面幾個不一樣返回,不能這樣只返回一個 result = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; return result;
}
(如若哪里存在漏洞請多多提出來,非常感謝)
