From d9cff67a1f60c6850c4c556f182948dfdfcbe866 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=A3=B7=E5=8F=B6?=
<14103883+leaf-phos@user.noreply.gitee.com>
Date: Wed, 8 Jan 2025 14:54:47 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../smart-switch-common/pom.xml | 1 -
.../java/com/ruoyi/common/pay/Payable.java | 5 +
.../common/pay/syb/service/SybPayService.java | 2 +-
.../common/pay/xy/config/XyPayConfig.java | 24 +++
.../pay/xy/constants/XyPayConstants.java | 18 ++
.../common/pay/xy/service/XyWxPayService.java | 105 +++++++++++
.../ruoyi/common/pay/xy/utils/Base64Util.java | 113 ++++++++++++
.../ruoyi/common/pay/xy/utils/HttpUtil.java | 85 +++++++++
.../ruoyi/common/pay/xy/utils/RSAUtil.java | 78 ++++++++
.../com/ruoyi/common/pay/xy/utils/SHA256.java | 53 ++++++
.../ruoyi/common/pay/xy/utils/XyPayUtil.java | 27 +++
.../java/com/ruoyi/ss/app/domain/App.java | 37 ++++
.../com/ruoyi/ss/app/domain/AppQuery.java | 11 ++
.../java/com/ruoyi/ss/app/domain/AppVO.java | 11 ++
.../com/ruoyi/ss/app/mapper/AppMapper.java | 75 ++++++++
.../com/ruoyi/ss/app/mapper/AppMapper.xml | 170 ++++++++++++++++++
.../com/ruoyi/ss/app/service/AppService.java | 64 +++++++
.../ss/app/service/impl/AppServiceImpl.java | 98 ++++++++++
.../ss/channel/domain/ChannelConfig.java | 11 +-
.../channel/domain/enums/ChannelApiType.java | 14 +-
.../ruoyi/ss/channel/mapper/ChannelMapper.xml | 6 +-
.../service/impl/ChannelConverterImpl.java | 56 +++++-
.../service/impl/ChannelServiceImpl.java | 2 +
.../com/ruoyi/ss/payBill/domain/PayBill.java | 12 ++
.../ruoyi/ss/payBill/mapper/PayBillMapper.xml | 7 +-
.../service/impl/PayBillConverterImpl.java | 2 +
.../service/impl/PayBillServiceImpl.java | 27 ++-
.../service/impl/RefundServiceImpl.java | 40 +++--
.../domain/TransactionBill.java | 44 +----
.../web/controller/app/AppPayController.java | 43 +++--
.../web/controller/ss/AppController.java | 101 +++++++++++
.../src/main/resources/application.yml | 4 -
32 files changed, 1245 insertions(+), 101 deletions(-)
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/config/XyPayConfig.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/constants/XyPayConstants.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/service/XyWxPayService.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/Base64Util.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/HttpUtil.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/RSAUtil.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/SHA256.java
create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/XyPayUtil.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/App.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppQuery.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppVO.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.xml
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/service/AppService.java
create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/app/service/impl/AppServiceImpl.java
create mode 100644 smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/AppController.java
diff --git a/smart-switch-ruoyi/smart-switch-common/pom.xml b/smart-switch-ruoyi/smart-switch-common/pom.xml
index d3590b6c..920ec509 100644
--- a/smart-switch-ruoyi/smart-switch-common/pom.xml
+++ b/smart-switch-ruoyi/smart-switch-common/pom.xml
@@ -78,7 +78,6 @@
org.apache.httpcomponents
httpclient
- 4.2.1
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/Payable.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/Payable.java
index 04cf839d..cd249262 100644
--- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/Payable.java
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/Payable.java
@@ -40,4 +40,9 @@ public interface Payable {
* 获取openId
*/
String payableOpenId();
+
+ /**
+ * 获取支付者IP
+ */
+ String payableIp();
}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java
index a74adaad..f262d324 100644
--- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java
@@ -130,7 +130,7 @@ public class SybPayService implements PayApi {
@Override
public boolean isPaySuccessByOutTradeNo(String outTradeNo, Object config) {
- return isPaySuccess(this.queryByOutTradeNo(outTradeNo, ));
+ return isPaySuccess(this.queryByOutTradeNo(outTradeNo, config));
}
@Override
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/config/XyPayConfig.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/config/XyPayConfig.java
new file mode 100644
index 00000000..32e66349
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/config/XyPayConfig.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.pay.xy.config;
+
+import lombok.Data;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+@Data
+public class XyPayConfig {
+
+ // 公钥
+ private String publicKey;
+
+ // 机构号 商户所在国通系统内机构号(或虚拟机构号)
+ private String agetId;
+
+ // 商户号 商户所在国通系统内商户号
+ private String custId;
+
+ // 请求主机
+ private String host;
+
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/constants/XyPayConstants.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/constants/XyPayConstants.java
new file mode 100644
index 00000000..33528c7e
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/constants/XyPayConstants.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.pay.xy.constants;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+public class XyPayConstants {
+
+ // 支付方式:微信小程序
+ public static final String PAY_WAY_WX = "1";
+
+ // 支付方式:支付宝
+ public static final String PAY_WAY_ALIPAY = "2";
+
+ // 支付方式:银联
+ public static final String PAY_WAY_UNION = "3";
+
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/service/XyWxPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/service/XyWxPayService.java
new file mode 100644
index 00000000..a4552f47
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/service/XyWxPayService.java
@@ -0,0 +1,105 @@
+package com.ruoyi.common.pay.xy.service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.pay.PayApi;
+import com.ruoyi.common.pay.Payable;
+import com.ruoyi.common.pay.Refundable;
+import com.ruoyi.common.pay.xy.config.XyPayConfig;
+import com.ruoyi.common.pay.xy.constants.XyPayConstants;
+import com.ruoyi.common.pay.xy.utils.HttpUtil;
+import com.ruoyi.common.pay.xy.utils.XyPayUtil;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.ServiceUtil;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Objects;
+import java.util.TreeMap;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+@Service
+@Slf4j
+public class XyWxPayService implements PayApi {
+ @Override
+ public Object pay(Payable payable, Object config) {
+ XyPayConfig payConfig = (XyPayConfig) config;
+
+ // 请求地址
+ String url = payConfig.getHost() + "/yyfsevr/order/pay";
+
+ // 请求参数
+ TreeMap params = new TreeMap<>();
+ params.put("agetId", payConfig.getAgetId());
+ params.put("custId", payConfig.getCustId());
+ params.put("orderNo", payable.payableOutTradeNo());
+ params.put("txamt", payable.payableFen());
+ params.put("openid", payable.payableOpenId());
+ params.put("payWay", XyPayConstants.PAY_WAY_WX);
+ params.put("ip", payable.payableIp());
+ params.put("timeStamp", DateUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss"));
+ params.put("version", "1.0.0");
+
+ // 参数签名
+ params.put("sign", XyPayUtil.encrypt(params, payConfig.getPublicKey()));
+
+ // 发送请求
+ try {
+ String response = HttpUtil.postData(url, params);
+ ServiceUtil.assertion(response == null, "响应结果为空");
+ JSONObject json = JSONObject.parseObject(response);
+ String code = json.getString("code");
+ if (Objects.equals("000000", code)) {
+ JSONObject data = json.getJSONObject("data");
+ ServiceUtil.assertion(data == null, "响应数据为空");
+ PrepayWithRequestPaymentResponse result = new PrepayWithRequestPaymentResponse();
+ result.setAppId(data.getString("jsapiAppid"));
+ result.setTimeStamp(data.getString("jsapiTimestamp"));
+ result.setNonceStr(data.getString("jsapiNoncestr"));
+ result.setPackageVal(data.getString("jsapiPackage"));
+ result.setSignType(data.getString("jsapiSignType"));
+ result.setPaySign(data.getString("jsapiPaySign"));
+ return result;
+ }
+ } catch (Exception e) {
+ log.error("支付请求失败:" + e.getMessage());
+ return null;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void closeByOutTradeNo(String outTradeNo, Object config) {
+
+ }
+
+ @Override
+ public Object queryByOutTradeNo(String outTradeNo, Object config) {
+ return null;
+ }
+
+ @Override
+ public Object refund(Refundable refundAble, Object config) {
+ return null;
+ }
+
+ @Override
+ public boolean isPaySuccessByOutTradeNo(String outTradeNo, Object config) {
+ return false;
+ }
+
+ @Override
+ public boolean isPaySuccess(Object result) {
+ return false;
+ }
+
+ @Override
+ public LocalDateTime getPayTime(Object result) {
+ return null;
+ }
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/Base64Util.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/Base64Util.java
new file mode 100644
index 00000000..c005f236
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/Base64Util.java
@@ -0,0 +1,113 @@
+package com.ruoyi.common.pay.xy.utils;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+public class Base64Util {
+
+ private static final char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
+
+ private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 };
+
+ private Base64Util() {}
+
+ /**
+ * 将字节数组编码为字符串
+ *
+ * @param data
+ */
+ public static String encode(byte[] data) {
+ StringBuffer sb = new StringBuffer();
+ int len = data.length;
+ int i = 0;
+ int b1, b2, b3;
+
+ while (i < len) {
+ b1 = data[i++] & 0xff;
+ if (i == len) {
+ sb.append(base64EncodeChars[b1 >>> 2]);
+ sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
+ sb.append("==");
+ break;
+ }
+ b2 = data[i++] & 0xff;
+ if (i == len) {
+ sb.append(base64EncodeChars[b1 >>> 2]);
+ sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
+ sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
+ sb.append("=");
+ break;
+ }
+ b3 = data[i++] & 0xff;
+ sb.append(base64EncodeChars[b1 >>> 2]);
+ sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
+ sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
+ sb.append(base64EncodeChars[b3 & 0x3f]);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 将base64字符串解码为字节数组
+ *
+ * @param str
+ */
+ public static byte[] decode(String str) throws Exception{
+ byte[] data = str.getBytes("GBK");
+
+ int len = data.length;
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
+ int i = 0;
+ int b1, b2, b3, b4;
+
+ while (i < len) {
+
+ /* b1 */
+ do {
+ b1 = base64DecodeChars[data[i++]];
+ } while (i < len && b1 == -1);
+ if (b1 == -1) {
+ break;
+ }
+
+ /* b2 */
+ do {
+ b2 = base64DecodeChars[data[i++]];
+ } while (i < len && b2 == -1);
+ if (b2 == -1) {
+ break;
+ }
+ buf.write((int) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
+
+ /* b3 */
+ do {
+ b3 = data[i++];
+ if (b3 == 61) {
+ return buf.toByteArray();
+ }
+ b3 = base64DecodeChars[b3];
+ } while (i < len && b3 == -1);
+ if (b3 == -1) {
+ break;
+ }
+ buf.write((int) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
+
+ /* b4 */
+ do {
+ b4 = data[i++];
+ if (b4 == 61) {
+ return buf.toByteArray();
+ }
+ b4 = base64DecodeChars[b4];
+ } while (i < len && b4 == -1);
+ if (b4 == -1) {
+ break;
+ }
+ buf.write((int) (((b3 & 0x03) << 6) | b4));
+ }
+ return buf.toByteArray();
+ }
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/HttpUtil.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/HttpUtil.java
new file mode 100644
index 00000000..01ff63ae
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/HttpUtil.java
@@ -0,0 +1,85 @@
+package com.ruoyi.common.pay.xy.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.SocketTimeoutException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+@Slf4j
+public class HttpUtil {
+
+ public static String postData(String url, Map params) throws UnsupportedEncodingException {
+ String json = JSONObject.toJSONString(params);
+ return postData(url, json, StandardCharsets.UTF_8);
+ }
+
+ public static String postData(String url, String json, Charset responseCharset) throws UnsupportedEncodingException {
+ log.info("请求地址:" + url);
+ HttpPost httpPost = new HttpPost(url);
+ setTimeOut(httpPost);
+ log.info("连接成功");
+ StringEntity requestEntity = new StringEntity(json, "UTF-8");
+ requestEntity.setContentEncoding("UTF-8");
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setEntity(requestEntity);
+ log.info("请求报文:" + json);
+ return execute(httpPost, responseCharset);
+ }
+
+ private static void setTimeOut(HttpRequestBase httpRequest) {
+ //设置超时时间 请求超时时间 30s
+ RequestConfig config = RequestConfig.custom()
+ // 设置连接超时时间(单位毫秒)
+ .setConnectTimeout(30000)
+ // 设置请求超时时间(单位毫秒)
+ .setConnectionRequestTimeout(30000)
+ // socket读写超时时间(单位毫秒)
+ .setSocketTimeout(30000).build();
+ httpRequest.setConfig(config);
+ }
+
+ private static String execute(HttpRequestBase httpRequest, Charset responseCharset) {
+ log.info("开始请求————————");
+ log.info("请求中------------------");
+ long start = System.currentTimeMillis();
+ String result = "";
+ try (CloseableHttpClient httpClient = HttpClientBuilder.create().build();
+ CloseableHttpResponse response = httpClient.execute(httpRequest)) {
+ long end = System.currentTimeMillis();
+ log.info("请求结束————————");
+ log.info("响应时间:" + (end - start));
+ if (response != null) {
+ // 从响应模型中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+ log.info("响应状态为:" + response.getStatusLine());
+ if (responseEntity != null) {
+ log.info("响应内容长度为:" + responseEntity.getContentLength());
+ result = EntityUtils.toString(responseEntity, responseCharset);
+ log.info("响应内容为:" + result);
+ }
+ }
+ } catch (SocketTimeoutException s) {
+ log.error("请求超时", s);
+ } catch (Exception e) {
+ log.error("请求处理异常", e);
+ }
+ return result;
+ }
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/RSAUtil.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/RSAUtil.java
new file mode 100644
index 00000000..99e2258c
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/RSAUtil.java
@@ -0,0 +1,78 @@
+package com.ruoyi.common.pay.xy.utils;
+
+import sun.misc.BASE64Decoder;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+public class RSAUtil {
+
+ /**
+ * 使用公钥对明文进行签名
+ *
+ * @param publicKey 公钥
+ * @param plainText 明文
+ * @return
+ */
+ public static String encrypt(String publicKey, String plainText) {
+ try {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
+ byte[] bytes = plainText.getBytes();
+ ByteArrayInputStream read = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream write = new ByteArrayOutputStream();
+ byte[] buf = new byte[117];
+ int len = 0;
+ while ((len = read.read(buf)) != -1) {
+ byte[] buf1 = null;
+ if (buf.length == len) {
+ buf1 = buf;
+ } else {
+ buf1 = new byte[len];
+ for (int i = 0; i < len; i++) {
+ buf1[i] = buf[i];
+ }
+ }
+ byte[] bytes1 = cipher.doFinal(buf1);
+ write.write(bytes1);
+ }
+ return Base64Util.encode(write.toByteArray());
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 得到公钥
+ *
+ * @param key 密钥字符串(经过base64编码�?
+ * @throws Exception
+ */
+ public static PublicKey getPublicKey(String key) throws Exception {
+ byte[] keyBytes;
+ keyBytes = new BASE64Decoder().decodeBuffer(key);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PublicKey publicKey = keyFactory.generatePublic(keySpec);
+ return publicKey;
+ }
+
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/SHA256.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/SHA256.java
new file mode 100644
index 00000000..3f2f8e9c
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/SHA256.java
@@ -0,0 +1,53 @@
+package com.ruoyi.common.pay.xy.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+public class SHA256 {
+
+ /**
+ * 利用java原生的类实现SHA256加密
+ *
+ * @param str 加密后的报文
+ * @return
+ */
+ public static String getSHA256(String str) {
+ MessageDigest messageDigest;
+ String encodestr = "";
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
+ encodestr = byte2Hex(messageDigest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ return encodestr;
+ }
+
+
+ /**
+ * 将byte转为16进制
+ *
+ * @param bytes
+ * @return
+ */
+ private static String byte2Hex(byte[] bytes) {
+ StringBuffer stringBuffer = new StringBuffer();
+ String temp = null;
+ for (int i = 0; i < bytes.length; i++) {
+ temp = Integer.toHexString(bytes[i] & 0xFF);
+ if (temp.length() == 1) {
+ stringBuffer.append("0");
+ }
+ stringBuffer.append(temp);
+ }
+ return stringBuffer.toString();
+ }
+
+
+}
diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/XyPayUtil.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/XyPayUtil.java
new file mode 100644
index 00000000..e6d88f4f
--- /dev/null
+++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/xy/utils/XyPayUtil.java
@@ -0,0 +1,27 @@
+package com.ruoyi.common.pay.xy.utils;
+
+import java.util.TreeMap;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+public class XyPayUtil {
+
+ /**
+ * 生成签名
+ * @param params 待签名参数
+ * @param publicKey 公钥
+ */
+ public static String encrypt(TreeMap params, String publicKey) {
+
+ StringBuilder sb = new StringBuilder();
+ for (String key : params.keySet()) {
+ sb.append(key).append("=").append(params.get(key)).append("&");
+ }
+ String res = sb.substring(0, sb.lastIndexOf("&"));
+ String sha256 = SHA256.getSHA256(res);
+ return RSAUtil.encrypt(publicKey, sha256);
+ }
+
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/App.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/App.java
new file mode 100644
index 00000000..25ac8601
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/App.java
@@ -0,0 +1,37 @@
+package com.ruoyi.ss.app.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * APP信息对象 ss_app
+ *
+ * @author ruoyi
+ * @date 2025-01-08
+ */
+@Data
+public class App extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ private Long id;
+
+ @Excel(name = "应用名称")
+ @ApiModelProperty("应用名称")
+ private String name;
+
+ @Excel(name = "应用类型", readConverterExp = "1=微信小程序,2=支付宝小程序")
+ @ApiModelProperty("应用类型")
+ private String type;
+
+ @Excel(name = "应用ID")
+ @ApiModelProperty("应用ID")
+ private String appId;
+
+ @Excel(name = "应用秘钥")
+ @ApiModelProperty("应用秘钥")
+ private String appSecret;
+
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppQuery.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppQuery.java
new file mode 100644
index 00000000..f6ba4b70
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppQuery.java
@@ -0,0 +1,11 @@
+package com.ruoyi.ss.app.domain;
+
+import lombok.Data;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+@Data
+public class AppQuery extends AppVO{
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppVO.java
new file mode 100644
index 00000000..ca37787d
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/domain/AppVO.java
@@ -0,0 +1,11 @@
+package com.ruoyi.ss.app.domain;
+
+import lombok.Data;
+
+/**
+ * @author wjh
+ * 2025/1/8
+ */
+@Data
+public class AppVO extends App {
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.java
new file mode 100644
index 00000000..d47ee45f
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.java
@@ -0,0 +1,75 @@
+package com.ruoyi.ss.app.mapper;
+
+import com.ruoyi.ss.app.domain.App;
+import com.ruoyi.ss.app.domain.AppQuery;
+import com.ruoyi.ss.app.domain.AppVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * APP信息Mapper接口
+ *
+ * @author ruoyi
+ * @date 2025-01-08
+ */
+public interface AppMapper
+{
+ /**
+ * 查询APP信息
+ *
+ * @param id APP信息主键
+ * @return APP信息
+ */
+ AppVO selectAppById(Long id);
+
+ /**
+ * 查询APP信息列表
+ *
+ * @param query APP信息
+ * @return APP信息集合
+ */
+ List selectAppList(@Param("query")AppQuery query);
+
+ /**
+ * 新增APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ int insertApp(App app);
+
+ /**
+ * 批量新增APP信息
+ */
+ int batchInsert(@Param("list") List extends App> list);
+
+ /**
+ * 批量修改APP信息
+ */
+ int batchUpdate(@Param("list") List extends App> list);
+
+ /**
+ * 修改APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ public int updateApp(@Param("data") App app);
+
+ /**
+ * 删除APP信息
+ *
+ * @param id APP信息主键
+ * @return 结果
+ */
+ int deleteAppById(Long id);
+
+ /**
+ * 批量删除APP信息
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteAppByIds(Long[] ids);
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.xml
new file mode 100644
index 00000000..ccc83d11
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/mapper/AppMapper.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+ select
+ sa.id,
+ sa.name,
+ sa.type,
+ sa.app_id,
+ sa.app_secret,
+ sa.create_time
+ from ss_app sa
+
+
+
+ and id = #{query.id}
+ and name like concat('%', #{query.name}, '%')
+ and type = #{query.type}
+ and app_id like concat('%', #{query.appId}, '%')
+ ${query.params.dataScope}
+
+
+
+
+
+
+
+ insert into ss_app
+
+ name,
+ type,
+ app_id,
+ app_secret,
+ create_time,
+
+
+ #{name},
+ #{type},
+ #{appId},
+ #{appSecret},
+ #{createTime},
+
+
+
+
+ insert into ss_app
+
+ name,
+ type,
+ app_id,
+ app_secret,
+ create_time,
+
+ values
+
+
+ #{i.name},
+ default,
+ #{i.type},
+ default,
+ #{i.appId},
+ default,
+ #{i.appSecret},
+ default,
+ #{i.createTime},
+ default,
+
+
+
+
+
+ update ss_app
+
+
+
+
+ WHEN #{item.id} THEN #{item.name}
+
+
+ WHEN #{item.id} THEN `name`
+
+
+
+
+
+
+ WHEN #{item.id} THEN #{item.type}
+
+
+ WHEN #{item.id} THEN `type`
+
+
+
+
+
+
+ WHEN #{item.id} THEN #{item.appId}
+
+
+ WHEN #{item.id} THEN `app_id`
+
+
+
+
+
+
+ WHEN #{item.id} THEN #{item.appSecret}
+
+
+ WHEN #{item.id} THEN `app_secret`
+
+
+
+
+
+
+ WHEN #{item.id} THEN #{item.createTime}
+
+
+ WHEN #{item.id} THEN `create_time`
+
+
+
+
+ where id in
+
+ #{item.id}
+
+
+
+
+ update ss_app
+
+
+
+ where id = #{data.id}
+
+
+
+ name = #{data.name},
+ type = #{data.type},
+ app_id = #{data.appId},
+ app_secret = #{data.appSecret},
+ create_time = #{data.createTime},
+
+
+
+ delete from ss_app where id = #{id}
+
+
+
+ delete from ss_app where id in
+
+ #{id}
+
+
+
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/AppService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/AppService.java
new file mode 100644
index 00000000..b527ba6a
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/AppService.java
@@ -0,0 +1,64 @@
+package com.ruoyi.ss.app.service;
+
+import com.ruoyi.ss.app.domain.App;
+import com.ruoyi.ss.app.domain.AppQuery;
+import com.ruoyi.ss.app.domain.AppVO;
+
+import java.util.List;
+
+/**
+ * APP信息Service接口
+ *
+ * @author ruoyi
+ * @date 2025-01-08
+ */
+public interface AppService
+{
+ /**
+ * 查询APP信息
+ *
+ * @param id APP信息主键
+ * @return APP信息
+ */
+ public AppVO selectAppById(Long id);
+
+ /**
+ * 查询APP信息列表
+ *
+ * @param app APP信息
+ * @return APP信息集合
+ */
+ public List selectAppList(AppQuery app);
+
+ /**
+ * 新增APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ public int insertApp(App app);
+
+ /**
+ * 修改APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ public int updateApp(App app);
+
+ /**
+ * 批量删除APP信息
+ *
+ * @param ids 需要删除的APP信息主键集合
+ * @return 结果
+ */
+ public int deleteAppByIds(Long[] ids);
+
+ /**
+ * 删除APP信息信息
+ *
+ * @param id APP信息主键
+ * @return 结果
+ */
+ public int deleteAppById(Long id);
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/impl/AppServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/impl/AppServiceImpl.java
new file mode 100644
index 00000000..e7899c59
--- /dev/null
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/app/service/impl/AppServiceImpl.java
@@ -0,0 +1,98 @@
+package com.ruoyi.ss.app.service.impl;
+
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.ss.app.domain.App;
+import com.ruoyi.ss.app.domain.AppQuery;
+import com.ruoyi.ss.app.domain.AppVO;
+import com.ruoyi.ss.app.mapper.AppMapper;
+import com.ruoyi.ss.app.service.AppService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * APP信息Service业务层处理
+ *
+ * @author ruoyi
+ * @date 2025-01-08
+ */
+@Service
+public class AppServiceImpl implements AppService
+{
+ @Autowired
+ private AppMapper appMapper;
+
+ /**
+ * 查询APP信息
+ *
+ * @param id APP信息主键
+ * @return APP信息
+ */
+ @Override
+ public AppVO selectAppById(Long id)
+ {
+ return appMapper.selectAppById(id);
+ }
+
+ /**
+ * 查询APP信息列表
+ *
+ * @param app APP信息
+ * @return APP信息
+ */
+ @Override
+ public List selectAppList(AppQuery app)
+ {
+ return appMapper.selectAppList(app);
+ }
+
+ /**
+ * 新增APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ @Override
+ public int insertApp(App app)
+ {
+ app.setCreateTime(DateUtils.getNowDate());
+ return appMapper.insertApp(app);
+ }
+
+ /**
+ * 修改APP信息
+ *
+ * @param app APP信息
+ * @return 结果
+ */
+ @Override
+ public int updateApp(App app)
+ {
+ return appMapper.updateApp(app);
+ }
+
+ /**
+ * 批量删除APP信息
+ *
+ * @param ids 需要删除的APP信息主键
+ * @return 结果
+ */
+ @Override
+ public int deleteAppByIds(Long[] ids)
+ {
+ return appMapper.deleteAppByIds(ids);
+ }
+
+ /**
+ * 删除APP信息信息
+ *
+ * @param id APP信息主键
+ * @return 结果
+ */
+ @Override
+ public int deleteAppById(Long id)
+ {
+ return appMapper.deleteAppById(id);
+ }
+}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/ChannelConfig.java b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/ChannelConfig.java
index 11279f5e..3bf07a37 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/ChannelConfig.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/ChannelConfig.java
@@ -21,7 +21,6 @@ public class ChannelConfig {
// 证书序列号
private String merchantSerialNumber;
-
// 支付宝
// 应用私钥
private String privateKey;
@@ -34,7 +33,6 @@ public class ChannelConfig {
// 支付宝根证书地址
private String alipayRootCertPath;
-
// 太米
// 开发者ID
private String developerId;
@@ -43,4 +41,13 @@ public class ChannelConfig {
// 签名Key
private String signKey;
+ // 国通星驿
+ // 公钥
+ private String publicKey;
+ // 机构号 商户所在国通系统内机构号(或虚拟机构号)
+ private String agetId;
+ // 商户号 商户所在国通系统内商户号
+ private String custId;
+ // 请求主机
+ private String host;
}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/enums/ChannelApiType.java b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/enums/ChannelApiType.java
index be79fbf9..c53a5da7 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/enums/ChannelApiType.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/domain/enums/ChannelApiType.java
@@ -5,6 +5,7 @@ import com.ruoyi.common.pay.ali.service.AliPayService;
import com.ruoyi.common.pay.syb.service.SybPayService;
import com.ruoyi.common.pay.tm.TmPayService;
import com.ruoyi.common.pay.wx.service.WxPayService;
+import com.ruoyi.common.pay.xy.service.XyWxPayService;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ss.account.domain.enums.AccountType;
import lombok.AllArgsConstructor;
@@ -29,7 +30,8 @@ public enum ChannelApiType {
BANK("3", "银行卡", AccountType.BANK_CARD, null, false),
BALANCE("4", "余额支付", null, null, true),
TL_WX("5", "通联微信支付", null, SybPayService.class, true),
- TM_WX("6", "太米微信支付", null, TmPayService.class, true);
+ TM_WX("6", "太米微信支付", null, TmPayService.class, true),
+ XY_WX("7", "国通星驿微信支付", null, XyWxPayService.class, true);
private final String type;
private final String name;
@@ -55,9 +57,15 @@ public enum ChannelApiType {
*/
public static PayApi getPayApi(String type) {
ChannelApiType parse = parse(type);
- if (parse == null || parse.getPayApi() == null) {
+ return getPayApi(parse);
+ }
+
+
+ public static PayApi getPayApi(ChannelApiType type) {
+ if (type == null || type.getPayApi() == null) {
return null;
}
- return SpringUtils.getBean(parse.getPayApi());
+ return SpringUtils.getBean(type.getPayApi());
}
}
+
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/mapper/ChannelMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/mapper/ChannelMapper.xml
index 1cf2c363..0d1bd81a 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/mapper/ChannelMapper.xml
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/mapper/ChannelMapper.xml
@@ -23,7 +23,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
sc.api_type,
sc.type,
sc.channel_config,
- sc.deleted
+ sc.deleted,
+ sc.create_time
from sm_channel sc
@@ -70,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
api_type,
type,
channel_config,
+ create_time,
#{channelId},
@@ -83,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{apiType},
#{type},
#{channelConfig,typeHandler=com.ruoyi.ss.channel.mapper.typehandler.ChannelConfigJsonTypeHandler},
+ #{createTime},
@@ -99,6 +102,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
api_type = #{data.apiType},
type = #{data.type},
channel_config = #{data.channelConfig,typeHandler=com.ruoyi.ss.channel.mapper.typehandler.ChannelConfigJsonTypeHandler},
+ create_time = #{data.createTime},
where channel_id = #{data.channelId}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelConverterImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelConverterImpl.java
index 9d7d20bf..13598c4f 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelConverterImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelConverterImpl.java
@@ -1,10 +1,14 @@
package com.ruoyi.ss.channel.service.impl;
+import com.ruoyi.common.auth.ali.AliConfig;
+import com.ruoyi.common.pay.tm.config.TmPayConfig;
import com.ruoyi.common.pay.wx.config.WxPayConfig;
+import com.ruoyi.common.pay.xy.config.XyPayConfig;
import com.ruoyi.ss.channel.domain.ChannelConfig;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.domain.enums.ChannelApiType;
import com.ruoyi.ss.channel.service.ChannelConverter;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -13,6 +17,16 @@ import org.springframework.stereotype.Service;
*/
@Service
public class ChannelConverterImpl implements ChannelConverter {
+
+ @Autowired
+ private WxPayConfig defaultWxPayConfig;
+
+ @Autowired
+ private AliConfig defaultAliConfig;
+
+ @Autowired
+ private TmPayConfig defaultTmConfig;
+
@Override
public Object toConfig(ChannelVO channel) {
if (channel == null || channel.getChannelConfig() == null) {
@@ -21,18 +35,52 @@ public class ChannelConverterImpl implements ChannelConverter {
ChannelConfig channelConfig = channel.getChannelConfig();
+ // 微信
if (ChannelApiType.WECHAT.getType().equals(channel.getApiType())) {
WxPayConfig config = new WxPayConfig();
config.setAppId(channelConfig.getAppId());
config.setMerchantId(channelConfig.getMerchantId());
config.setApiV3Key(channelConfig.getApiV3Key());
- // TODO
- config.setNotifyUrl("");
- config.setRefundNotifyUrl();
+ config.setNotifyUrl(defaultWxPayConfig.getNotifyUrl());
+ config.setRefundNotifyUrl(defaultWxPayConfig.getRefundNotifyUrl());
config.setPrivateKeyPath(channelConfig.getPrivateKeyPath());
config.setMerchantSerialNumber(channelConfig.getMerchantSerialNumber());
return config;
}
- //TODO 其他渠道
+ // 支付宝
+ else if (ChannelApiType.ALI.getType().equals(channel.getApiType())) {
+ AliConfig config = new AliConfig();
+ config.setAppId(channelConfig.getAppId());
+ config.setPrivateKey(channelConfig.getPrivateKey());
+ config.setAesPrivateKey(channelConfig.getAesPrivateKey());
+ config.setNotifyUrl(defaultAliConfig.getNotifyUrl() + "/" + channel.getChannelId());
+ config.setTransferNotifyUrl(defaultAliConfig.getTransferNotifyUrl() + "/" + channel.getChannelId());
+ config.setAppCertPath(channelConfig.getAppCertPath());
+ config.setAlipayCertPath(channelConfig.getAlipayCertPath());
+ config.setAlipayRootCertPath(channelConfig.getAlipayRootCertPath());
+ return config;
+ }
+ // 太米
+ else if (ChannelApiType.TM_WX.getType().equals(channel.getApiType())) {
+ TmPayConfig config = new TmPayConfig();
+ config.setDeveloperId(channelConfig.getDeveloperId());
+ config.setShopId(channelConfig.getShopId());
+ config.setSignKey(channelConfig.getSignKey());
+ config.setHttpUrl(defaultTmConfig.getHttpUrl());
+ config.setSn(defaultTmConfig.getSn());
+ config.setNotifyUrl(defaultTmConfig.getNotifyUrl() + "/" + channel.getChannelId());
+ return config;
+ }
+ // 国通星驿
+ else if (ChannelApiType.XY_WX.getType().equals(channel.getApiType())) {
+ XyPayConfig config = new XyPayConfig();
+ config.setPublicKey(channelConfig.getPublicKey());
+ config.setAgetId(channelConfig.getAgetId());
+ config.setCustId(channelConfig.getCustId());
+ config.setHost(channelConfig.getHost());
+ return config;
+ }
+
+ return null;
}
}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelServiceImpl.java
index cad12b32..c645141a 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/channel/service/impl/ChannelServiceImpl.java
@@ -1,5 +1,6 @@
package com.ruoyi.ss.channel.service.impl;
+import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.account.service.AccountService;
@@ -66,6 +67,7 @@ public class ChannelServiceImpl implements ChannelService
@Override
public int insertSmChannel(Channel channel)
{
+ channel.setCreateTime(DateUtils.getNowDate());
return channelMapper.insertSmChannel(channel);
}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/domain/PayBill.java b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/domain/PayBill.java
index 00eb910c..14dc6282 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/domain/PayBill.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/domain/PayBill.java
@@ -67,6 +67,10 @@ public class PayBill extends BaseEntity implements Payable
@ApiModelProperty("退款中金额")
private BigDecimal refundingAmount;
+ @Excel(name = "付款人IP")
+ @ApiModelProperty("付款人IP")
+ private String ip;
+
/**
* 获取价格(分)
*/
@@ -106,4 +110,12 @@ public class PayBill extends BaseEntity implements Payable
public String payableOpenId() {
return account;
}
+
+ /**
+ * 获取支付者IP
+ */
+ @Override
+ public String payableIp() {
+ return ip;
+ }
}
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml
index d8a99ef7..33cfc198 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml
@@ -24,7 +24,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
spb.account,
spb.channel_cost,
spb.refund_amount,
- spb.refunding_amount
+ spb.refunding_amount,
+ spb.ip
from ss_pay_bill spb
@@ -39,6 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and spb.create_time <= #{query.endCreateTime}
and date(spb.pay_time) >= date(#{query.payDateStart})
and date(spb.pay_time) <= date(#{query.payDateEnd})
+ and ip like concat('%',#{query.ip},'%')
and spb.status in
@@ -112,6 +114,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
channel_cost,
refund_amount,
refunding_amount,
+ ip,
#{payNo},
@@ -127,6 +130,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{channelCost},
#{refundAmount},
#{refundingAmount},
+ #{ip},
@@ -165,6 +169,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
channel_cost = #{data.channelCost},
refund_amount = #{data.refundAmount},
refunding_amount = #{data.refundingAmount},
+ ip = #{data.ip},
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillConverterImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillConverterImpl.java
index e444e474..118deb20 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillConverterImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillConverterImpl.java
@@ -1,5 +1,6 @@
package com.ruoyi.ss.payBill.service.impl;
+import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.domain.enums.ChannelPlatform;
import com.ruoyi.ss.channel.service.ChannelService;
@@ -70,6 +71,7 @@ public class PayBillConverterImpl implements PayBillConverter {
po.setStatus(PayBillStatus.WAIT_PAY.getStatus());
po.setDescription("充值订单:" + order.getBillNo());
po.setChannelCost(this.calcChannelCost(channel, order.getMoney()));
+ po.setIp(IpUtils.getIpAddr());
// 支付人
if (ChannelPlatform.WX.getCode().equals(channel.getPlatform())) {
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java
index 51355079..38b5418c 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java
@@ -224,7 +224,7 @@ public class PayBillServiceImpl implements PayBillService
// 关闭支付中的订单
if (PayBillStatus.PAYING.getStatus().equals(bill.getStatus())) {
- // TODO 查询渠道信息
+ // 查询渠道信息
ChannelVO channel = channelService.selectSmChannelByChannelId(bill.getChannelId());
if (channel == null) {
continue;
@@ -338,9 +338,18 @@ public class PayBillServiceImpl implements PayBillService
this.handleSuccess(bill.getPayNo(), LocalDateTime.now());
}, 1L, TimeUnit.SECONDS);
} else {
- PayApi payApi = ChannelApiType.getPayApi(bill.getChannelId());
- ServiceUtil.assertion(payApi == null, "暂不支持该支付方式");
- vo.setPayParams(payApi.pay(bill, ));
+ // 获取渠道信息
+ ChannelVO channel = channelService.selectSmChannelByChannelId(bill.getChannelId());
+ ServiceUtil.assertion(channel == null, "ID为%s的支付渠道不存在", bill.getChannelId());
+ ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "支付渠道【%s】不可用", channel.getName());
+
+ // 获取API
+ PayApi payApi = ChannelApiType.getPayApi(channel.getApiType());
+ ServiceUtil.assertion(payApi == null, "当前支付渠道开发中,请尝试其他渠道");
+
+ // 调用API发起支付
+ vo.setPayParams(payApi.pay(bill, channelConverter.toConfig(channel)));
+
// 异步刷新支付结果
scheduledExecutorService.schedule(() -> {
this.refreshPayResultMaxCount(bill, 20L, TimeUnit.SECONDS, 10);
@@ -517,14 +526,20 @@ public class PayBillServiceImpl implements PayBillService
return PayResultVO.success(LocalDateTime.now());
}
+ // 获取渠道
+ ChannelVO channel = channelService.selectSmChannelByChannelId(bill.getChannelId());
+ if (channel == null) {
+ return PayResultVO.fail(String.format("ID为%s的支付渠道不存在", bill.getChannelId()));
+ }
+
// 获取支付API
- PayApi payApi = ChannelApiType.getPayApi(bill.getChannelId());
+ PayApi payApi = ChannelApiType.getPayApi(channel.getApiType());
if (payApi == null) {
return PayResultVO.fail("暂不支持该支付方式");
}
// 获取支付结果
- Object result = payApi.queryByOutTradeNo(bill.getPayNo(), );
+ Object result = payApi.queryByOutTradeNo(bill.getPayNo(), channelConverter.toConfig(channel));
if (payApi.isPaySuccess(result)) {
return PayResultVO.success(payApi.getPayTime(result), result);
} else {
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java
index 6b68ea1a..5d0a3759 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java
@@ -3,13 +3,13 @@ package com.ruoyi.ss.refund.service.impl;
import com.ruoyi.common.domain.vo.LocalDateDecimalVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.PayApi;
-import com.ruoyi.common.pay.syb.service.SybPayService;
-import com.ruoyi.common.pay.tm.TmPayService;
-import com.ruoyi.common.pay.wx.service.WxPayService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.SnowFlakeUtil;
+import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.domain.enums.ChannelApiType;
+import com.ruoyi.ss.channel.service.ChannelConverter;
+import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.payBill.service.PayBillService;
import com.ruoyi.ss.refund.domain.Refund;
import com.ruoyi.ss.refund.domain.RefundQuery;
@@ -45,20 +45,17 @@ public class RefundServiceImpl implements RefundService
@Autowired
private TransactionBillService transactionBillService;
- @Autowired
- private WxPayService wxPayService;
-
@Autowired
private PayBillService payBillService;
- @Autowired
- private SybPayService sybPayService;
-
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Autowired
- private TmPayService tmPayService;
+ private ChannelService channelService;
+
+ @Autowired
+ private ChannelConverter channelConverter;
/**
@@ -191,16 +188,25 @@ public class RefundServiceImpl implements RefundService
RefundVO vo = this.selectRefundByRefundNo(refund.getRefundNo());
- // 发起退款
- PayApi payApi = ChannelApiType.getPayApi(refund.getChannelId());
- if (payApi == null) {
- throw new ServiceException("当前支付方式不支持退款");
+ // 获取渠道信息
+ ChannelVO channel = channelService.selectSmChannelByChannelId(refund.getChannelId());
+ ServiceUtil.assertion(channel == null, "ID为%s的支付渠道不存在", refund.getChannelId());
+
+ // 获取API
+ ChannelApiType channelApiType = ChannelApiType.parse(channel.getApiType());
+ if (channelApiType == null) {
+ throw new ServiceException("当前退款API开发中,请稍后重试");
}
- payApi.refund(vo, );
+ PayApi payApi = ChannelApiType.getPayApi(channelApiType);
+ if (payApi == null) {
+ throw new ServiceException("当前退款API开发中,请稍后重试");
+ }
+
+ // 调用API退款
+ payApi.refund(vo, channelConverter.toConfig(channel));
// 判断是否同步通知,若是则直接处理支付成功
- ChannelApiType channelApiType = ChannelApiType.parse(refund.getChannelId());
- if (channelApiType != null && channelApiType.getIsRefundSync() != null && channelApiType.getIsRefundSync()) {
+ if (channelApiType.getIsRefundSync() != null && channelApiType.getIsRefundSync()) {
scheduledExecutorService.schedule(() -> {
this.handleRefundSuccess(refund.getRefundNo());
}, 10, TimeUnit.SECONDS);
diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java
index 792164c3..7225f93e 100644
--- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java
+++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java
@@ -7,9 +7,6 @@ import com.ruoyi.common.constants.DictTypeConstants;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.domain.ValidGroup;
-import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillType;
-import com.ruoyi.common.pay.Payable;
-import com.ruoyi.common.pay.wx.domain.enums.AttachEnums;
import com.ruoyi.system.valid.DictValid;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -29,7 +26,7 @@ import java.util.List;
* @date 2024-02-21
*/
@Data
-public class TransactionBill extends BaseEntity implements Payable
+public class TransactionBill extends BaseEntity
{
private static final long serialVersionUID = 1L;
@@ -332,43 +329,4 @@ public class TransactionBill extends BaseEntity implements Payable
@ApiModelProperty("商户展示手机号缴费状态")
private String mchShowMobileStatus;
- /**
- * 获取价格(分)
- */
- @Override
- public BigDecimal payableFen() {
- return money.multiply(BigDecimal.valueOf(100));
- }
-
- /**
- * 获取描述
- */
- @Override
- public String payableDescription() {
- return TransactionBillType.parse(type).getDescription();
- }
-
- /**
- * 获取附加信息
- */
- @Override
- public String payableAttach() {
- return AttachEnums.TRANSACTION_BILL.getAttach();
- }
-
- /**
- * 获取外部订单号
- */
- @Override
- public String payableOutTradeNo() {
- return billNo;
- }
-
- /**
- * 获取微信openId
- */
- @Override
- public String payableOpenId() {
- return accountNo;
- }
}
diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java
index d8876430..5af198f2 100644
--- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java
+++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java
@@ -20,12 +20,12 @@ import com.ruoyi.common.pay.wx.domain.enums.WxNotifyEventType;
import com.ruoyi.common.pay.wx.domain.enums.WxTransferBatchStatus;
import com.ruoyi.common.pay.wx.util.WxPayUtil;
import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.http.HttpUtils;
-import com.ruoyi.ss.channel.domain.enums.ChannelApiType;
+import com.ruoyi.ss.channel.domain.ChannelVO;
+import com.ruoyi.ss.channel.service.ChannelService;
import com.ruoyi.ss.payBill.service.PayBillService;
import com.ruoyi.ss.refund.service.RefundService;
-import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
-import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.transactionBill.service.TransactionBillConverter;
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
import com.wechat.pay.java.core.exception.ValidationException;
@@ -78,15 +78,19 @@ public class AppPayController extends BaseController {
@Autowired
private AliPayService aliPayService;
+ @Autowired
+ private ChannelService channelService;
+
@ApiOperation("微信支付充值订单")
@GetMapping("/wx/{billNo}")
public AjaxResult wxPay(@PathVariable @ApiParam("订单编号") String billNo) {
- TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(billNo);
- if (bill == null || bill.getUserId() == null || !bill.getUserId().equals(getUserId())) {
- return error("这不是您的订单");
- }
- RechargePayBO bo = transactionBillConverter.toRechargePayBO(bill, ChannelApiType.WECHAT.getType());
- return success(transactionBillService.pay(bo));
+ return error("接口已弃用,请使用/app/bill/pay接口");
+// TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(billNo);
+// if (bill == null || bill.getUserId() == null || !bill.getUserId().equals(getUserId())) {
+// return error("这不是您的订单");
+// }
+// RechargePayBO bo = transactionBillConverter.toRechargePayBO(bill, ChannelApiType.WECHAT.getType());
+// return success(transactionBillService.pay(bo));
}
// 微信支付结果通知
@@ -210,15 +214,17 @@ public class AppPayController extends BaseController {
* 太米微信支付回调
*/
@ApiOperation(value = "太米微信支付回调")
- @PostMapping("/notify/tm")
- public String tmwx(HttpServletRequest request) {
+ @PostMapping("/notify/tm/{channelId}")
+ public String tmwx(HttpServletRequest request, @PathVariable Long channelId) {
try {
String body = HttpUtils.getBody(request);
log.info("【太米微信支付回调】接收对象 : " + body);
// 先把body转成map
Map params = JSON.parseObject(body, Map.class);
- // TODO signKey 验证签名
- boolean sign = tmPayService.validSign(params, null);
+ // 验证签名
+ ChannelVO channel = channelService.selectSmChannelByChannelId(channelId);
+ ServiceUtil.assertion(channel == null || channel.getChannelConfig() == null, "渠道ID为%s的配置为空", channelId);
+ boolean sign = tmPayService.validSign(params, channel.getChannelConfig().getSignKey());
if (sign) {
JSONObject tradeInfo = (JSONObject)params.get("tradeInfo");
String payType = tradeInfo.getString("payType"); // 交易类型
@@ -237,14 +243,16 @@ public class AppPayController extends BaseController {
}
@ApiOperation("支付宝支付通知")
- @PostMapping("/notify/ali")
+ @PostMapping("/notify/ali/{channelId}")
@Anonymous
- public String aliPayNotify(HttpServletRequest request) {
+ public String aliPayNotify(HttpServletRequest request, @PathVariable Long channelId) {
try {
log.info("收到支付宝支付通知{}", request);
Map params = HttpUtils.convertRequestParamsToMap(request);
- // TODO
- aliPayService.checkNotifySign(params, null);
+
+ ChannelVO channel = channelService.selectSmChannelByChannelId(channelId);
+ ServiceUtil.assertion(channel == null || channel.getChannelConfig() == null, "渠道ID为%s的配置为空", channelId);
+ aliPayService.checkNotifySign(params, channel.getChannelConfig().getAlipayCertPath());
log.info("收到支付宝支付通知{}", params);
@@ -274,7 +282,6 @@ public class AppPayController extends BaseController {
return "fail";
}
-
return "success";
}
diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/AppController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/AppController.java
new file mode 100644
index 00000000..025ddabe
--- /dev/null
+++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/AppController.java
@@ -0,0 +1,101 @@
+package com.ruoyi.web.controller.ss;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.ss.app.domain.App;
+import com.ruoyi.ss.app.domain.AppQuery;
+import com.ruoyi.ss.app.domain.AppVO;
+import com.ruoyi.ss.app.service.AppService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * APP信息Controller
+ *
+ * @author ruoyi
+ * @date 2025-01-08
+ */
+@RestController
+@RequestMapping("/ss/app")
+public class AppController extends BaseController
+{
+ @Autowired
+ private AppService appService;
+
+ /**
+ * 查询APP信息列表
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(AppQuery query)
+ {
+ startPage();
+ startOrderBy();
+ List list = appService.selectAppList(query);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出APP信息列表
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:export')")
+ @Log(title = "APP信息", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, AppQuery query)
+ {
+ List list = appService.selectAppList(query);
+ ExcelUtil util = new ExcelUtil(AppVO.class);
+ util.exportExcel(response, list, "APP信息数据");
+ }
+
+ /**
+ * 获取APP信息详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:query')")
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id)
+ {
+ return success(appService.selectAppById(id));
+ }
+
+ /**
+ * 新增APP信息
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:add')")
+ @Log(title = "APP信息", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody App app)
+ {
+ return toAjax(appService.insertApp(app));
+ }
+
+ /**
+ * 修改APP信息
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:edit')")
+ @Log(title = "APP信息", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody App app)
+ {
+ return toAjax(appService.updateApp(app));
+ }
+
+ /**
+ * 删除APP信息
+ */
+ @PreAuthorize("@ss.hasPermi('ss:app:remove')")
+ @Log(title = "APP信息", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids)
+ {
+ return toAjax(appService.deleteAppByIds(ids));
+ }
+}
diff --git a/smart-switch-web/src/main/resources/application.yml b/smart-switch-web/src/main/resources/application.yml
index ac39cef0..49b25179 100644
--- a/smart-switch-web/src/main/resources/application.yml
+++ b/smart-switch-web/src/main/resources/application.yml
@@ -173,10 +173,6 @@ org:
sm:
# 物联网平台地址
iotHost: https://iot-api.heclouds.com
- # 产品id 智能电表
-# productId: SnDlte5gPh
- # 新的id
- productId: 6EX6t0UH7g
# 版本号 签名算法版本
version: 2020-05-29
# 用户资源信息 用户id