前一篇文章的時序圖中說了,app端調用微信支付必須先由后台調用微信后台生成預付單,再構建參數給手機端,而數據的構建要以xml形式,那么看看代碼具體實現吧,代碼已經精簡過了,自己的業務已經除去,精簡的代碼附上注釋是可以直接調用微信后台的
這個是微信所要接受的參數,咱們可以把它構建成一個entity
public class WXPrepay { private static String unifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder"; private static String orderquery = "https://api.mch.weixin.qq.com/pay/orderquery"; private String appid; // 應用ID 微信開放平台審核通過的應用APPID private String mch_id; // 商戶號 微信支付分配的商戶號 private String nonce_str = OrderUtil.CreateNoncestr(); // 隨機字符串 隨機字符串,不長於32位 private String sign; // 簽名 private String body; // 商品描述 商品描述交易字段格式根據不同的應用場景按照以下格式:APP——需傳入應用市場上的APP名字-實際商品名稱,天天愛消除-游戲充值。 private String out_trade_no; // 商戶訂單號 商戶系統內部的訂單號,32個字符內、可包含字母 private String total_fee; // 總金額 訂單總金額,單位為分 private String spbill_create_ip; // 終端IP 用戶端實際ip private String notify_url; // 通知地址 接收微信支付異步通知回調地址,通知url必須為直接可訪問的url,不能攜帶參數。 private String trade_type; // 交易類型 支付類型 private String partnerKey; private String attach; // 附加數據 附加數據,在查詢API和支付通知中原樣返回,該字段主要用於商戶攜帶訂單的自定義數據 private String prepay_id; // 預支付訂單號
controller作為一個restful接口供手機端調用,這個接口可以被ios,安卓等調用,只要微信提供了相應手機端的sdk,那就沒有問題
@RequestMapping("/wxpay") @ResponseBody public LeeJSONResult wxpay(HttpServletRequest request, Model model) { try { // TODO 根據你的業務邏輯計算你需要支付的訂單總額 double totalFee = 1; // 生成交易流水,流水id需要傳給微信,這個流水ID可以作為你的訂單ID,由於我們的業務是多訂單的,流水ID僅僅只是作為表關聯 // 需要保存貨源id,需要的車輛數,訂單id在通知成功后保存 String payFlowId = sid.nextShort(); SpPayFlowCargoSource payFlowCargoSource = new SpPayFlowCargoSource(); payFlowCargoSource.setId(payFlowId); payFlowCargoSource.setFee(new BigDecimal(totalFee)); payFlowCargoSource.setPayStatus(PayStatusEnum.NOT_PAID.value); // 支付狀態:未支付 // 構建微信參數 String spbill_create_ip = request.getRemoteAddr(); // 用戶IP WXPrepay prePay = new WXPrepay(); prePay.setAppid(WXPayContants.appId); prePay.setMch_id(WXPayContants.partnerId); prePay.setBody("demo - 微信支付"); prePay.setOut_trade_no(payFlowId); // 這里要注意,微信支付是以分為單位,而系統是以元為單位,所以需要金額轉換。題外話:曾經看到過京東和蘇寧都有類似的bug,就是一個台手機和耳機都是要十幾元,估計是金額轉換出的問題 prePay.setTotal_fee(String.valueOf(new BigDecimal(totalFee).multiply(new BigDecimal(100)).intValue())); // prePay.setTotal_fee("1"); prePay.setSpbill_create_ip(spbill_create_ip); prePay.setNotify_url(notifyUrl); // 異步通知,這個下篇文章講 prePay.setTrade_type("APP"); prePay.setAttach(payFlowId); // 存入交易流水id prePay.setPartnerKey(WXPayContants.partnerKey); // 獲取預支付訂單號 String prepayId = prePay.submitXmlGetPrepayId(); logger.info("獲取的預支付訂單是:" + prepayId); if (prepayId != null && prepayId.length() > 10) { // 生成微信支付參數,此處拼接為完整的JSON格式,符合支付調起傳入格式 String jsParam = WXPay.createPackageValue(WXPayContants.appId, WXPayContants.partnerKey, prepayId); System.out.println("jsParam=" + jsParam); // 此處可以添加訂單的處理邏輯 model.addAttribute("jsParam", jsParam); logger.info("生成的微信調起JS參數為:" + jsParam); payFlowCargoSource.setPrepayId(prepayId); spPayFlowCargoSourceService.savePayFlow(payFlowCargoSource); return LeeJSONResult.ok(); } else { return LeeJSONResult.errorMsg("微信支付接口調用失敗"); } } catch (Exception e) { e.printStackTrace(); return LeeJSONResult.errorException(e.getMessage()); } }
需要注意的是,微信后台接受的參數都是xml格式的,所以咱們的bean需要轉換為xml再傳給微信,最后調用成功,微信會封裝一個xml傳過來,咱們同樣再解析一下獲取預付單號就OK了
public String submitXmlGetPrepayId() { // 創建HttpClientBuilder HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // HttpClient CloseableHttpClient closeableHttpClient = httpClientBuilder.build(); HttpPost httpPost = new HttpPost(unifiedorder); String xml = getPackage(); StringEntity entity; try { entity = new StringEntity(xml, "utf-8"); httpPost.setEntity(entity); HttpResponse httpResponse; // post請求 httpResponse = closeableHttpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); if (httpEntity != null) { // 打印響應內容 String result = EntityUtils.toString(httpEntity, "UTF-8"); System.out.println(result); // 過濾 result = result.replaceAll("<![CDATA[|]]>", ""); String prepay_id = Jsoup.parse(result).select("prepay_id").html(); this.prepay_id = prepay_id; if (prepay_id != null) { return prepay_id; } } // 釋放資源 closeableHttpClient.close(); } catch (Exception e) { e.printStackTrace(); } return prepay_id; }
其實不用這樣的方式也行,把bean通過json的方式封裝,最后讓它自動轉為xml,也是沒有問題的,或者直接使用 restful webservice標准協議來接受xml和發送xml