app端微信支付(二) - 生成预付单
?前一篇文章的時(shí)序圖中說(shuō)了,app端調(diào)用微信支付必須先由后臺(tái)調(diào)用微信后臺(tái)生成預(yù)付單,再構(gòu)建參數(shù)給手機(jī)端,而數(shù)據(jù)的構(gòu)建要以xml形式,那么看看代碼具體實(shí)現(xiàn)吧,代碼已經(jīng)精簡(jiǎn)過(guò)了,自己的業(yè)務(wù)已經(jīng)除去,精簡(jiǎn)的代碼附上注釋是可以直接調(diào)用微信后臺(tái)的
這個(gè)是微信所要接受的參數(shù),咱們可以把它構(gòu)建成一個(gè)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; // 應(yīng)用ID 微信開(kāi)放平臺(tái)審核通過(guò)的應(yīng)用APPIDprivate String mch_id; // 商戶號(hào) 微信支付分配的商戶號(hào)private String nonce_str = OrderUtil.CreateNoncestr(); // 隨機(jī)字符串 隨機(jī)字符串,不長(zhǎng)于32位private String sign; // 簽名 private String body; // 商品描述 商品描述交易字段格式根據(jù)不同的應(yīng)用場(chǎng)景按照以下格式:APP——需傳入應(yīng)用市場(chǎng)上的APP名字-實(shí)際商品名稱,天天愛(ài)消除-游戲充值。private String out_trade_no; // 商戶訂單號(hào) 商戶系統(tǒng)內(nèi)部的訂單號(hào),32個(gè)字符內(nèi)、可包含字母private String total_fee; // 總金額 訂單總金額,單位為分private String spbill_create_ip; // 終端IP 用戶端實(shí)際ipprivate String notify_url; // 通知地址 接收微信支付異步通知回調(diào)地址,通知url必須為直接可訪問(wèn)的url,不能攜帶參數(shù)。 private String trade_type; // 交易類型 支付類型private String partnerKey;private String attach; // 附加數(shù)據(jù) 附加數(shù)據(jù),在查詢API和支付通知中原樣返回,該字段主要用于商戶攜帶訂單的自定義數(shù)據(jù)private String prepay_id; // 預(yù)支付訂單號(hào)?
controller作為一個(gè)restful接口供手機(jī)端調(diào)用,這個(gè)接口可以被ios,安卓等調(diào)用,只要微信提供了相應(yīng)手機(jī)端的sdk,那就沒(méi)有問(wèn)題
@RequestMapping("/wxpay")@ResponseBodypublic LeeJSONResult wxpay(HttpServletRequest request, Model model) {try {// TODO 根據(jù)你的業(yè)務(wù)邏輯計(jì)算你需要支付的訂單總額double totalFee = 1;// 生成交易流水,流水id需要傳給微信,這個(gè)流水ID可以作為你的訂單ID,由于我們的業(yè)務(wù)是多訂單的,流水ID僅僅只是作為表關(guān)聯(lián)// 需要保存貨源id,需要的車輛數(shù),訂單id在通知成功后保存String payFlowId = sid.nextShort();SpPayFlowCargoSource payFlowCargoSource = new SpPayFlowCargoSource();payFlowCargoSource.setId(payFlowId);payFlowCargoSource.setFee(new BigDecimal(totalFee));payFlowCargoSource.setPayStatus(PayStatusEnum.NOT_PAID.value); // 支付狀態(tài):未支付// 構(gòu)建微信參數(shù)String spbill_create_ip = request.getRemoteAddr(); // 用戶IPWXPrepay prePay = new WXPrepay();prePay.setAppid(WXPayContants.appId); prePay.setMch_id(WXPayContants.partnerId);prePay.setBody("demo - 微信支付"); prePay.setOut_trade_no(payFlowId); // 這里要注意,微信支付是以分為單位,而系統(tǒng)是以元為單位,所以需要金額轉(zhuǎn)換。題外話:曾經(jīng)看到過(guò)京東和蘇寧都有類似的bug,就是一個(gè)臺(tái)手機(jī)和耳機(jī)都是要十幾元,估計(jì)是金額轉(zhuǎn)換出的問(wèn)題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); // 異步通知,這個(gè)下篇文章講prePay.setTrade_type("APP");prePay.setAttach(payFlowId); // 存入交易流水id prePay.setPartnerKey(WXPayContants.partnerKey);// 獲取預(yù)支付訂單號(hào)String prepayId = prePay.submitXmlGetPrepayId();logger.info("獲取的預(yù)支付訂單是:" + prepayId);if (prepayId != null && prepayId.length() > 10) {// 生成微信支付參數(shù),此處拼接為完整的JSON格式,符合支付調(diào)起傳入格式String jsParam = WXPay.createPackageValue(WXPayContants.appId, WXPayContants.partnerKey, prepayId);System.out.println("jsParam=" + jsParam);// 此處可以添加訂單的處理邏輯model.addAttribute("jsParam", jsParam);logger.info("生成的微信調(diào)起JS參數(shù)為:" + jsParam);payFlowCargoSource.setPrepayId(prepayId); spPayFlowCargoSourceService.savePayFlow(payFlowCargoSource);return LeeJSONResult.ok();} else {return LeeJSONResult.errorMsg("微信支付接口調(diào)用失敗");}} catch (Exception e) {e.printStackTrace();return LeeJSONResult.errorException(e.getMessage());}}?
需要注意的是,微信后臺(tái)接受的參數(shù)都是xml格式的,所以咱們的bean需要轉(zhuǎn)換為xml再傳給微信,最后調(diào)用成功,微信會(huì)封裝一個(gè)xml傳過(guò)來(lái),咱們同樣再解析一下獲取預(yù)付單號(hào)就OK了
public String submitXmlGetPrepayId() {// 創(chuàng)建HttpClientBuilderHttpClientBuilder httpClientBuilder = HttpClientBuilder.create();// HttpClientCloseableHttpClient 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請(qǐng)求httpResponse = closeableHttpClient.execute(httpPost);HttpEntity httpEntity = httpResponse.getEntity();if (httpEntity != null) {// 打印響應(yīng)內(nèi)容String result = EntityUtils.toString(httpEntity, "UTF-8");System.out.println(result);// 過(guò)濾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;}?
其實(shí)不用這樣的方式也行,把bean通過(guò)json的方式封裝,最后讓它自動(dòng)轉(zhuǎn)為xml,也是沒(méi)有問(wèn)題的,或者直接使用 restful webservice標(biāo)準(zhǔn)協(xié)議來(lái)接受xml和發(fā)送xml
總結(jié)
以上是生活随笔為你收集整理的app端微信支付(二) - 生成预付单的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: busybox rootfs 启动脚本分
- 下一篇: TypeScript 学习一 参数,