近期,公司內部移動辦公系統要實現微信支付模塊,用於員工繳費,微信支付頁面用h5開發,嵌入移動辦公系統,後臺是java。
大致流程如下:
1.前端頁面生成訂單(確定支付金額、訂單詳情,此步驟根據業務而定)
2.調用後臺預支付接口,該接口需要請求微信統一支付接口,拿到返回鏈接,直接將該鏈接(深度鏈技術,可以理解爲微信的協議,用於喚醒微信)返回給前端
3.前端拿到連接後,直接open即可,就會喚醒微信。
4.如果支付成功,微信會回調後臺提供的支付通知接口,次接口接收微信回調和修改本地訂單狀態。
代碼如下
/** 預支付
* 發起支付
*/
@SuppressWarnings("unchecked")
@PostMapping(value = "/pay")
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public Map<String, String> pay(HttpServletRequest request,@RequestBody Map<String,Object> param) {
String userCode = String.valueOf(String.valueOf(param.get("userCode")));
String ym = String.valueOf(String.valueOf(param.get("ym")));
Order order = orderMapper.selectOrderByThisYear(ym,userCode);
Map<String,String> map = new HashMap<>();
map.put("result_code", "fail");
if(Objects.isNull(order)) {
map.put("msg", "未查詢到可支付的訂單,無需支付");
return map;
}
if(order.getStatus() == 3 || order.getStatus() == 2) { //支付成功
map.put("msg", "訂單已經完成,無需重複支付");
return map;
}
EntityWrapper<Order> wrapper = new EntityWrapper<>();
wrapper.eq("user_id", userCode).eq("period", ym);
Order entity = new Order();
entity.setUserId(userCode);
entity.setOrderNo("");
entity.setStatus(1);
int flag = 0;
if(order.getStatus() == 0 || order.getStatus() == 4) {//交易關閉、取消
flag = 1;
}
if(!Objects.isNull(order.getCreateTime()) && order.getStatus() == 1 && System.currentTimeMillis() - order.getCreateTime().getTime() >= 5 * 60 * 1000 ) {//超時
flag = 2;
}
if(flag != 0) {
orderMapper.update(entity, wrapper);
orderMapper.updateDateTime(ym,userCode);
if(flag == 1) {
map.put("msg", "訂單異常,請重新發起支付");
}else if(flag == 2) {
map.put("msg", "訂單超時,請重新發起支付");
}
return map;
}
//更新訂單創建時間和生成訂單號
entity.setCreateTime(new Date());
entity.setOrderNo(System.currentTimeMillis() + "");
orderMapper.update(entity, wrapper);
SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
String currTime = PayToolUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayToolUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
packageParams.put("appid", WXConfig.appid);
packageParams.put("mch_id", WXConfig.mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", order.getDesc());
packageParams.put("out_trade_no", entity.getOrderNo());
Double totalFee = order.getPayment().doubleValue() * 100;
packageParams.put("total_fee", totalFee.intValue() + ""); // 價格的單位爲分
packageParams.put("spbill_create_ip",getIP(request));
packageParams.put("notify_url", WXConfig.notify_url);
packageParams.put("trade_type", WXConfig.tradeType);
String sign = PayToolUtil.createSign("UTF-8", packageParams, WXConfig.key);
packageParams.put("sign", sign);
String requestXML = PayToolUtil.getRequestXml(packageParams);
String resXml = HttpUtil.postData(WXConfig.unifiedorder_url,
requestXML);
try {
map = XMLUtil.doXMLParse(resXml);
/*System.out.println(resXml);*/
if(!map.get("return_code").equals("FAIL")) {
//確認支付過後跳的地址,需要經過urlencode處理,必須爲h5支付綁定的域名
String urlString = URLEncoder.encode("http:\\xxxxx.com/index.html#/success?userCode=" + userCode, "GBK");//該地址爲支付成功後回調的頁面,該頁面需要輪訓訂單詳情接口;;判斷訂單狀態
String mweb_url = map.get("mweb_url") + "&redirect_url=" + urlString;
map.clear();
map.put("result_code", "success");
//mweb_url就是喚醒微信的深度連
map.put("mweb_url", mweb_url);
}else {
map.put("result_code", "fail");
}
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
回調方法
/**
* 異步回調
*/
@PostMapping(value = "/notify")
public Boolean notify(@RequestBody String notifyData) throws Exception {
try {
Map<String,String> doXMLParse = XMLUtil.doXMLParse(notifyData);
String string = doXMLParse.get("out_trade_no");
EntityWrapper<Order> wrapper = new EntityWrapper<>();
wrapper.eq("order_no", string);
Order order = orderService.selectOne(wrapper);
order.setStatus(3);
orderMapper.update(order, wrapper);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
效果展示