From cc3714c59996676ebce82384bfa63602c749dacc Mon Sep 17 00:00:00 2001 From: Kane Zhu Date: Wed, 14 Oct 2015 16:36:55 +0800 Subject: [PATCH] Improve prepay API to support all parameters. --- .../me/chanjar/weixin/mp/api/WxMpService.java | 76 ++++++++++++------- .../weixin/mp/api/WxMpServiceImpl.java | 73 +++++++++++++----- .../mp/bean/result/WxMpPrepayIdResult.java | 27 +++++++ 3 files changed, 130 insertions(+), 46 deletions(-) diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java index 5c15e89b..b583798e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java @@ -671,33 +671,57 @@ public interface WxMpService { */ void setMaxRetryTimes(int maxRetryTimes); - /** - * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) - * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" - * @param openId 支付人openId - * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @return - */ - WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); + /** + * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) + * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * @param openId 支付人openId + * @param outTradeNo 商户端对应订单号 + * @param amt 金额(单位元) + * @param body 商品描述 + * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 + * @return + * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getPrepayId(Map) instead + */ + @Deprecated + WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); - /** - * 该接口调用“统一下单”接口,并拼装JSSDK发起支付请求需要的参数 - * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 - * @param openId 支付人openId - * @param outTradeNo 商户端对应订单号 - * @param amt 金额(单位元) - * @param body 商品描述 - * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP - * @param ip 发起支付的客户端IP - * @param notifyUrl 通知地址 - * @return - */ - Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); + /** + * 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) + * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param parameters + * All required/optional parameters for weixin payment + * @return + * @throws IllegalArgumentException + */ + WxMpPrepayIdResult getPrepayId(Map parameters); + + /** + * 该接口调用“统一下单”接口,并拼装JSSDK发起支付请求需要的参数 + * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 + * @param parameters + * the required or optional parameters + * @return + */ + Map getJSSDKPayInfo(Map parameters); + + /** + * 该接口调用“统一下单”接口,并拼装JSSDK发起支付请求需要的参数 + * 详见http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E5.8F.91.E8.B5.B7.E4.B8.80.E4.B8.AA.E5.BE.AE.E4.BF.A1.E6.94.AF.E4.BB.98.E8.AF.B7.E6.B1.82 + * @param openId 支付人openId + * @param outTradeNo 商户端对应订单号 + * @param amt 金额(单位元) + * @param body 商品描述 + * @param tradeType 交易类型 JSAPI,NATIVE,APP,WAP + * @param ip 发起支付的客户端IP + * @param notifyUrl 通知地址 + * @return + * @deprecated Use me.chanjar.weixin.mp.api.WxMpService.getJSSDKPayInfo(Map) instead + */ + @Deprecated + Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String notifyUrl); /** * 该接口提供所有微信支付订单的查询,当支付通知处理异常戒丢失的情冴,商户可以通过该接口查询订单支付状态。 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java index 1263c9a1..da4252fd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpServiceImpl.java @@ -11,6 +11,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; import java.util.UUID; @@ -777,35 +778,37 @@ public class WxMpServiceImpl implements WxMpService { @Override public WxMpPrepayIdResult getPrepayId(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) { - String nonce_str = System.currentTimeMillis() + ""; - - SortedMap packageParams = new TreeMap(); + Map packageParams = new HashMap(); packageParams.put("appid", wxMpConfigStorage.getAppId()); packageParams.put("mch_id", wxMpConfigStorage.getPartnerId()); - packageParams.put("nonce_str", nonce_str); packageParams.put("body", body); packageParams.put("out_trade_no", outTradeNo); - packageParams.put("total_fee", (int) (amt * 100) + ""); packageParams.put("spbill_create_ip", ip); packageParams.put("notify_url", callbackUrl); packageParams.put("trade_type", tradeType); packageParams.put("openid", openId); + return getPrepayId(packageParams); + } + + public WxMpPrepayIdResult getPrepayId(final Map parameters) { + String nonce_str = System.currentTimeMillis() + ""; + + final SortedMap packageParams = new TreeMap(parameters); + packageParams.put("appid", wxMpConfigStorage.getAppId()); + packageParams.put("mch_id", wxMpConfigStorage.getPartnerId()); + packageParams.put("nonce_str", nonce_str); + checkParameters(packageParams); + String sign = WxCryptUtil.createSign(packageParams, wxMpConfigStorage.getPartnerKey()); - String xml = "" + - "" + wxMpConfigStorage.getAppId() + "" + - "" + wxMpConfigStorage.getPartnerId() + "" + - "" + nonce_str + "" + - "" + sign + "" + - "" + - "" + outTradeNo + "" + - "" + packageParams.get("total_fee") + "" + - "" + ip + "" + - "" + callbackUrl + "" + - "" + tradeType + "" + - "" + openId + "" + - ""; + packageParams.put("sign", sign); + + StringBuilder request = new StringBuilder(""); + for (Entry para : packageParams.entrySet()) { + request.append(String.format("<%s>%s", para.getKey(), para.getValue(), para.getKey())); + } + request.append(""); HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); if (httpProxy != null) { @@ -813,7 +816,7 @@ public class WxMpServiceImpl implements WxMpService { httpPost.setConfig(config); } - StringEntity entity = new StringEntity(xml, Consts.UTF_8); + StringEntity entity = new StringEntity(request.toString(), Consts.UTF_8); httpPost.setEntity(entity); try { CloseableHttpResponse response = getHttpclient().execute(httpPost); @@ -828,9 +831,39 @@ public class WxMpServiceImpl implements WxMpService { return new WxMpPrepayIdResult(); } + final String[] REQUIRED_ORDER_PARAMETERS = new String[] { "appid", "mch_id", "body", "out_trade_no", "total_fee", "spbill_create_ip", "notify_url", + "trade_type", }; + + private void checkParameters(Map parameters) { + for (String para : REQUIRED_ORDER_PARAMETERS) { + if (!parameters.containsKey(para)) + throw new IllegalArgumentException("Reqiured argument '" + para + "' is missing."); + } + if ("JSAPI".equals(parameters.get("trade_type")) && !parameters.containsKey("openid")) + throw new IllegalArgumentException("Reqiured argument 'openid' is missing when trade_type is 'JSAPI'."); + if ("NATIVE".equals(parameters.get("trade_type")) && !parameters.containsKey("product_id")) + throw new IllegalArgumentException("Reqiured argument 'product_id' is missing when trade_type is 'NATIVE'."); + } + @Override public Map getJSSDKPayInfo(String openId, String outTradeNo, double amt, String body, String tradeType, String ip, String callbackUrl) { - WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(openId, outTradeNo, amt, body, tradeType, ip, callbackUrl); + Map packageParams = new HashMap(); + packageParams.put("appid", wxMpConfigStorage.getAppId()); + packageParams.put("mch_id", wxMpConfigStorage.getPartnerId()); + packageParams.put("body", body); + packageParams.put("out_trade_no", outTradeNo); + packageParams.put("total_fee", (int) (amt * 100) + ""); + packageParams.put("spbill_create_ip", ip); + packageParams.put("notify_url", callbackUrl); + packageParams.put("trade_type", tradeType); + packageParams.put("openid", openId); + + return getJSSDKPayInfo(packageParams); + } + + @Override + public Map getJSSDKPayInfo(Map parameters) { + WxMpPrepayIdResult wxMpPrepayIdResult = getPrepayId(parameters); String prepayId = wxMpPrepayIdResult.getPrepay_id(); if (prepayId == null || prepayId.equals("")) { throw new RuntimeException("get prepayid error"); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java index aa42299a..b5c09b21 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/result/WxMpPrepayIdResult.java @@ -22,6 +22,9 @@ public class WxMpPrepayIdResult implements Serializable { private String result_code; private String prepay_id; private String trade_type; + private String err_code; + private String err_code_des; + private String code_url; public String getReturn_code() { return return_code; @@ -94,4 +97,28 @@ public class WxMpPrepayIdResult implements Serializable { public void setTrade_type(String trade_type) { this.trade_type = trade_type; } + + public String getErr_code() { + return err_code; + } + + public void setErr_code(String err_code) { + this.err_code = err_code; + } + + public String getErr_code_des() { + return err_code_des; + } + + public void setErr_code_des(String err_code_des) { + this.err_code_des = err_code_des; + } + + public String getCode_url() { + return code_url; + } + + public void setCode_url(String code_url) { + this.code_url = code_url; + } }