支付篇—微信掃碼支付
應用場景:
商戶根據商品資訊,生成商品二維碼,使用者通過微信掃一掃功能掃描該二維碼,完成支付。
支付模式:
現在微信掃碼支付支援兩種模式。
模式一需要商戶必須先在公眾平臺後臺設定支付回撥URL。URL實現的功能:接收使用者掃碼後微信支付系統回撥的productid和openid。
模式二與模式一相比,流程更為簡單,不依賴設定的回撥支付URL。商戶後臺系統先呼叫微信支付的統一下單介面,微信後臺系統返回連結引數code_url,商戶後臺系統將code_url值生成二維碼圖片,使用者使用微信客戶端掃碼後發起支付。注意:code_url有效期為2小時,過期後掃碼不能再發起支付。
我使用的模式二,也就是微信的統一下單介面。該模式的業務流程時序圖如下:
業務流程說明:
(1)商戶後臺系統根據使用者選購的商品生成訂單。
(2)使用者確認支付後呼叫微信支付【統一下單API】生成預支付交易;
(3)微信支付系統收到請求後生成預支付交易單,並返回交易會話的二維碼連結code_url。
(4)商戶後臺系統根據返回的code_url生成二維碼。
(5)使用者開啟微信“掃一掃”掃描二維碼,微信客戶端將掃碼內容傳送到微信支付系統。
(6)微信支付系統收到客戶端請求,驗證連結有效性後發起使用者支付,要求使用者授權。
(7)使用者在微信客戶端輸入密碼,確認支付後,微信客戶端提交授權。
(8)微信支付系統根據使用者授權完成支付交易。
(9)微信支付系統完成支付交易後給微信客戶端返回交易結果,並將交易結果通過簡訊、微信訊息提示使用者。微信客戶端展示支付交易結果頁面。
(10)微信支付系統通過傳送非同步訊息通知商戶後臺系統支付結果。商戶後臺系統需回覆接收情況,通知微信後臺系統不再發送該單的支付通知。
(11)未收到支付通知的情況,商戶後臺系統呼叫【查詢訂單API】。
(12)商戶確認訂單已支付後給使用者發貨。
整個支付流程精簡下來主要就是2點:
①呼叫介面獲取支付二維碼並顯示出來
②微信回撥介面,通知支付結果
針對這2點我寫了兩個方法,一個是獲取二維碼,一個是提供給微信的支付結果回撥介面。
開發過程中需要用到微信提供的jar包,maven地址如下:
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version> 0.0.3</version>
</dependency>
/**
* 該類為配置類,主要是關於公眾號和商戶的一些配置資訊抽離出來
* @author
*
* 2017年11月17日
*/
public class MyConfig implements WXPayConfig{
//公眾賬號ID
public String getAppID() {
return "wx11bd61834b0d57ef";
}
public int getHttpConnectTimeoutMs() {
return 8000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
//商戶祕鑰
public String getKey() {
return "1234567890";
}
//商戶號
public String getMchID() {
return "1234567890";
}
}
/**
* 獲得微信支付二維碼
* @param req
* @param resp
* @throws IOException
*/
@RequestMapping(value = "/getWxPayCode")
public void getWxPayCode(HttpServletRequest req, HttpServletResponse resp)
throws IOException{
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
String out_trade_no = DateUtil.dateToStr(new Date(), "yyyyMMddHHmmss");
Map<String, String> data = new HashMap<String, String>();
data.put("body", "填寫商品名稱"); //商品描述
data.put("out_trade_no", out_trade_no); //商戶訂單號,不可重複
data.put("device_info", ""); //裝置號
data.put("fee_type", "CNY"); //標價幣種(預設人民幣)
data.put("total_fee", "1"); //標價金額,單位:分
data.put("spbill_create_ip", "127.0.0.1"); //終端IP
data.put("notify_url", "https://www.baidu.com/getWxPayNotify.action"); //通知地址,必須是外網能訪問的地址
data.put("trade_type", "NATIVE"); // 此處指定為掃碼支付
data.put("product_id", "12"); //商品ID
Map<String, String> respnoe = null;
try {
respnoe = wxpay.unifiedOrder(data);
String codeUrl = respnoe.get("code_url");
System.out.println("返回的二維碼url:" + codeUrl);
} catch (Exception e) {
e.printStackTrace();
}
resp.setContentType("text/html;charset=UTF-8");
OutputStream os = resp.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(respnoe.toString());
oos.flush();
oos.close();
os.close();
}
這樣就完成了微信支付的二維碼請求。在進行請求的時候,微信是以xml格式的資料進行的請求,不過微信已經在提供的jar包裡進行了封裝,所以我們就不必再進行資料封裝了。
商戶後臺將該二維碼地址返回給手機端,手機端通過zxing工具包,將該地址轉換成二維碼供使用者掃碼支付。當用戶掃碼支付完成後,微信後臺會回撥我們提供給微信後臺的介面,就是剛才我們設定的notify_url引數,這裡一定要記得是外網能夠訪問到的地址!
下面是處理微信回撥的方法:
/**
* 獲得微信支付通知回撥結果
* @param req
* @param resp
* @throws Exception
* @throws IOException
*/
@RequestMapping(value = "/getWxPayNotify")
public void getWxPayNotify(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String notifyData = "";
try {
InputStream is = req.getInputStream();
StringBuffer sb = new StringBuffer();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
is.close();
notifyData = sb.toString();
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 轉換成map
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
logger.info("支付成功");
// 簽名正確
// 進行處理。
// 注意特殊情況:訂單已經退款,但收到了支付結果成功的通知,不應把商戶側訂單狀態從退款改成支付成功
}
else {
// 簽名錯誤,如果資料裡沒有sign欄位,也認為是簽名錯誤
logger.error("支付失敗");
}
logger.info("微信支付返回的通知為:" + notifyMap);
resp.setContentType("text/html;charset=UTF-8");
OutputStream os = resp.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(notifyData);
oos.flush();
oos.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
具體的處理方法這裡我就不寫了,微信回撥的時候需要驗證簽名是否正確,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止資料洩漏導致出現“假通知”,造成資金損失。另外當微信回撥我們的介面的時候,我們需要給微信後臺返回應答,已經接收到回撥,不然微信將會重新發起通知(通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)
另外當客戶端一定時間內沒有接收到微信後臺的回撥時,也可以主動查詢訂單狀態,跟統一下單差不多,只是把下單改為查詢
Map<String, String> resp = wxpay.orderQuery(data);
如需轉載,請註明出處!