|
@@ -11,7 +11,6 @@ import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpSession;
|
|
|
|
|
|
import com.chelvc.framework.base.context.SessionContextHolder;
|
|
|
-import com.chelvc.framework.base.model.Terminal;
|
|
|
import com.chelvc.framework.base.util.DecimalUtils;
|
|
|
import com.chelvc.framework.base.util.HostUtils;
|
|
|
import com.chelvc.framework.base.util.ObjectUtils;
|
|
@@ -130,49 +129,30 @@ public class DefaultWechatHandler implements WechatHandler {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 根据支付交易类型获取Appid
|
|
|
+ * 获取支付配置
|
|
|
*
|
|
|
- * @param type 交易类型
|
|
|
- * @param payment 支付配置
|
|
|
- * @return Appid
|
|
|
+ * @param mode 支付方式
|
|
|
+ * @return 支付配置
|
|
|
*/
|
|
|
- private String getAppid(TradeType type, WechatProperties.Payment payment) {
|
|
|
- if (type == TradeType.APP) {
|
|
|
- // 兼容老版本
|
|
|
- if (SessionContextHolder.isBeforeVersion(Terminal.APP, "1.4.4")) {
|
|
|
- return "wx297be7a59f0eaf28";
|
|
|
- }
|
|
|
- return Objects.requireNonNull(payment.getPayid(), "Wechat payid unspecified");
|
|
|
- }
|
|
|
- return Objects.requireNonNull(this.properties.getAppid(), "Wechat appid unspecified");
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 参数签名
|
|
|
- *
|
|
|
- * @param payment 支付配置
|
|
|
- * @param parameters 签名参数
|
|
|
- * @return 签名信息
|
|
|
- */
|
|
|
- private String sign(WechatProperties.Payment payment, Map<String, String> parameters) {
|
|
|
- String mchkey = Objects.requireNonNull(payment.getMchkey(), "Wechat mchkey unspecified");
|
|
|
- return WechatUtils.sign(mchkey, parameters);
|
|
|
+ private WechatProperties.Payment getPayment(PayMode mode) {
|
|
|
+ List<WechatProperties.Payment> payments = this.properties.getPayments();
|
|
|
+ WechatProperties.Payment payment = CollectionUtils.isEmpty(payments) ? null :
|
|
|
+ payments.stream().filter(config -> config.getMode() == mode).findAny().orElse(null);
|
|
|
+ return Objects.requireNonNull(payment, "Not support pay mode: " + mode);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 构建支付参数
|
|
|
+ * 生成支付参数
|
|
|
*
|
|
|
- * @param type 交易类型
|
|
|
* @param payment 支付配置
|
|
|
* @param request 支付请求参数
|
|
|
* @return 支付参数键/值对
|
|
|
*/
|
|
|
- private Map<String, String> buildPaymentParameters(TradeType type, WechatProperties.Payment payment,
|
|
|
- WechatPayRequest request) {
|
|
|
+ private Map<String, String> generatePaymentParameters(WechatProperties.Payment payment, WechatPayRequest request) {
|
|
|
String mchid = Objects.requireNonNull(payment.getMchid(), "Wechat mchid unspecified");
|
|
|
String callback = Objects.requireNonNull(payment.getCallback(), "Wechat callback unspecified");
|
|
|
Map<String, String> parameters = Maps.newHashMap();
|
|
|
- parameters.put("appid", this.getAppid(type, payment));
|
|
|
+ parameters.put("appid", this.getAppid(payment));
|
|
|
parameters.put("mch_id", mchid);
|
|
|
parameters.put("body", request.getComment());
|
|
|
parameters.put("out_trade_no", request.getOrder());
|
|
@@ -183,46 +163,34 @@ public class DefaultWechatHandler implements WechatHandler {
|
|
|
parameters.put("total_fee", String.valueOf(request.getAmount().multiply(DecimalUtils.HUNDRED).intValue()));
|
|
|
parameters.put("spbill_create_ip", HostUtils.LOCAL_ADDRESS);
|
|
|
parameters.put("notify_url", callback);
|
|
|
- parameters.put("trade_type", type.name());
|
|
|
+ parameters.put("trade_type", payment.getMode().name());
|
|
|
parameters.put("nonce_str", WXPayUtil.generateNonceStr());
|
|
|
return parameters;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 微信统一下单
|
|
|
+ * 根据支付交易类型获取Appid
|
|
|
*
|
|
|
- * @param payment 支付配置
|
|
|
- * @param parameters 下单参数
|
|
|
- * @return 下单结果
|
|
|
+ * @param payment 支付配置
|
|
|
+ * @return Appid
|
|
|
*/
|
|
|
- private Map<String, String> unifiedorder(WechatProperties.Payment payment, Map<String, String> parameters) {
|
|
|
- boolean debug = log.isDebugEnabled();
|
|
|
- if (debug) {
|
|
|
- log.debug("Wechat parameters: {}", parameters);
|
|
|
- }
|
|
|
-
|
|
|
- // 请求参数签名
|
|
|
- parameters.put("sign", this.sign(payment, parameters));
|
|
|
-
|
|
|
- // 将请求参数转换成xml请求体
|
|
|
- String body = WechatUtils.map2xml(parameters);
|
|
|
- if (debug) {
|
|
|
- log.debug("Wechat request: {}, {}", UNIFIEDORDER_URL, body);
|
|
|
+ private String getAppid(WechatProperties.Payment payment) {
|
|
|
+ if (payment.getMode() == PayMode.APP || payment.getMode() == PayMode.NATIVE) {
|
|
|
+ return Objects.requireNonNull(payment.getPayid(), "Wechat payid unspecified");
|
|
|
}
|
|
|
+ return Objects.requireNonNull(this.properties.getAppid(), "Wechat appid unspecified");
|
|
|
+ }
|
|
|
|
|
|
- // 发起下单请求
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.setContentType(MediaType.TEXT_XML);
|
|
|
- HttpEntity<?> entity = new HttpEntity<>(body, headers);
|
|
|
- String response = this.restTemplate.exchange(UNIFIEDORDER_URL, HttpMethod.POST, entity, String.class).getBody();
|
|
|
- if (debug) {
|
|
|
- log.debug("Wechat response: {}", response);
|
|
|
- }
|
|
|
- if (StringUtils.isEmpty(response) || !response.contains("SUCCESS")) {
|
|
|
- log.error("Wechat unifiedorder failed: {}", response);
|
|
|
- throw new RuntimeException("Wechat unifiedorder failed");
|
|
|
- }
|
|
|
- return WechatUtils.xml2map(response);
|
|
|
+ /**
|
|
|
+ * 参数签名
|
|
|
+ *
|
|
|
+ * @param payment 支付配置
|
|
|
+ * @param parameters 签名参数
|
|
|
+ * @return 签名信息
|
|
|
+ */
|
|
|
+ private String sign(WechatProperties.Payment payment, Map<String, String> parameters) {
|
|
|
+ String mchkey = Objects.requireNonNull(payment.getMchkey(), "Wechat mchkey unspecified");
|
|
|
+ return WechatUtils.sign(mchkey, parameters);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -394,69 +362,58 @@ public class DefaultWechatHandler implements WechatHandler {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public WechatProperties.Payment getPayment(@NonNull String type) {
|
|
|
- List<WechatProperties.Payment> payments = this.properties.getPayments();
|
|
|
- WechatProperties.Payment payment = CollectionUtils.isEmpty(payments) ? null :
|
|
|
- payments.stream().filter(config -> Objects.equals(config.getType(), type)).findAny().orElse(null);
|
|
|
- return Objects.requireNonNull(payment, "Not support payment type: " + type);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public String sign(@NonNull String type, @NonNull Map<String, String> parameters) {
|
|
|
- return this.sign(this.getPayment(type), parameters);
|
|
|
+ public String sign(@NonNull PayMode mode, @NonNull Map<String, String> parameters) {
|
|
|
+ return this.sign(this.getPayment(mode), parameters);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Map<String, String> pay(@NonNull String type, @NonNull WechatPayRequest request) {
|
|
|
+ public WechatUnifiedOrder unifiedorder(@NonNull PayMode mode, @NonNull WechatPayRequest request) {
|
|
|
// 获取支付配置
|
|
|
- WechatProperties.Payment payment = this.getPayment(type);
|
|
|
+ WechatProperties.Payment payment = this.getPayment(mode);
|
|
|
|
|
|
// 构建请求参数
|
|
|
- Map<String, String> parameters = this.buildPaymentParameters(TradeType.APP, payment, request);
|
|
|
-
|
|
|
- // 统一下单
|
|
|
- Map<String, String> result = this.unifiedorder(payment, parameters);
|
|
|
-
|
|
|
- // 构建支付结果
|
|
|
- Map<String, String> returns = Maps.newHashMapWithExpectedSize(8);
|
|
|
- returns.put("appid", this.getAppid(TradeType.APP, payment));
|
|
|
- returns.put("partnerid", payment.getMchid());
|
|
|
- returns.put("prepayid", result.get("prepay_id"));
|
|
|
- returns.put("noncestr", WXPayUtil.generateNonceStr());
|
|
|
- returns.put("package", "Sign=WXPay");
|
|
|
- returns.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000).substring(0, 10));
|
|
|
- returns.put("sign", this.sign(payment, returns));
|
|
|
- returns.put("orderId", String.valueOf(request.getOrder()));
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("App payment: {}", returns);
|
|
|
+ Map<String, String> parameters = this.generatePaymentParameters(payment, request);
|
|
|
+
|
|
|
+ // 如果是小程序支付则需要指定openid
|
|
|
+ if (mode == PayMode.JSAPI) {
|
|
|
+ parameters.put("openid", Objects.requireNonNull(request.getOpenid(), "openid unspecified"));
|
|
|
}
|
|
|
- return returns;
|
|
|
- }
|
|
|
|
|
|
- @Override
|
|
|
- public Map<String, String> appletPay(@NonNull String type, @NonNull String token, WechatPayRequest request) {
|
|
|
- // 获取支付配置
|
|
|
- WechatProperties.Payment payment = this.getPayment(type);
|
|
|
+ boolean debug = log.isDebugEnabled();
|
|
|
+ if (debug) {
|
|
|
+ log.debug("Wechat parameters: {}", parameters);
|
|
|
+ }
|
|
|
|
|
|
- // 构建请求参数
|
|
|
- Map<String, String> parameters = this.buildPaymentParameters(TradeType.JSAPI, payment, request);
|
|
|
- parameters.put("openid", this.code2session(token).getOpenid());
|
|
|
-
|
|
|
- // 统一下单
|
|
|
- Map<String, String> result = this.unifiedorder(payment, parameters);
|
|
|
-
|
|
|
- // 构建支付结果
|
|
|
- Map<String, String> returns = Maps.newHashMapWithExpectedSize(7);
|
|
|
- returns.put("appId", this.getAppid(TradeType.JSAPI, payment));
|
|
|
- returns.put("nonceStr", WXPayUtil.generateNonceStr());
|
|
|
- returns.put("package", "prepay_id=" + result.get("prepay_id"));
|
|
|
- returns.put("signType", "MD5");
|
|
|
- returns.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000).substring(0, 10));
|
|
|
- returns.put("paySign", this.sign(payment, returns));
|
|
|
- returns.put("orderId", String.valueOf(request.getOrder()));
|
|
|
- if (log.isDebugEnabled()) {
|
|
|
- log.debug("Applet payment: {}", returns);
|
|
|
+ // 请求参数签名
|
|
|
+ parameters.put("sign", this.sign(payment, parameters));
|
|
|
+
|
|
|
+ // 将请求参数转换成xml请求体
|
|
|
+ String body = WechatUtils.map2xml(parameters);
|
|
|
+ if (debug) {
|
|
|
+ log.debug("Wechat request: {}, {}", UNIFIEDORDER_URL, body);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发起下单请求
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.TEXT_XML);
|
|
|
+ HttpEntity<?> entity = new HttpEntity<>(body, headers);
|
|
|
+ String response = this.restTemplate.exchange(UNIFIEDORDER_URL, HttpMethod.POST, entity, String.class).getBody();
|
|
|
+ if (debug) {
|
|
|
+ log.debug("Wechat response: {}", response);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证相应结果
|
|
|
+ Map<String, String> result = ObjectUtils.ifNull(response, WechatUtils::xml2map);
|
|
|
+ if (StringUtils.isEmpty(response) || !Objects.equals(result.get("return_code"), "SUCCESS")
|
|
|
+ || !Objects.equals(result.get("result_code"), "SUCCESS")
|
|
|
+ || !Objects.equals(result.remove("sign"), this.sign(payment, result))) {
|
|
|
+ log.error("Wechat unifiedorder failed: {}", response);
|
|
|
+ throw new RuntimeException("Wechat unifiedorder failed");
|
|
|
}
|
|
|
- return returns;
|
|
|
+
|
|
|
+ // 构建微信统一下单信息
|
|
|
+ return WechatUnifiedOrder.builder().mode(mode).appid(result.get("appid")).mchid(result.get("mch_id"))
|
|
|
+ .nonce(result.get("nonce_str")).prepayid(result.get("prepay_id"))
|
|
|
+ .qrcode(result.get("code_url")).build();
|
|
|
}
|
|
|
}
|