From e8be5dee9d46d03089152fec12c79dae910f941c Mon Sep 17 00:00:00 2001
From: gong <1157756119@qq.com>
Date: Wed, 14 Jan 2026 10:35:33 +0800
Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=9D=A1=E7=A0=81=E6=94=AF?=
=?UTF-8?q?=E4=BB=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
cash-dependencies/pom.xml | 8 +
cash-sdk/aggregation-pay/pom.xml | 7 +
.../src/main/java/com/czg/EntryManager.java | 4 +-
.../src/main/java/com/czg/PayManager.java | 39 ++-
.../java/com/czg/dto/req/PayParamsDto.java | 16 ++
.../czg/third/alipay/AlipayIsvPayManager.java | 33 ++-
.../czg/third/wechat/WechatPayManager.java | 238 ++++++++++++++++--
.../com/czg/third/wechat/WechatReqUtils.java | 2 +-
.../wechat/dto/config/WechatPayConfigDto.java | 6 +
9 files changed, 324 insertions(+), 29 deletions(-)
diff --git a/cash-dependencies/pom.xml b/cash-dependencies/pom.xml
index a598172c8..7a4777293 100644
--- a/cash-dependencies/pom.xml
+++ b/cash-dependencies/pom.xml
@@ -44,6 +44,7 @@
4.1.128.Final
0.2.17
3.1.65.ALL
+ 2.2.0
@@ -282,6 +283,13 @@
alipay-sdk-java-v3
${apipay-v3.version}
+
+
+ org.dom4j
+ dom4j
+ ${dom4j.version}
+ compile
+
diff --git a/cash-sdk/aggregation-pay/pom.xml b/cash-sdk/aggregation-pay/pom.xml
index 8eb8d2da1..d201553ec 100644
--- a/cash-sdk/aggregation-pay/pom.xml
+++ b/cash-sdk/aggregation-pay/pom.xml
@@ -35,6 +35,13 @@
ocr_api20210707
3.1.2
+
+
+
+ org.dom4j
+ dom4j
+ compile
+
\ No newline at end of file
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/EntryManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/EntryManager.java
index 76d70ecac..7f81f350a 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/EntryManager.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/EntryManager.java
@@ -385,8 +385,8 @@ public class EntryManager {
// verifyEntryParam(merchantDto);
// uploadParamImage(merchantDto);
//// System.out.println(merchantDto);
- EntryRespDto respDto = entryMerchant(merchantDto, PayCst.Platform.WECHAT);
-// entryMerchant(merchantDto, PayCst.Platform.ALIPAY);
+// EntryRespDto respDto = entryMerchant(merchantDto, PayCst.Platform.WECHAT);
+ EntryRespDto respDto = entryMerchant(merchantDto, PayCst.Platform.ALIPAY);
// entryMerchant(merchantDto, PayCst.Platform.WECHAT, PayCst.Platform.ALIPAY);
System.out.println(respDto);
}
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java
index 06ea794e3..90f5730b3 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java
@@ -1,22 +1,51 @@
package com.czg;
import com.czg.dto.req.PayParamsDto;
+import com.czg.exception.CzgException;
import com.czg.third.alipay.AlipayIsvPayManager;
import com.czg.third.wechat.WechatPayManager;
+import java.util.Map;
+
/**
* @author yjjie
* @date 2026/1/9 11:24
*/
public class PayManager {
- public static void jsapiPay(PayParamsDto paramsDto) {
+ /**
+ * jsapi支付
+ *
+ * @param paramsDto 参数
+ * @return 结果
+ */
+ public static Map jsapiPay(PayParamsDto paramsDto) {
paramsDto.verifyParams();
if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) {
- WechatPayManager.jsapiPay(null, paramsDto);
+ return WechatPayManager.jsapiPay(null, paramsDto);
} else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) {
- AlipayIsvPayManager.jsapiPay(null, paramsDto);
+ return AlipayIsvPayManager.jsapiPay(null, paramsDto);
+ } else {
+ throw new CzgException("不支持的支付平台");
+ }
+ }
+
+ /**
+ * 条码支付
+ *
+ * @param paramsDto 参数
+ * @return 结果
+ */
+ public static Map barPay(PayParamsDto paramsDto) {
+ paramsDto.verifyParams();
+
+ if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) {
+ return WechatPayManager.barPay(null, paramsDto);
+ } else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) {
+ return AlipayIsvPayManager.barPay(null, paramsDto);
+ } else {
+ throw new CzgException("不支持的支付平台");
}
}
@@ -35,10 +64,10 @@ public class PayManager {
jsapiPay(new PayParamsDto()
.setPlatform(PayCst.Platform.WECHAT)
.setAppId("wxd88fffa983758a30")
- .setOpenId("123123123")
+ .setOpenId("or1l86yipGvwyfPhrKIAcQuSfAV8")
.setOrderNo("1111231231213")
.setTitle("1213")
- .setMerchantId("1665469114")
+ .setMerchantId("1738216504")
.setBody("1213")
.setAmount(1000L)
.setPayParams("{\"app_auth_token\": \"ssss\"}")
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/PayParamsDto.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/PayParamsDto.java
index 114d45ef2..80365910f 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/PayParamsDto.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/PayParamsDto.java
@@ -77,6 +77,22 @@ public class PayParamsDto {
*/
private String body;
+ /**
+ * 扩展数据
+ */
+ private String extData;
+
+ /**
+ * 设备 ip
+ */
+ private String clientIp;
+
+ /**
+ * 支付条码
+ * 微信:18位纯数字,前缀以10、11、12、13、14、15开头
+ */
+ private String barCode;
+
/**
* 支付宝 授权信息解析,不用传
*/
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java
index 50244a798..56214e479 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java
@@ -14,6 +14,8 @@ import com.czg.third.alipay.dto.config.AlipayConfigDto;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
/**
* @author yjjie
@@ -22,7 +24,12 @@ import java.math.BigDecimal;
@Slf4j
public class AlipayIsvPayManager {
- public static String jsapiPay(AlipayConfigDto configDto, PayParamsDto paramsDto) {
+ /**
+ * H5支付
+ * @param configDto 配置
+ * @param paramsDto 参数
+ */
+ public static Map jsapiPay(AlipayConfigDto configDto, PayParamsDto paramsDto) {
try {
AlipayClient.setApiClient(configDto);
AlipayTradeApi api = new AlipayTradeApi();
@@ -41,7 +48,8 @@ public class AlipayIsvPayManager {
customizedParams.setAppAuthToken(paramsDto.getAlipayAuthInfo().getAppAuthToken());
AlipayTradeCreateResponseModel responseModel = api.create(model, customizedParams);
- return responseModel.getTradeNo();
+ log.info("支付宝 jsapi 支付结果: {}", responseModel);
+ return new HashMap<>();
} catch (ApiException e) {
String body = e.getResponseBody();
log.error("支付宝 H5 api 支付异常: {}", body);
@@ -53,6 +61,27 @@ public class AlipayIsvPayManager {
}
}
+ /**
+ * 条码支付
+ * @param configDto 配置
+ * @param paramsDto 参数
+ */
+ public static Map barPay(AlipayConfigDto configDto, PayParamsDto paramsDto) {
+ try {
+ AlipayClient.setApiClient(configDto);
+
+ return new JSONObject();
+// } catch (ApiException e) {
+// String body = e.getResponseBody();
+// log.error("支付宝 条码支付异常: {}", body);
+// JSONObject object = JSONObject.parseObject(body);
+// throw new CzgException(object.getString(PayCst.ALIPAY_ERROR_MSG_KEY));
+ } catch (Exception e) {
+ log.error("支付宝 条码支付异常: {}", e.getMessage());
+ throw new CzgException(e.getMessage());
+ }
+ }
+
/**
* 金额转换
*/
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java
index 415edd6d4..7061bb65f 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java
@@ -1,9 +1,31 @@
package com.czg.third.wechat;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.dto.req.PayParamsDto;
+import com.czg.exception.CzgException;
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
+import com.wechat.pay.java.core.Config;
+import com.wechat.pay.java.core.cipher.Signer;
+import com.wechat.pay.java.core.util.NonceUtil;
import lombok.extern.slf4j.Slf4j;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.SAXReader;
+import org.dom4j.io.XMLWriter;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
/**
* @author yjjie
@@ -12,33 +34,211 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class WechatPayManager {
+ private static final String PAY_SUCCESS = "SUCCESS";
+ private static final String BAR_PAY_URL = "https://api.mch.weixin.qq.com/pay/micropay";
+
/**
* jsapi 小程序支付
- * @param configDto 配置
- * @param paramsDto 参数
+ *
+ * @param configDto 配置
+ * @param paramsDto 参数
*/
- public static String jsapiPay(WechatPayConfigDto configDto, PayParamsDto paramsDto) {
+ public static Map jsapiPay(WechatPayConfigDto configDto, PayParamsDto paramsDto) {
if (configDto == null) {
configDto = WechatPayConfigDto.getDefaultConfig();
}
- JSONObject reqData = new JSONObject();
- reqData.put("sp_appid", paramsDto.getAppId());
- reqData.put("sp_mchid", configDto.getMerchantId());
- reqData.put("sub_mchid", paramsDto.getMerchantId());
- reqData.put("description", paramsDto.getTitle());
- reqData.put("out_trade_no", paramsDto.getOrderNo());
- reqData.put("notify_url", paramsDto.getNotifyUrl());
- JSONObject amount = new JSONObject();
- amount.put("total", paramsDto.getAmount());
- reqData.put("amount", amount);
+ try {
+ JSONObject reqData = new JSONObject();
+ reqData.put("sp_appid", paramsDto.getAppId());
+ reqData.put("sp_mchid", configDto.getMerchantId());
+ reqData.put("sub_mchid", paramsDto.getMerchantId());
+ reqData.put("description", paramsDto.getTitle());
+ reqData.put("out_trade_no", paramsDto.getOrderNo());
+ reqData.put("notify_url", paramsDto.getNotifyUrl());
+ reqData.put("attach", paramsDto.getExtData());
- JSONObject payer = new JSONObject();
- payer.put("sp_openid", paramsDto.getOpenId());
- reqData.put("payer", payer);
+ JSONObject amount = new JSONObject();
+ amount.put("total", paramsDto.getAmount());
+ reqData.put("amount", amount);
- String string = WechatReqUtils.postReq(configDto, "/v3/pay/partner/transactions/jsapi", reqData.toJSONString());
- log.info("微信支付请求结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), string);
- return "";
+ JSONObject payer = new JSONObject();
+ payer.put("sp_openid", paramsDto.getOpenId());
+ reqData.put("payer", payer);
+
+ String string = WechatReqUtils.postReq(configDto, "/v3/pay/partner/transactions/jsapi", reqData.toJSONString());
+ log.info("微信支付请求结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), string);
+
+ JSONObject object = JSONObject.parseObject(string);
+
+ long timestamp = Instant.now().getEpochSecond();
+ String nonceStr = NonceUtil.createNonce(32);
+ String packageVal = "prepay_id=" + object.getString("prepay_id");
+ String message =
+ paramsDto.getAppId() + "\n" + timestamp + "\n" + nonceStr + "\n" + packageVal + "\n";
+
+ Config config = WechatConfig.getRsaConfig(configDto);
+ Signer signer = config.createSigner();
+ String sign = signer.sign(message).getSign();
+
+ JSONObject res = new JSONObject();
+ res.put("appId", paramsDto.getAppId());
+ res.put("timeStamp", String.valueOf(timestamp));
+ res.put("nonceStr", nonceStr);
+ res.put("package", packageVal);
+ res.put("signType", "RSA");
+ res.put("paySign", sign);
+ log.info("微信支付签名结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), res);
+ return res;
+ } catch (Exception e) {
+ log.error("微信支付异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
+ throw new CzgException("微信支付异常");
+ }
+ }
+
+ /**
+ * 条码支付
+ * 用户付款码规则:18位纯数字,前缀以10、11、12、13、14、15开头
+ * @param configDto 配置
+ * @param paramsDto 参数
+ */
+ public static Map barPay(WechatPayConfigDto configDto, PayParamsDto paramsDto) {
+ try {
+ if (configDto == null) {
+ configDto = WechatPayConfigDto.getDefaultConfig();
+ }
+
+ String nonceStr = NonceUtil.createNonce(32);
+
+ Map payMap = new HashMap<>();
+ Document document = DocumentHelper.createDocument();
+
+ // 添加根元素
+ Element xml = document.addElement("xml");
+
+ addElementIfNotEmpty(xml, "appid", paramsDto.getAppId());
+ payMap.put("appid", paramsDto.getAppId());
+ addElementIfNotEmpty(xml, "mch_id", configDto.getMerchantId());
+ payMap.put("mch_id", configDto.getMerchantId());
+ addElementIfNotEmpty(xml, "sub_mch_id", paramsDto.getMerchantId());
+ payMap.put("sub_mch_id", paramsDto.getMerchantId());
+ addElementIfNotEmpty(xml, "nonce_str", nonceStr);
+ payMap.put("nonce_str", nonceStr);
+ addElementIfNotEmpty(xml, "body", paramsDto.getTitle());
+ payMap.put("body", paramsDto.getTitle());
+ addElementIfNotEmpty(xml, "out_trade_no", paramsDto.getOrderNo());
+ payMap.put("out_trade_no", paramsDto.getOrderNo());
+ addElementIfNotEmpty(xml, "total_fee", paramsDto.getAmount());
+ payMap.put("total_fee", paramsDto.getAmount());
+ addElementIfNotEmpty(xml, "spbill_create_ip", paramsDto.getClientIp());
+ payMap.put("spbill_create_ip", paramsDto.getClientIp());
+ addElementIfNotEmpty(xml, "auth_code", paramsDto.getBarCode());
+ payMap.put("auth_code", paramsDto.getBarCode());
+
+ if (StrUtil.isNotBlank(paramsDto.getExtData())) {
+ addElementIfNotEmpty(xml, "attach", paramsDto.getExtData());
+ payMap.put("attach", paramsDto.getExtData());
+ }
+
+ String sign = signBarPayParam(configDto, payMap);
+ addElementIfNotEmpty(xml, "sign", sign);
+
+ OutputFormat format = OutputFormat.createPrettyPrint();
+ XMLWriter writer = new XMLWriter(System.out, format);
+ writer.write(document);
+
+ String xmlStr = document.asXML();
+ log.info("微信条码支付参数:{}", xmlStr);
+
+ String post = HttpUtil.post(BAR_PAY_URL, xmlStr);
+ log.info("微信条码支付请求结果: orderNo = {}, res = {}", paramsDto.getOrderNo(), post);
+
+ JSONObject res = new JSONObject();
+ res.put("orderNo", paramsDto.getOrderNo());
+
+ SAXReader saxReader = new SAXReader();
+ Document read = saxReader.read(stringToInputStream(post));
+ Element rootElement = read.getRootElement();
+ String returnCode = rootElement.elementText("return_code");
+
+ String errCode = rootElement.elementText("err_code");
+ String errCodeDes = rootElement.elementText("err_code_des");
+ res.put("message", errCodeDes);
+
+ if (StrUtil.isNotBlank(errCode)) {
+ if ("SYSTEMERROR".equals(errCode) || "BANKERROR".equals(errCode) || "USERPAYING".equals(errCode)) {
+ // 等待结果
+ log.info("微信条码支付等待结果: orderNo = {}, err {}", paramsDto.getOrderNo(), errCodeDes);
+ res.put("status", "TRADE_AWAIT");
+ return res;
+ }
+
+ res.put("status", "TRADE_FAIL");
+ return res;
+ }
+
+ if (!PAY_SUCCESS.equals(returnCode)) {
+ log.error("微信条码支付失败: orderNo = {}, msg = {}", paramsDto.getOrderNo(), rootElement.elementText("return_msg"));
+ res.put("status", "TRADE_FAIL");
+ return res;
+ }
+
+ // 支付成功
+ log.info("微信条码支付成功: orderNo = {}, msg = {}", paramsDto.getOrderNo(), rootElement.elementText("return_msg"));
+ res.put("status", "TRADE_SUCCESS");
+ return res;
+ } catch (CzgException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("微信条码支付异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage());
+ throw new CzgException("微信支付异常");
+ }
+ }
+
+ /**
+ * 将String转换为InputStream
+ * @param str 待转换的字符串
+ * @return 转换后的InputStream
+ */
+ private static InputStream stringToInputStream(String str) {
+ if (str == null || str.isEmpty()) {
+ return new ByteArrayInputStream(new byte[0]);
+ }
+ // 核心:先转字节数组,再封装为ByteArrayInputStream
+ byte[] byteArray = str.getBytes(StandardCharsets.UTF_8);
+ return new ByteArrayInputStream(byteArray);
+ }
+
+ private static String signBarPayParam(WechatPayConfigDto configDto, Map params) {
+ TreeMap sortedParams = new TreeMap<>(params);
+ String sortParam = sortedParams.entrySet().stream()
+ // 将每个键值对转换为 "key=value" 格式的字符串
+ .map(entry -> entry.getKey() + "=" + (entry.getValue() == null ? "" : entry.getValue()))
+ // 使用 "&" 连接所有转换后的字符串
+ .collect(Collectors.joining("&"));
+ log.info("微信条码支付 加密前参数: {}", sortParam);
+
+ String signStr = sortParam + "&key=" + configDto.getApiV2Key();
+ return SecureUtil.md5(signStr).toUpperCase();
+ }
+
+ /**
+ * 添加元素,包括空值
+ */
+ private static void addElementIfNotEmpty(Element parent, String name, Object value) {
+ Element element = parent.addElement(name);
+ element.addText(value == null ? "" : String.valueOf(value));
+ }
+
+ public static void main(String[] args) {
+ barPay(null, new PayParamsDto()
+ .setMerchantId("1738216504")
+ .setOrderNo("sa101293120sss1")
+ .setTitle("1213")
+ .setBody("1213")
+ .setAmount(1L)
+ .setAppId("wxd88fffa983758a30")
+ .setClientIp("127.0.0.1")
+ .setBarCode("130013153082460022"));
}
}
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java
index 6bf217918..ad2885200 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java
@@ -59,7 +59,7 @@ public class WechatReqUtils {
.header("Wechatpay-Serial", configDto.getPublicKeyId())
.charset(StandardCharsets.UTF_8)
.contentType("application/json")
- .body(body );
+ .body(body);
case "GET" -> HttpUtil.createGet(configDto.getDomain() + url)
.header("Authorization", authorization)
diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/dto/config/WechatPayConfigDto.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/dto/config/WechatPayConfigDto.java
index 78e544e8b..c1b303ed3 100644
--- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/dto/config/WechatPayConfigDto.java
+++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/dto/config/WechatPayConfigDto.java
@@ -21,6 +21,11 @@ public class WechatPayConfigDto {
*/
private String apiV3Key;
+ /**
+ * Api V2 密钥
+ */
+ private String apiV2Key;
+
/**
* 商户证书序列号
*/
@@ -51,6 +56,7 @@ public class WechatPayConfigDto {
return new WechatPayConfigDto()
.setMerchantId("1643779408")
.setApiV3Key("a92baac5eb7a36ed8ec198113e769a03")
+ .setApiV2Key("3caf37225b6ea77a624ee03b7e3d03bb")
.setSerialNumber("4DE9BAC2EA584C3F274F694C9753CA814C4E9BF4")
.setPublicKey("""
-----BEGIN PUBLIC KEY-----