1. 程式人生 > >微信支付——呼叫微信客戶端支付之【服務端】開發詳解

微信支付——呼叫微信客戶端支付之【服務端】開發詳解

最近準備上網頁的微信支付,大家可以參考後續教程:

2015-09-12 更新:

因微信支付已經升級到V3版本,請大家參考官網的幫助文件。

之前一篇提到微信支付的開發過程,寫得有點亂,現在重新整理一下。

好了,說說到底該怎樣一步一步分享處理。


先把服務端demo的程式碼整理到我們的服務端中(注意,此程式碼的編碼格式是GBK,直接複製過去註釋都會變亂碼。可用文字檔案開啟後再複製過去)。處理完成後啟動;且訪問:http://localhost:8080/WeiXinpay/

會得到以下檢視:

-------------------------------------------------------------------------------------------------------------

點選連結:

0OK wxd930ea5d5a258f4f 454cecc4829279e64d624cd8a8c9ddf1 Sign=WXPay 1900000109 120100001014112819a3561c0c02c882 eb139e44b8df8ce01b386f7c016defe5b95517791417104896

-------------------------------------------------------------------------------------------------------------


返回控制檯可以得到以下檢視:


好了,到這裡,算是成功了一小步了(哈哈哈哈哈哈 yy一下)。

你也許會問,這些引數到底是作什麼用的?更可悲的是,居然沒有服務端的介面文件。

唯有先看手頭上有的資料了。開啟《【微信APP支付】介面文件V1.2_For_Android.pdf》

裡面有提到微信支付的呼叫步驟:

1、獲取  access_token

2、生成預支付訂單

3、調起微信支付

下面說說這幾個步驟:

1、access_token的獲取

因為access_token的獲取有請求頻的限制,只能固化到資料庫中了。這個不是難題。

2、生成預支付訂單

在微信支付android的介面文件開頭有提到:

注意:appsecret、appkey、partnerkey 不應硬編碼到客戶端程式中,建議需要用到這三個欄位的過程都在伺服器端完成


故此過程所有的資訊全部在服務端生成。那麼問題來了?挖掘機.... kao, 應該是,如何生成?

在翻看服務端的demo中,有jsp資料夾。開啟一看,都幾乎可以直接搬運使用了。

實現該過程的檔案:payRequest.jsp

如何在JAVA中實現上面jsp的請求?專案中用到了Spring MVC,程式碼如下:

@Controller
@RequestMapping("/weixin/")
public class WeiXinPayController extends ResponsePage  {

	private Logger log = Logger.getLogger(WeiXinPayController.class);
	
	@RequestMapping("weixin.do")
	public String doWeinXinRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
		Map<Object,Object> resInfo = new HashMap<Object, Object>();
		//接收財付通通知的URL
		String notify_url = "http://127.0.0.1:8180/tenpay_api_b2c/payNotifyUrl.jsp";

		//---------------生成訂單號 開始------------------------
		//當前時間 yyyyMMddHHmmss
		String currTime = TenpayUtil.getCurrTime();
		//8位日期
		String strTime = currTime.substring(8, currTime.length());
		//四位隨機數
		String strRandom = TenpayUtil.buildRandom(4) + "";
		//10位序列號,可以自行調整。
		String strReq = strTime + strRandom;
		//訂單號,此處用時間加隨機數生成,商戶根據自己情況調整,只要保持全域性唯一就行
		String out_trade_no = strReq;
		//---------------生成訂單號 結束------------------------

		PackageRequestHandler packageReqHandler = new PackageRequestHandler(request, response);//生成package的請求類 
		PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);//獲取prepayid的請求類
		ClientRequestHandler clientHandler = new ClientRequestHandler(request, response);//返回客戶端支付引數的請求類
		packageReqHandler.setKey(ConstantUtil.PARTNER_KEY);

		int retcode ;
		String retmsg = "";
		String xml_body = "";
		//獲取token值 
		
		String token = AccessTokenRequestHandler.getAccessToken();
		
		log.info("獲取token------值 " + token);
		
		if (!"".equals(token)) {
			//設定package訂單引數
			packageReqHandler.setParameter("bank_type", "WX");//銀行渠道
			packageReqHandler.setParameter("body", "測試"); //商品描述   
			packageReqHandler.setParameter("notify_url", notify_url); //接收財付通通知的URL  
			packageReqHandler.setParameter("partner", ConstantUtil.PARTNER); //商戶號    
			packageReqHandler.setParameter("out_trade_no", out_trade_no); //商家訂單號   
			packageReqHandler.setParameter("total_fee", "1"); //商品金額,以分為單位  
			packageReqHandler.setParameter("spbill_create_ip",request.getRemoteAddr()); //訂單生成的機器IP,指使用者瀏覽器端IP  
			packageReqHandler.setParameter("fee_type", "1"); //幣種,1人民幣   66
			packageReqHandler.setParameter("input_charset", "GBK"); //字元編碼

			//獲取package包
			String packageValue = packageReqHandler.getRequestURL();
			resInfo.put("package", packageValue);
			
			log.info("獲取package------值 " + packageValue);

			String noncestr = WXUtil.getNonceStr();
			String timestamp = WXUtil.getTimeStamp();
			String traceid = "";
			////設定獲取prepayid支付引數
			prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
			prepayReqHandler.setParameter("appkey", ConstantUtil.APP_KEY);
			prepayReqHandler.setParameter("noncestr", noncestr);
			prepayReqHandler.setParameter("package", packageValue);
			prepayReqHandler.setParameter("timestamp", timestamp);
			prepayReqHandler.setParameter("traceid", traceid);

			//生成獲取預支付簽名
			String sign = prepayReqHandler.createSHA1Sign();
			//增加非參與簽名的額外引數
			prepayReqHandler.setParameter("app_signature", sign);
			prepayReqHandler.setParameter("sign_method",
					ConstantUtil.SIGN_METHOD);
			String gateUrl = ConstantUtil.GATEURL + token;
			prepayReqHandler.setGateUrl(gateUrl);

			//獲取prepayId
			String prepayid = prepayReqHandler.sendPrepay();
			
			log.info("獲取prepayid------值 " + prepayid);
			
			//吐回給客戶端的引數
			if (null != prepayid && !"".equals(prepayid)) {
				//輸出引數列表
				clientHandler.setParameter("appid", ConstantUtil.APP_ID);
				clientHandler.setParameter("appkey", ConstantUtil.APP_KEY);
				clientHandler.setParameter("noncestr", noncestr);
				//clientHandler.setParameter("package", "Sign=" + packageValue);
				clientHandler.setParameter("package", "Sign=WXPay");
				clientHandler.setParameter("partnerid", ConstantUtil.PARTNER);
				clientHandler.setParameter("prepayid", prepayid);
				clientHandler.setParameter("timestamp", timestamp);
				//生成簽名
				sign = clientHandler.createSHA1Sign();
				clientHandler.setParameter("sign", sign);

				xml_body = clientHandler.getXmlBody();
				resInfo.put("entity", xml_body);
				retcode = 0;
				retmsg = "OK";
			} else {
				retcode = -2;
				retmsg = "錯誤:獲取prepayId失敗";
			}
		} else {
			retcode = -1;
			retmsg = "錯誤:獲取不到Token";
		}
		
		resInfo.put("retcode", retcode);
		resInfo.put("retmsg", retmsg);
		String strJson = JSON.toJSONString(resInfo);
		return responseAjax(request, strJson);
	}
	
}

好了此時,客戶端需要的引數都已經可以通過請求:http://localhost:8080/WeiXinpay/weixin/weixin.do 來獲取

3、調起微信支付

這步就不需要我們服務端處理了。客戶端的兄弟,來接力。

最後,微信回撥:可以參考jsp資料夾中的payNotifyUrl.jsp來處理,處理過程和上面第二步差不多。