feat:钱包接口对接
This commit is contained in:
@@ -103,6 +103,10 @@
|
|||||||
<artifactId>openpdf</artifactId>
|
<artifactId>openpdf</artifactId>
|
||||||
<version>1.3.30</version>
|
<version>1.3.30</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.icepdf.os/icepdf-core -->
|
<!-- https://mvnrepository.com/artifact/org.icepdf.os/icepdf-core -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.icepdf.os</groupId>
|
<groupId>org.icepdf.os</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.cool.store.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 12:15
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
public class KeyFormatUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将单行密钥转换为标准PEM多行格式
|
||||||
|
*/
|
||||||
|
public static String convertToPEMFormat(String singleLineKey, String keyType) {
|
||||||
|
if (singleLineKey == null || singleLineKey.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("密钥不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理密钥,移除可能存在的头尾标记和空白
|
||||||
|
String cleanedKey = cleanKey(singleLineKey);
|
||||||
|
|
||||||
|
// 定义头尾标记
|
||||||
|
String header = getKeyHeader(keyType);
|
||||||
|
String footer = getKeyFooter(keyType);
|
||||||
|
|
||||||
|
// 构建多行格式
|
||||||
|
StringBuilder pemKey = new StringBuilder();
|
||||||
|
pemKey.append(header).append("\n");
|
||||||
|
|
||||||
|
// 每64个字符换行
|
||||||
|
for (int i = 0; i < cleanedKey.length(); i += 64) {
|
||||||
|
int end = Math.min(i + 64, cleanedKey.length());
|
||||||
|
pemKey.append(cleanedKey.substring(i, end)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pemKey.append(footer);
|
||||||
|
return pemKey.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理密钥字符串
|
||||||
|
*/
|
||||||
|
public static String cleanKey(String key) {
|
||||||
|
return key.replaceAll("-----BEGIN.*-----", "")
|
||||||
|
.replaceAll("-----END.*-----", "")
|
||||||
|
.replaceAll("\\s", "") // 移除所有空白字符
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getKeyHeader(String keyType) {
|
||||||
|
switch (keyType.toUpperCase()) {
|
||||||
|
case "PRIVATE":
|
||||||
|
case "PRIVATE_KEY":
|
||||||
|
return "-----BEGIN PRIVATE KEY-----";
|
||||||
|
case "PUBLIC":
|
||||||
|
case "PUBLIC_KEY":
|
||||||
|
return "-----BEGIN PUBLIC KEY-----";
|
||||||
|
case "RSA_PRIVATE":
|
||||||
|
return "-----BEGIN RSA PRIVATE KEY-----";
|
||||||
|
case "RSA_PUBLIC":
|
||||||
|
return "-----BEGIN RSA PUBLIC KEY-----";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("不支持的密钥类型: " + keyType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getKeyFooter(String keyType) {
|
||||||
|
switch (keyType.toUpperCase()) {
|
||||||
|
case "PRIVATE":
|
||||||
|
case "PRIVATE_KEY":
|
||||||
|
return "-----END PRIVATE KEY-----";
|
||||||
|
case "PUBLIC":
|
||||||
|
case "PUBLIC_KEY":
|
||||||
|
return "-----END PUBLIC KEY-----";
|
||||||
|
case "RSA_PRIVATE":
|
||||||
|
return "-----END RSA PRIVATE KEY-----";
|
||||||
|
case "RSA_PUBLIC":
|
||||||
|
return "-----END RSA PUBLIC KEY-----";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("不支持的密钥类型: " + keyType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,85 +112,4 @@ public class OpenSignatureUtil {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造签名串
|
|
||||||
* @param params 参数Map
|
|
||||||
* @return 构造好的签名串
|
|
||||||
*/
|
|
||||||
public static String buildSignString(Map<String, String> params) {
|
|
||||||
return params.entrySet().stream()
|
|
||||||
// 过滤空值字段
|
|
||||||
.filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty())
|
|
||||||
// 按参数名 ASCII 码升序排序
|
|
||||||
.sorted(Map.Entry.comparingByKey())
|
|
||||||
// 格式化为 key=value,值进行URL编码
|
|
||||||
.map(entry -> {
|
|
||||||
try {
|
|
||||||
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
|
|
||||||
return entry.getKey() + "=" + encodedValue;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("URL编码失败", e);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 用 & 连接
|
|
||||||
.collect(Collectors.joining("&"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用私钥对签名串进行 RSA-SHA256 签名
|
|
||||||
* @param signString 待签名的字符串
|
|
||||||
* @param privateKeyStr Base64编码的私钥
|
|
||||||
* @return Base64编码的签名
|
|
||||||
*/
|
|
||||||
public static String signWithRsaSha256(String signString, String privateKeyStr) {
|
|
||||||
try {
|
|
||||||
// 1. 解码Base64私钥
|
|
||||||
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
|
|
||||||
|
|
||||||
// 2. 创建PKCS8编码密钥规范
|
|
||||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
|
|
||||||
|
|
||||||
// 3. 获取RSA KeyFactory
|
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
|
||||||
|
|
||||||
// 4. 生成私钥对象
|
|
||||||
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
|
|
||||||
|
|
||||||
// 5. 创建Signature实例,使用SHA256withRSA算法
|
|
||||||
Signature signature = Signature.getInstance("SHA256withRSA");
|
|
||||||
signature.initSign(privateKey);
|
|
||||||
|
|
||||||
// 6. 更新要签名的数据
|
|
||||||
signature.update(signString.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
// 7. 执行签名
|
|
||||||
byte[] digitalSignature = signature.sign();
|
|
||||||
|
|
||||||
// 8. 对签名结果进行Base64编码
|
|
||||||
return Base64.getEncoder().encodeToString(digitalSignature);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("RSA-SHA256签名失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 完整的签名生成方法
|
|
||||||
* @param params 参数Map
|
|
||||||
* @param privateKeyStr 私钥字符串
|
|
||||||
* @return 签名结果
|
|
||||||
*/
|
|
||||||
public static String generateSignature(Map<String, String> params, String privateKeyStr) {
|
|
||||||
// 1. 构造签名串
|
|
||||||
String signString = buildSignString(params);
|
|
||||||
log.info("待签名串: {}", signString);
|
|
||||||
|
|
||||||
// 2. 使用私钥进行RSA-SHA256签名
|
|
||||||
String signature = signWithRsaSha256(signString, privateKeyStr);
|
|
||||||
log.info("生成签名: {}", signature);
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
package com.cool.store.utils;
|
||||||
|
|
||||||
|
import com.sun.deploy.net.URLEncoder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
|
||||||
|
import sun.security.util.DerInputStream;
|
||||||
|
import sun.security.util.DerValue;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.Signature;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.*;
|
||||||
|
/**
|
||||||
|
* RSA签名工具类
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/12 22:57
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RsaSignUtil {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加签方法
|
||||||
|
*/
|
||||||
|
public static String generateSign(Map<String, Object> params, String privateKeyPEM) {
|
||||||
|
// 移除可能存在的sign字段
|
||||||
|
params.remove("sign");
|
||||||
|
String afterSort = objectToSortedString(params);
|
||||||
|
log.info("排序后的参数:{}", afterSort);
|
||||||
|
String formattedPrivateKey = KeyFormatUtil.convertToPEMFormat(privateKeyPEM, "RSA_PRIVATE");
|
||||||
|
return rsaPrivateKeySign(afterSort, privateKeyPEM, "SHA256withRSA");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验签方法
|
||||||
|
*/
|
||||||
|
public static boolean verifySign(Map<String, Object> params, String publicKeyPEM) {
|
||||||
|
String sign = String.valueOf(params.get("sign"));
|
||||||
|
params.remove("sign");
|
||||||
|
String afterSort = objectToSortedString(params);
|
||||||
|
return rsaPublicKeyVerify(afterSort, sign, publicKeyPEM, "SHA256withRSA");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询签名验证 - 主入口方法
|
||||||
|
*/
|
||||||
|
public static boolean querySignCrm(String publicKey, Map<String, Object> params) {
|
||||||
|
return verifySign(params, publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为排序后的字符串
|
||||||
|
*/
|
||||||
|
public static String objectToSortedString(Map<String, Object> obj) {
|
||||||
|
return convertToSortedString(obj, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归将参数转换为排序字符串
|
||||||
|
*/
|
||||||
|
private static String convertToSortedString(Map<String, Object> params, String prefix) {
|
||||||
|
// 按键排序
|
||||||
|
List<String> keys = new ArrayList<>(params.keySet());
|
||||||
|
Collections.sort(keys);
|
||||||
|
|
||||||
|
List<String> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = params.get(key);
|
||||||
|
if (value == null || "".equals(value) ||
|
||||||
|
(value instanceof Number && ((Number) value).doubleValue() == 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentKey = key;
|
||||||
|
if (!prefix.isEmpty()) {
|
||||||
|
currentKey = prefix + "[" + key + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof Map) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> nestedMap = (Map<String, Object>) value;
|
||||||
|
String nestedString = convertToSortedString(nestedMap, currentKey);
|
||||||
|
if (!nestedString.isEmpty()) {
|
||||||
|
parts.add(nestedString);
|
||||||
|
}
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
List<?> list = (List<?>) value;
|
||||||
|
List<String> elemStrs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Object element : list) {
|
||||||
|
String elementStr;
|
||||||
|
if (element instanceof Map) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> elementMap = (Map<String, Object>) element;
|
||||||
|
String inner = convertToSortedString(elementMap, "");
|
||||||
|
elementStr = "{" + inner + "}";
|
||||||
|
} else if (element instanceof Double) {
|
||||||
|
elementStr = String.format("%.0f", (Double) element);
|
||||||
|
} else if (element instanceof Float) {
|
||||||
|
elementStr = String.format("%.0f", (Float) element);
|
||||||
|
} else {
|
||||||
|
elementStr = String.valueOf(element);
|
||||||
|
}
|
||||||
|
elemStrs.add(elementStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对元素字符串排序
|
||||||
|
Collections.sort(elemStrs);
|
||||||
|
|
||||||
|
// URL编码并添加到parts
|
||||||
|
for (String es : elemStrs) {
|
||||||
|
String encodedValue = urlEncode(es);
|
||||||
|
parts.add(currentKey + "[]=" + encodedValue);
|
||||||
|
}
|
||||||
|
} else if (value instanceof Double) {
|
||||||
|
String strValue = String.format("%.0f", (Double) value);
|
||||||
|
parts.add(currentKey + "=" + urlEncode(strValue));
|
||||||
|
} else if (value instanceof Float) {
|
||||||
|
String strValue = String.format("%.0f", (Float) value);
|
||||||
|
parts.add(currentKey + "=" + urlEncode(strValue));
|
||||||
|
} else {
|
||||||
|
String strValue = String.valueOf(value);
|
||||||
|
parts.add(currentKey + "=" + urlEncode(strValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.join("&", parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL编码(替换+为%20)
|
||||||
|
*/
|
||||||
|
private static String urlEncode(String value) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(value, StandardCharsets.UTF_8.name())
|
||||||
|
.replace("+", "%20");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSA私钥加签
|
||||||
|
*/
|
||||||
|
public static String rsaPrivateKeySign(String text, String privateKeyPEM, String algorithm) {
|
||||||
|
try {
|
||||||
|
// 1. 解析私钥
|
||||||
|
log.debug("Received private key PEM: {}", privateKeyPEM);
|
||||||
|
PrivateKey privateKey = parsePrivateKey(privateKeyPEM);
|
||||||
|
if (privateKey == null) {
|
||||||
|
throw new RuntimeException("解析私钥失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 创建签名实例
|
||||||
|
Signature signature = Signature.getInstance(algorithm);
|
||||||
|
signature.initSign(privateKey);
|
||||||
|
signature.update(text.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
// 3. 生成签名并Base64编码
|
||||||
|
byte[] digitalSignature = signature.sign();
|
||||||
|
return Base64.getEncoder().encodeToString(digitalSignature);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("加签失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSA公钥验签
|
||||||
|
*/
|
||||||
|
public static boolean rsaPublicKeyVerify(String text, String signBase64,
|
||||||
|
String publicKeyPEM, String algorithm) {
|
||||||
|
try {
|
||||||
|
// 1. 解码Base64签名
|
||||||
|
byte[] signature = Base64.getDecoder().decode(signBase64);
|
||||||
|
|
||||||
|
// 2. 解析公钥
|
||||||
|
PublicKey publicKey = parsePublicKey(publicKeyPEM);
|
||||||
|
if (publicKey == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 验证签名
|
||||||
|
Signature sig = Signature.getInstance(algorithm);
|
||||||
|
sig.initVerify(publicKey);
|
||||||
|
sig.update(text.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
return sig.verify(signature);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析PEM格式私钥(兼容PKCS#1和PKCS#8格式)
|
||||||
|
*/
|
||||||
|
private static PrivateKey parsePrivateKey(String privateKeyPEM) {
|
||||||
|
try {
|
||||||
|
String pemContent = privateKeyPEM
|
||||||
|
.replace("-----BEGIN PRIVATE KEY-----", "")
|
||||||
|
.replace("-----END PRIVATE KEY-----", "")
|
||||||
|
.replace("-----BEGIN RSA PRIVATE KEY-----", "")
|
||||||
|
.replace("-----END RSA PRIVATE KEY-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
|
||||||
|
byte[] keyBytes = Base64.getDecoder().decode(pemContent);
|
||||||
|
|
||||||
|
// 尝试PKCS#8格式
|
||||||
|
try {
|
||||||
|
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
return keyFactory.generatePrivate(keySpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 使用Bouncy Castle处理PKCS#1
|
||||||
|
RSAPrivateKey rsaPrivKey = RSAPrivateKey.getInstance(keyBytes);
|
||||||
|
return KeyFactory.getInstance("RSA").generatePrivate(
|
||||||
|
new RSAPrivateKeySpec(rsaPrivKey.getModulus(), rsaPrivKey.getPrivateExponent()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("解析私钥失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析PKCS#1格式私钥
|
||||||
|
*/
|
||||||
|
private static PrivateKey parsePKCS1PrivateKey(byte[] keyBytes) {
|
||||||
|
try {
|
||||||
|
int length = keyBytes.length;
|
||||||
|
byte[] pkcs8Header = new byte[] {
|
||||||
|
0x30, (byte) 0x82,
|
||||||
|
(byte) ((length + 26) >> 8), (byte) (length + 26), // 总长度
|
||||||
|
0x02, 0x01, 0x00,
|
||||||
|
0x30, 0x0D, 0x06, 0x09, 0x2A, (byte) 0x86, 0x48, (byte) 0x86, (byte) 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00,
|
||||||
|
0x04, (byte) 0x82,
|
||||||
|
(byte) (length >> 8), (byte) length // BIT STRING 长度
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] pkcs8Key = new byte[pkcs8Header.length + keyBytes.length];
|
||||||
|
System.arraycopy(pkcs8Header, 0, pkcs8Key, 0, pkcs8Header.length);
|
||||||
|
System.arraycopy(keyBytes, 0, pkcs8Key, pkcs8Header.length, keyBytes.length);
|
||||||
|
|
||||||
|
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Key);
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
return keyFactory.generatePrivate(keySpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("解析PKCS#1私钥失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析PEM格式公钥(兼容PKCS#1和PKCS#8格式)
|
||||||
|
*/
|
||||||
|
private static PublicKey parsePublicKey(String publicKeyPEM) {
|
||||||
|
try {
|
||||||
|
// 移除PEM头尾标记和空白字符
|
||||||
|
String pemContent = publicKeyPEM
|
||||||
|
.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||||
|
.replace("-----END PUBLIC KEY-----", "")
|
||||||
|
.replace("-----BEGIN RSA PUBLIC KEY-----", "")
|
||||||
|
.replace("-----END RSA PUBLIC KEY-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
|
||||||
|
byte[] keyBytes = Base64.getDecoder().decode(pemContent);
|
||||||
|
|
||||||
|
// 先尝试PKCS#8格式
|
||||||
|
try {
|
||||||
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
return keyFactory.generatePublic(keySpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果PKCS#8失败,尝试PKCS#1格式
|
||||||
|
return parsePKCS1PublicKey(keyBytes);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析PKCS#1格式公钥
|
||||||
|
*/
|
||||||
|
private static PublicKey parsePKCS1PublicKey(byte[] keyBytes) {
|
||||||
|
try {
|
||||||
|
// PKCS#1 RSA公钥转换为PKCS#8格式
|
||||||
|
byte[] pkcs8Prefix = new byte[] {
|
||||||
|
0x30, (byte) 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, (byte) 0x86,
|
||||||
|
0x48, (byte) 0x86, (byte) 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
|
||||||
|
(byte) 0x82, 0x01, 0x0f, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] pkcs8Key = new byte[pkcs8Prefix.length + keyBytes.length];
|
||||||
|
System.arraycopy(pkcs8Prefix, 0, pkcs8Key, 0, pkcs8Prefix.length);
|
||||||
|
System.arraycopy(keyBytes, 0, pkcs8Key, pkcs8Prefix.length, keyBytes.length);
|
||||||
|
|
||||||
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pkcs8Key);
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
return keyFactory.generatePublic(keySpec);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
package com.cool.store.utils;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*RSA-SHA256 验签工具类
|
|
||||||
* @Author suzhuhong
|
|
||||||
* @Date 2025/11/12 15:15
|
|
||||||
* @Version 1.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class VerifySignatureUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证签名
|
|
||||||
* @param params 参数Map(包含sign字段)
|
|
||||||
* @param publicKeyStr Base64编码的公钥
|
|
||||||
* @return 验签结果
|
|
||||||
*/
|
|
||||||
public static boolean verifySignature(Map<String, String> params, String publicKeyStr) {
|
|
||||||
try {
|
|
||||||
// 1. 从参数中提取签名(并移除,不参与签名串构造)
|
|
||||||
String receivedSignature = params.get("sign");
|
|
||||||
if (receivedSignature == null || receivedSignature.trim().isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("签名参数sign不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 创建参数的副本,移除sign字段
|
|
||||||
Map<String, String> paramsForSign = new HashMap<>(params);
|
|
||||||
paramsForSign.remove("sign");
|
|
||||||
|
|
||||||
// 3. 构造签名串(与签名方相同的规则)
|
|
||||||
String signString = buildSignString(paramsForSign);
|
|
||||||
log.info("验签待签名串: {}", signString);
|
|
||||||
|
|
||||||
// 4. 验证签名
|
|
||||||
return verifyRsaSha256(signString, receivedSignature, publicKeyStr);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("验签过程异常: ", e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造签名串(与签名方相同的逻辑)
|
|
||||||
*/
|
|
||||||
private static String buildSignString(Map<String, String> params) {
|
|
||||||
return params.entrySet().stream()
|
|
||||||
.filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty())
|
|
||||||
.sorted(Map.Entry.comparingByKey())
|
|
||||||
.map(entry -> {
|
|
||||||
try {
|
|
||||||
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
|
|
||||||
return entry.getKey() + "=" + encodedValue;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("URL编码失败", e);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(Collectors.joining("&"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RSA-SHA256 验签
|
|
||||||
*/
|
|
||||||
private static boolean verifyRsaSha256(String data, String signature, String publicKeyStr) {
|
|
||||||
try {
|
|
||||||
// 1. 解码Base64公钥
|
|
||||||
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
|
|
||||||
|
|
||||||
// 2. 创建X509编码密钥规范
|
|
||||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
|
|
||||||
|
|
||||||
// 3. 获取RSA KeyFactory
|
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
|
||||||
|
|
||||||
// 4. 生成公钥对象
|
|
||||||
PublicKey publicKey = keyFactory.generatePublic(keySpec);
|
|
||||||
|
|
||||||
// 5. 创建Signature实例
|
|
||||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
|
||||||
sig.initVerify(publicKey);
|
|
||||||
|
|
||||||
// 6. 更新要验证的数据
|
|
||||||
sig.update(data.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
// 7. 解码收到的签名
|
|
||||||
byte[] signatureBytes = Base64.getDecoder().decode(signature);
|
|
||||||
|
|
||||||
// 8. 执行验证
|
|
||||||
return sig.verify(signatureBytes);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("RSA-SHA256验签失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:06
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AccountAuthenticationDTO {
|
||||||
|
|
||||||
|
private Integer accountStatus;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门店签约人账户
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:54
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AccountInfoDTO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "结算卡业务类型 枚举值:1:对公 2:对私", required = true)
|
||||||
|
private String accountType;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "营业执照号码")
|
||||||
|
private String licenseNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工商注册名称")
|
||||||
|
private String licenseName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人姓名")
|
||||||
|
private String legalName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人证件号码")
|
||||||
|
private String legalNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人联系电话")
|
||||||
|
private String legalPhone;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店编号", required = true)
|
||||||
|
private String storeSn;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账户编号", required = true)
|
||||||
|
private String accountNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账户名称", required = true)
|
||||||
|
private String accountName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账户别名", required = true)
|
||||||
|
private String accountAliasName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "结算银行卡号", required = true)
|
||||||
|
private String accountCardNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "结算卡银行预留手机号", required = true)
|
||||||
|
private String accountPhone;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "开户支行名称", required = true)
|
||||||
|
private String bankName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "支行编号", required = true)
|
||||||
|
private String bankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账户状态 1:待提交 2:待鉴权 3:鉴权中 4:开通", required = true)
|
||||||
|
private Integer accountStatus;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账户余额", required = true)
|
||||||
|
private String totalAmount;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:58
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AccountNoDTO {
|
||||||
|
|
||||||
|
private String accountNo;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:09
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AccountVerifyDTO {
|
||||||
|
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
private Integer accountStatus;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:59
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AddTagDTO {
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
private Integer addTagType;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 10:54
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BankDTO {
|
||||||
|
|
||||||
|
@ApiModelProperty("银行编号")
|
||||||
|
private String headCode;
|
||||||
|
@ApiModelProperty("银行名称")
|
||||||
|
private String headName;
|
||||||
|
@ApiModelProperty("支行号")
|
||||||
|
private String branchCode;
|
||||||
|
@ApiModelProperty("支行名称")
|
||||||
|
private String branchName;
|
||||||
|
@ApiModelProperty("支行地址")
|
||||||
|
private String branchAddress;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import com.cool.store.request.wallet.WalletBasicPageInfo;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:36
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BankListDTO {
|
||||||
|
|
||||||
|
WalletBasicPageInfo page;
|
||||||
|
|
||||||
|
List<BankDTO> pageData;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 17:15
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LargePaymentDTO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "外部门店唯一标识", required = true)
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "请求预支付Id", required = true)
|
||||||
|
private String paymentId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收款码唯一流水号", required = true)
|
||||||
|
private String transOrderTrace;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款人账户编号", required = true)
|
||||||
|
private String payerAcctNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款人户名", required = true)
|
||||||
|
private String payerAcctName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款银行名称")
|
||||||
|
private String payerBankName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款银行行号")
|
||||||
|
private String payerBankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "充值金额", required = true)
|
||||||
|
private String amt;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收款账号", required = true)
|
||||||
|
private String payeeAccNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收款账户名称", required = true)
|
||||||
|
private String payeeAccName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收款银行名称", required = true)
|
||||||
|
private String payeeBankName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "收款银行行号", required = true)
|
||||||
|
private String payeeBankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "账号过期时间")
|
||||||
|
private String expireTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 18:23
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PaymentDTO {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "外部门店唯一标识", required = true)
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "请求预支付Id", required = true)
|
||||||
|
private String paymentId;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "收款码唯一流水号", required = true)
|
||||||
|
private String transOrderTrace;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "金额", required = true)
|
||||||
|
private String totalFee;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "状态:1-成功 2-失败 3-支付中 4-撤销", required = true)
|
||||||
|
private Integer orderStatus;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "利楚订单号(商户订单号)")
|
||||||
|
private String outTradeNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "通道订单号(银行订单号)")
|
||||||
|
private String channelOrderNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "付款人账号")
|
||||||
|
private String payerAccNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "付款人户名")
|
||||||
|
private String payerAccName;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "付款人银行名称")
|
||||||
|
private String payerBankName;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "付款银行行号")
|
||||||
|
private String payerBankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "收款账号", required = true)
|
||||||
|
private String payeeAccNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "收款账户名称", required = true)
|
||||||
|
private String payeeAccName;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "收款银行名称", required = true)
|
||||||
|
private String payeeBankName;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "收款银行行号", required = true)
|
||||||
|
private String payeeBankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "账号过期时间")
|
||||||
|
private String expireTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "创建时间")
|
||||||
|
private String createTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "付款明细")
|
||||||
|
private List<PaymentDetailDTO> payList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 17:38
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PaymentDetailDTO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "打款金额", required = true)
|
||||||
|
private String tranAmt;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款人账号", required = true)
|
||||||
|
private String payerAccountName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款时间", required = true)
|
||||||
|
private String paySuccessTime;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款银行账号", required = true)
|
||||||
|
private String payerAccountBankNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "银行受理时间", required = true)
|
||||||
|
private String tranSeqNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "付款账号", required = true)
|
||||||
|
private String payerAccountNo;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.cool.store.dto.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:54
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StoreAccountDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 营帐通的账户ID
|
||||||
|
*/
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:09
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "营业执照信息请求参数")
|
||||||
|
public class AccountAddTagRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "外部门店唯一标识", required = true)
|
||||||
|
@NotBlank(message = "外部门店唯一标识不能为空")
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "营业执照号码", required = true)
|
||||||
|
@NotBlank(message = "营业执照号码不能为空")
|
||||||
|
private String licenseNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "工商注册名称", required = true)
|
||||||
|
@NotBlank(message = "工商注册名称不能为空")
|
||||||
|
private String licenseName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "营业执照到期日(格式YYYY-MM-DD),如果证件到期日期为“长期”,则传:“2999-12-31”)")
|
||||||
|
private String licenseExpire;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人姓名", required = true)
|
||||||
|
@NotBlank(message = "法人姓名不能为空")
|
||||||
|
private String legalName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人证件号码", required = true)
|
||||||
|
@NotBlank(message = "法人证件号码不能为空")
|
||||||
|
private String legalNo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "证件发证日期 yyyy-MM-dd")
|
||||||
|
private String idCardStartDate;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "证件到期日期 yyyy-MM-dd,如果证件到期日期为“长期”,则传:“2999-12-31”")
|
||||||
|
private String idCardEndDate;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "法人联系电话", required = true)
|
||||||
|
@NotBlank(message = "法人联系电话不能为空")
|
||||||
|
private String legalPhone;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:08
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AccountVerifyRequest {
|
||||||
|
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
private String verifyNo;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 13:49
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CreateStoreAndAccountRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "CRM门店编号", required = true)
|
||||||
|
private String outStoreId;
|
||||||
|
@ApiModelProperty(name = "组织编号", required = true)
|
||||||
|
private String orgCode;
|
||||||
|
@ApiModelProperty(name = "组织名称", required = true)
|
||||||
|
private String orgName;
|
||||||
|
@ApiModelProperty(name = "联系电话", required = true)
|
||||||
|
private String phoneNumber;
|
||||||
|
@ApiModelProperty(name = "结算卡业务类型 枚举值:1:对公 2:对私", required = true)
|
||||||
|
private Integer accountType;
|
||||||
|
@ApiModelProperty(name = "开户类型:1企业 2个体工商户,3个人(小微商户) ", required = true)
|
||||||
|
private Integer businessType;
|
||||||
|
@ApiModelProperty(name = "法人姓名", required = true)
|
||||||
|
private String legalName;
|
||||||
|
@ApiModelProperty(name = "法人证件号码", required = true)
|
||||||
|
private String legalNo;
|
||||||
|
@ApiModelProperty(name = "账户简称", required = true)
|
||||||
|
private String accountAliasName;
|
||||||
|
@ApiModelProperty(name = "结算银行卡号", required = true)
|
||||||
|
private String accountCardno;
|
||||||
|
@ApiModelProperty(name = "结算卡银行预留手机号", required = true)
|
||||||
|
private String accountPhone;
|
||||||
|
@ApiModelProperty(name = "支行编号", required = true)
|
||||||
|
private String bankNo;
|
||||||
|
@ApiModelProperty(name = "开户支行名称", required = true)
|
||||||
|
private String bankName;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import com.sun.istack.NotNull;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 14:07
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CreateStoreRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "CRM门店编号", required = true)
|
||||||
|
@NotBlank(message = "CRM门店编号不能为空")
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店编号", required = true)
|
||||||
|
@NotBlank(message = "门店编号不能为空")
|
||||||
|
private String storeSn;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店名称", required = true)
|
||||||
|
@NotBlank(message = "门店名称不能为空")
|
||||||
|
private String storeName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店内部名称")
|
||||||
|
private String inStoreName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "组织编号", required = true)
|
||||||
|
@NotBlank(message = "组织编号不能为空")
|
||||||
|
private String orgCode;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "组织名称", required = true)
|
||||||
|
@NotBlank(message = "组织名称不能为空")
|
||||||
|
private String orgName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "联系电话", required = true)
|
||||||
|
@NotBlank(message = "联系电话不能为空")
|
||||||
|
private String phoneNumber;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店模式: 1.社会加盟 2.强管 3.强加盟", required = true)
|
||||||
|
private Integer storeMode;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "省-标准行政区域编码", required = true)
|
||||||
|
private Integer province;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "市-标准行政区域编码", required = true)
|
||||||
|
private Integer city;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "区县-标准行政区域编码", required = true)
|
||||||
|
private Integer district;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "门店地址", required = true)
|
||||||
|
@NotBlank(message = "门店地址不能为空")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 10:55
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GetBankRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty("银行名称")
|
||||||
|
private String headName;
|
||||||
|
@ApiModelProperty("关键字查询")
|
||||||
|
private String keyword;
|
||||||
|
@ApiModelProperty("分页查询参数")
|
||||||
|
private WalletBasicPageInfo page;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 18:28
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LargePaymentDetailRequest {
|
||||||
|
|
||||||
|
private String transOrderTrace;
|
||||||
|
|
||||||
|
private String paymentId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 17:00
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LargePaymentRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "商户门店编号",required = true)
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "请求预支付Id",required = true)
|
||||||
|
private String paymentId;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "签约人名称",required = true)
|
||||||
|
private String payerAccName;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "支付金额",required = true)
|
||||||
|
private String amt;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:05
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OutStoreIdRequest {
|
||||||
|
|
||||||
|
private String outStoreId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 17:37
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PaymentDetailRequest {
|
||||||
|
|
||||||
|
private String paymentId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 16:46
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UpdateStoreAccountRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "商户门店编号",required = true)
|
||||||
|
private String outStoreId;
|
||||||
|
@ApiModelProperty(name = "法人/自然人证件号码",required = true)
|
||||||
|
private String idnum;
|
||||||
|
@ApiModelProperty(name = "签约人姓名(对私结算卡必传)以上二选一",required = true)
|
||||||
|
private String accountName;
|
||||||
|
@ApiModelProperty(name = "结算银行卡号",required = true)
|
||||||
|
private String accountCardno;
|
||||||
|
@ApiModelProperty(name = "结算卡银行预留手机号。",required = true)
|
||||||
|
private String accountPhone;
|
||||||
|
@ApiModelProperty(name = "支行编号",required = true)
|
||||||
|
private String bankNo;
|
||||||
|
@ApiModelProperty(name = "开户支行名称",required = true)
|
||||||
|
private String bankName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.cool.store.request.wallet;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import io.swagger.models.auth.In;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 10:56
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class WalletBasicPageInfo {
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "当前页码",required = true)
|
||||||
|
private Integer currentPage;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "每页数量",required = true)
|
||||||
|
private Integer pageSize;
|
||||||
|
|
||||||
|
private Integer total;
|
||||||
|
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
private Boolean first;
|
||||||
|
|
||||||
|
private Boolean last;
|
||||||
|
|
||||||
|
public WalletBasicPageInfo(Integer currentPage, Integer pageSize){
|
||||||
|
this.currentPage = currentPage;
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
package com.cool.store.http;
|
||||||
|
|
||||||
|
import com.cool.store.enums.ErrorCodeEnum;
|
||||||
|
import com.cool.store.exception.ServiceException;
|
||||||
|
import com.cool.store.utils.RsaSignUtil;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.apache.poi.ss.formula.functions.T;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 10:00
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class WalletHttpClientRest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OkHttpClient okHttpClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Value("${cool.api.rsa.private.key}")
|
||||||
|
private String coolPrivateKey;
|
||||||
|
@Value("${wallet.api.rsa.public.key}")
|
||||||
|
private String walletPublicKey;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送带签名的POST请求
|
||||||
|
*/
|
||||||
|
public <T> T postWithSign(String url, Object request, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
// 1. 准备请求参数
|
||||||
|
Map<String, Object> requestParams = convertToMap(request);
|
||||||
|
requestParams.put("timestamp", System.currentTimeMillis());
|
||||||
|
requestParams.put("key", "360155690205317");
|
||||||
|
// 2. 生成签名
|
||||||
|
String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
|
||||||
|
requestParams.put("sign", signature);
|
||||||
|
|
||||||
|
// 3. 发送请求
|
||||||
|
String responseJson = executePost(url, requestParams);
|
||||||
|
|
||||||
|
// 4. 解析响应
|
||||||
|
return parseResponse(responseJson, responseType);
|
||||||
|
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 其他异常统一包装为RuntimeException
|
||||||
|
log.error("发送带签名POST请求失败: {}", url, e);
|
||||||
|
throw new RuntimeException("接口调用异常: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送带签名和验签的POST请求
|
||||||
|
*/
|
||||||
|
public <T> T postWithSignAndVerify(String url, Object request, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
// 1. 准备请求参数
|
||||||
|
Map<String, Object> requestParams = convertToMap(request);
|
||||||
|
requestParams.put("timestamp", System.currentTimeMillis());
|
||||||
|
|
||||||
|
// 2. 生成签名
|
||||||
|
String signature = RsaSignUtil.generateSign(requestParams,coolPrivateKey);
|
||||||
|
requestParams.put("sign", signature);
|
||||||
|
|
||||||
|
// 3. 发送请求
|
||||||
|
String responseJson = executePost(url, requestParams);
|
||||||
|
|
||||||
|
// 4. 解析响应并验证签名
|
||||||
|
return parseAndVerifyResponse(responseJson, responseType);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送带签名和验签POST请求失败: {}", url, e);
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送普通POST请求(无签名)
|
||||||
|
*/
|
||||||
|
public <T> T post(String url, Object request, Class<T> responseType) {
|
||||||
|
try {
|
||||||
|
String responseJson = executePost(url, request);
|
||||||
|
return parseResponse(responseJson, responseType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送POST请求失败: {}", url, e);
|
||||||
|
throw new RuntimeException("调用外部接口失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行POST请求
|
||||||
|
*/
|
||||||
|
private String executePost(String url, Object body) throws IOException {
|
||||||
|
String jsonBody = objectMapper.writeValueAsString(body);
|
||||||
|
RequestBody requestBody = RequestBody.create( MediaType.parse("application/json; charset=utf-8"),jsonBody);
|
||||||
|
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.post(requestBody)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
log.info("发送POST请求: {}, 数据: {}", url, jsonBody);
|
||||||
|
|
||||||
|
try (Response response = okHttpClient.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,response.code() + " " + response.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String responseBody = response.body().string();
|
||||||
|
log.info("收到响应: {}", responseBody);
|
||||||
|
|
||||||
|
checkBusinessResponseCode(responseBody);
|
||||||
|
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkBusinessResponseCode(String responseJson) throws IOException {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||||
|
new TypeReference<Map<String, Object>>() {
|
||||||
|
});
|
||||||
|
|
||||||
|
Object codeObj = responseMap.get("code");
|
||||||
|
if (codeObj != null) {
|
||||||
|
int code = 0;
|
||||||
|
if (codeObj instanceof Number) {
|
||||||
|
code = ((Number) codeObj).intValue();
|
||||||
|
} else {
|
||||||
|
code = Integer.parseInt(codeObj.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code != 200) {
|
||||||
|
String msg = (String) responseMap.get("msg");
|
||||||
|
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
|
||||||
|
"code: " + code + ", msg: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果解析失败,说明可能不是标准格式,继续处理
|
||||||
|
log.debug("无法解析响应码格式: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析响应
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T parseResponse(String responseJson, Class<T> responseType) throws Exception {
|
||||||
|
if (responseType == String.class) {
|
||||||
|
return (T) responseJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析为通用响应格式
|
||||||
|
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||||
|
new TypeReference<Map<String, Object>>() {});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 如果返回类型是Map,直接返回
|
||||||
|
if (responseType == Map.class) {
|
||||||
|
return (T) responseMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取data字段
|
||||||
|
Object data = responseMap.get("data");
|
||||||
|
if (data != null && responseType != Object.class) {
|
||||||
|
return objectMapper.convertValue(data, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectMapper.convertValue(responseMap, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析响应并验证签名
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T parseAndVerifyResponse(String responseJson, Class<T> responseType) throws Exception {
|
||||||
|
// 解析为Map来验证签名
|
||||||
|
Map<String, Object> responseMap = objectMapper.readValue(responseJson,
|
||||||
|
new TypeReference<Map<String, Object>>() {});
|
||||||
|
|
||||||
|
// 验证响应签名
|
||||||
|
String responseSign = (String) responseMap.get("sign");
|
||||||
|
if (responseSign != null) {
|
||||||
|
// 移除sign字段后进行验签
|
||||||
|
Map<String, Object> verifyParams = new HashMap<>(responseMap);
|
||||||
|
|
||||||
|
boolean isValid = RsaSignUtil.verifySign(verifyParams, walletPublicKey);
|
||||||
|
if (!isValid) {
|
||||||
|
throw new SecurityException("响应签名验证失败");
|
||||||
|
}
|
||||||
|
log.debug("响应签名验证成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回指定类型的数据
|
||||||
|
return parseResponse(responseJson, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为Map
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<String, Object> convertToMap(Object obj) {
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
return (Map<String, Object>) obj;
|
||||||
|
}
|
||||||
|
return objectMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.cool.store.service.wallet;
|
||||||
|
|
||||||
|
import com.cool.store.dto.wallet.*;
|
||||||
|
import com.cool.store.http.WalletHttpClientRest;
|
||||||
|
import com.cool.store.request.wallet.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/11/13 10:51
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class WalletApiService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
WalletHttpClientRest walletHttpClientRest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在平安扫呗系统中,创建签约人账户
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public StoreAccountDTO createStoreAndAccount(CreateStoreAndAccountRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/createStoreAndAccount", request, StoreAccountDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开通失败 开通
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public StoreAccountDTO updateStoreAccount(UpdateStoreAccountRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/updateStoreAccount", request, StoreAccountDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建门店接口
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AccountNoDTO createStore(CreateStoreRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/v1/createStoreAndAccount", request, AccountNoDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行发送短信接口
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AccountAuthenticationDTO authentication(OutStoreIdRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/authentication", request, AccountAuthenticationDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门店开通平安银行接口
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AccountVerifyDTO openAccount(AccountVerifyRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/openAccount", request, AccountVerifyDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签约人账户打标升级
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AddTagDTO addTag(AccountAddTagRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/addTag", request, AddTagDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取账户信息
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public AccountInfoDTO getAccountInfo(OutStoreIdRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/account/v1/getAccountInfo", request, AccountInfoDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 大额预支付接口
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public LargePaymentDTO largePayment(LargePaymentRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/payment/v1/largePayment", request, LargePaymentDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 大额预支付查询接口
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public PaymentDTO largePaymentQuery(PaymentDetailRequest request){
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/trans/v1/largePaymentQuery", request, PaymentDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取支行信息
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public BankListDTO getBankList(GetBankRequest request) {
|
||||||
|
return walletHttpClientRest.postWithSign("https://api.dev.wenmatech.com:443/open/crm/base/v1/findPageBank", request, BankListDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,15 +2,13 @@ package com.cool.store.controller.webb;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.cool.store.constants.CommonConstants;
|
import com.cool.store.constants.CommonConstants;
|
||||||
import com.cool.store.constants.RedisConstant;
|
|
||||||
import com.cool.store.dao.*;
|
import com.cool.store.dao.*;
|
||||||
import com.cool.store.dto.FoodTokenDTO;
|
import com.cool.store.dto.FoodTokenDTO;
|
||||||
import com.cool.store.dto.GetAccessTokenDTO;
|
import com.cool.store.dto.GetAccessTokenDTO;
|
||||||
import com.cool.store.dto.HqtTokenDTO;
|
import com.cool.store.dto.HqtTokenDTO;
|
||||||
import com.cool.store.dto.ModifyPasswordDTO;
|
import com.cool.store.dto.ModifyPasswordDTO;
|
||||||
import com.cool.store.dto.huoma.*;
|
import com.cool.store.dto.huoma.*;
|
||||||
import com.cool.store.dto.wechat.CallbackMessageDTO;
|
import com.cool.store.dto.wallet.*;
|
||||||
import com.cool.store.dto.wechat.WechatTemplateMessageDTO;
|
|
||||||
import com.cool.store.entity.*;
|
import com.cool.store.entity.*;
|
||||||
import com.cool.store.enums.DownSystemTypeEnum;
|
import com.cool.store.enums.DownSystemTypeEnum;
|
||||||
import com.cool.store.enums.MessageEnum;
|
import com.cool.store.enums.MessageEnum;
|
||||||
@@ -20,13 +18,13 @@ import com.cool.store.enums.wechat.WechatTemplateEnum;
|
|||||||
import com.cool.store.handler.WeChatHandler;
|
import com.cool.store.handler.WeChatHandler;
|
||||||
import com.cool.store.job.XxlJobHandler;
|
import com.cool.store.job.XxlJobHandler;
|
||||||
import com.cool.store.mapper.FranchiseFeeMapper;
|
import com.cool.store.mapper.FranchiseFeeMapper;
|
||||||
import com.cool.store.mapper.LineInfoMapper;
|
|
||||||
import com.cool.store.mapper.ShopInfoMapper;
|
import com.cool.store.mapper.ShopInfoMapper;
|
||||||
import com.cool.store.mq.util.HttpRestTemplateService;
|
import com.cool.store.mq.util.HttpRestTemplateService;
|
||||||
import com.cool.store.request.*;
|
import com.cool.store.request.*;
|
||||||
import com.cool.store.request.bigdata.ProfitDataRequest;
|
import com.cool.store.request.bigdata.ProfitDataRequest;
|
||||||
import com.cool.store.request.huoma.ShopBasicInfoRequest;
|
import com.cool.store.request.huoma.ShopBasicInfoRequest;
|
||||||
import com.cool.store.request.oppty.*;
|
import com.cool.store.request.oppty.*;
|
||||||
|
import com.cool.store.request.wallet.*;
|
||||||
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
|
import com.cool.store.request.xgj.PushFranchiseFeeRequest;
|
||||||
import com.cool.store.response.ResponseResult;
|
import com.cool.store.response.ResponseResult;
|
||||||
import com.cool.store.response.bigdata.ActDataResponse;
|
import com.cool.store.response.bigdata.ActDataResponse;
|
||||||
@@ -39,16 +37,12 @@ import com.cool.store.response.oppty.OpportunityDetailResponse;
|
|||||||
import com.cool.store.response.oppty.OpportunityInfoPageResponse;
|
import com.cool.store.response.oppty.OpportunityInfoPageResponse;
|
||||||
import com.cool.store.service.*;
|
import com.cool.store.service.*;
|
||||||
import com.cool.store.service.impl.CommonService;
|
import com.cool.store.service.impl.CommonService;
|
||||||
import com.cool.store.service.impl.OrderSysInfoServiceImpl;
|
|
||||||
import com.cool.store.service.impl.UserAuthMappingServiceImpl;
|
import com.cool.store.service.impl.UserAuthMappingServiceImpl;
|
||||||
|
import com.cool.store.service.wallet.WalletApiService;
|
||||||
import com.cool.store.service.wechat.WechatTemplateService;
|
import com.cool.store.service.wechat.WechatTemplateService;
|
||||||
import com.cool.store.service.xinfa.XinFaBusinessService;
|
import com.cool.store.service.xinfa.XinFaBusinessService;
|
||||||
import com.cool.store.service.xinfa.XinFaDeviceService;
|
import com.cool.store.utils.RsaSignUtil;
|
||||||
import com.cool.store.utils.CoolDateUtils;
|
|
||||||
import com.cool.store.utils.RedisConstantUtil;
|
|
||||||
import com.cool.store.utils.RedisUtilPool;
|
|
||||||
import com.cool.store.utils.poi.StringUtils;
|
import com.cool.store.utils.poi.StringUtils;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -58,7 +52,6 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@@ -638,4 +631,159 @@ public class PCTestController {
|
|||||||
return ResponseResult.success(publishStatus);
|
return ResponseResult.success(publishStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 测试数据
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("name", "张三");
|
||||||
|
params.put("age", 25);
|
||||||
|
params.put("amount", 100.50);
|
||||||
|
params.put("timestamp", System.currentTimeMillis());
|
||||||
|
|
||||||
|
List<Map<String, Object>> items = new ArrayList<>();
|
||||||
|
Map<String, Object> item1 = new HashMap<>();
|
||||||
|
item1.put("id", 1);
|
||||||
|
item1.put("name", "商品A");
|
||||||
|
item1.put("price", 29.99);
|
||||||
|
items.add(item1);
|
||||||
|
|
||||||
|
Map<String, Object> item2 = new HashMap<>();
|
||||||
|
item2.put("id", 2);
|
||||||
|
item2.put("name", "商品B");
|
||||||
|
item2.put("price", 39.99);
|
||||||
|
items.add(item2);
|
||||||
|
|
||||||
|
params.put("items", items);
|
||||||
|
|
||||||
|
String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" +
|
||||||
|
"MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtK\n" +
|
||||||
|
"uokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf\n" +
|
||||||
|
"3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE\n" +
|
||||||
|
"5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxS\n" +
|
||||||
|
"Tfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl\n" +
|
||||||
|
"42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+1\n" +
|
||||||
|
"3wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28\n" +
|
||||||
|
"ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy\n" +
|
||||||
|
"6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAj\n" +
|
||||||
|
"WIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqE\n" +
|
||||||
|
"hFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2\n" +
|
||||||
|
"vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9\n" +
|
||||||
|
"p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2\n" +
|
||||||
|
"EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFW\n" +
|
||||||
|
"OrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x\n" +
|
||||||
|
"98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/Xh\n" +
|
||||||
|
"YRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2A\n" +
|
||||||
|
"D+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJz\n" +
|
||||||
|
"NtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL\n" +
|
||||||
|
"2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIca\n" +
|
||||||
|
"PrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMP\n" +
|
||||||
|
"n2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP\n" +
|
||||||
|
"/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywd\n" +
|
||||||
|
"zyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvN\n" +
|
||||||
|
"bs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=\n" +
|
||||||
|
"-----END RSA PRIVATE KEY-----";
|
||||||
|
|
||||||
|
String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCy\n" +
|
||||||
|
"qKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9e\n" +
|
||||||
|
"g6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYz\n" +
|
||||||
|
"j9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzr\n" +
|
||||||
|
"tDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQ\n" +
|
||||||
|
"COa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo\n" +
|
||||||
|
"/QIDAQAB";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 加签
|
||||||
|
String sign = RsaSignUtil.generateSign(new HashMap<>(params), privateKey);
|
||||||
|
System.out.println("生成的签名: " + sign);
|
||||||
|
|
||||||
|
// 2. 将签名放入参数中
|
||||||
|
params.put("sign", sign);
|
||||||
|
|
||||||
|
// 3. 验签
|
||||||
|
boolean isValid = RsaSignUtil.verifySign(new HashMap<>(params), publicKey);
|
||||||
|
System.out.println("验签结果: " + isValid);
|
||||||
|
|
||||||
|
// 4. 测试排序字符串生成
|
||||||
|
String sortedString = RsaSignUtil.objectToSortedString(params);
|
||||||
|
System.out.println("排序后的字符串: " + sortedString);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
WalletApiService walletApiService;
|
||||||
|
|
||||||
|
@ApiOperation("获取银行信息")
|
||||||
|
@PostMapping("/getBankList")
|
||||||
|
public ResponseResult<BankListDTO> getBankList(@RequestBody GetBankRequest request) {
|
||||||
|
BankListDTO bankList = walletApiService.getBankList(request);
|
||||||
|
return ResponseResult.success(bankList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("签约人开通信息")
|
||||||
|
@PostMapping("/createStoreAndAccount")
|
||||||
|
public ResponseResult<StoreAccountDTO> createStoreAndAccount(@RequestBody CreateStoreAndAccountRequest request) {
|
||||||
|
StoreAccountDTO dto = walletApiService.createStoreAndAccount(request);
|
||||||
|
return ResponseResult.success(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("创建门店接口")
|
||||||
|
@PostMapping("/createStore")
|
||||||
|
public ResponseResult<AccountNoDTO> createStore(@RequestBody CreateStoreRequest request) {
|
||||||
|
AccountNoDTO accountNoDTO = walletApiService.createStore(request);
|
||||||
|
return ResponseResult.success(accountNoDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("打标接口")
|
||||||
|
@PostMapping("/addTag")
|
||||||
|
public ResponseResult<AddTagDTO> addTag(@RequestBody AccountAddTagRequest request) {
|
||||||
|
AddTagDTO addTag = walletApiService.addTag(request);
|
||||||
|
return ResponseResult.success(addTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("门店签约人账户鉴权申请接口")
|
||||||
|
@PostMapping("/authentication")
|
||||||
|
public ResponseResult<AccountAuthenticationDTO> authentication(@RequestBody OutStoreIdRequest request) {
|
||||||
|
AccountAuthenticationDTO accountAuthenticationDTO = walletApiService.authentication(request);
|
||||||
|
return ResponseResult.success(accountAuthenticationDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("门店签约人账户开通接口")
|
||||||
|
@PostMapping("/openAccount")
|
||||||
|
public ResponseResult<AccountVerifyDTO> openAccount(@RequestBody AccountVerifyRequest request) {
|
||||||
|
AccountVerifyDTO accountVerifyDTO = walletApiService.openAccount(request);
|
||||||
|
return ResponseResult.success(accountVerifyDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取账户信息")
|
||||||
|
@PostMapping("/getAccountInfo")
|
||||||
|
public ResponseResult<AccountInfoDTO> getAccountInfo(@RequestBody OutStoreIdRequest request) {
|
||||||
|
AccountInfoDTO accountInfo = walletApiService.getAccountInfo(request);
|
||||||
|
return ResponseResult.success(accountInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation("大额预支付接口")
|
||||||
|
@PostMapping("/largePayment")
|
||||||
|
public ResponseResult<LargePaymentDTO> largePayment(@RequestBody LargePaymentRequest request) {
|
||||||
|
LargePaymentDTO largePayment = walletApiService.largePayment(request);
|
||||||
|
return ResponseResult.success(largePayment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("大额预支付查询接口")
|
||||||
|
@PostMapping("/largePaymentQuery")
|
||||||
|
public ResponseResult<PaymentDTO> largePaymentQuery(@RequestBody PaymentDetailRequest request) {
|
||||||
|
PaymentDTO PaymentDTO = walletApiService.largePaymentQuery(request);
|
||||||
|
return ResponseResult.success(PaymentDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,3 +156,8 @@ huoMa.franchise.stores.account = 13563273279
|
|||||||
huoMa.franchise.stores.password = Zx@123456.
|
huoMa.franchise.stores.password = Zx@123456.
|
||||||
huoMa.restaurant.stores.account = 18656552865
|
huoMa.restaurant.stores.account = 18656552865
|
||||||
huoMa.restaurant.stores.password = ZX123456
|
huoMa.restaurant.stores.password = ZX123456
|
||||||
|
|
||||||
|
cool.api.rsa.private.key=MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+13wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAjWIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqEhFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFWOrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/XhYRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2AD+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJzNtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIcaPrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMPn2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywdzyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvNbs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=
|
||||||
|
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQAB
|
||||||
|
wallet.api.rsa.public.key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOmsrFtFPTnEzfpJ/hDl5RODBxw4i9Ex3NmmG/N7A1+by032zZZgLLpdNh8y5otjFY07Nyr4FGKFRSSuDiTk8vfx3pv6ImS1Rxjjg4qdVHIfqhCeB0Z2ZPuBD3Gbj8hHFEtXZq8+msAFu/5ZQjiVhgs5WWBjh54LYWSum+d9+wIDAQAB
|
||||||
|
|
||||||
|
|||||||
@@ -141,4 +141,8 @@ hqt.token.url=https://tc.cloud.hecom.cn
|
|||||||
hqt.token.username=18161486722
|
hqt.token.username=18161486722
|
||||||
hqt.token.grant_type=client_credentials
|
hqt.token.grant_type=client_credentials
|
||||||
hqt.token.client.id=WrPffdGpcWkcPsbN
|
hqt.token.client.id=WrPffdGpcWkcPsbN
|
||||||
hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD
|
hqt.token.client.secret=rYe9Cwug5LwQNIBJAiW0a7weF9CAhYCD
|
||||||
|
|
||||||
|
cool.api.rsa.private.key=MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+13wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAjWIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqEhFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFWOrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/XhYRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2AD+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJzNtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIcaPrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMPn2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywdzyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvNbs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=
|
||||||
|
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQAB
|
||||||
|
wallet.api.rsa.public.key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOmsrFtFPTnEzfpJ/hDl5RODBxw4i9Ex3NmmG/N7A1+by032zZZgLLpdNh8y5otjFY07Nyr4FGKFRSSuDiTk8vfx3pv6ImS1Rxjjg4qdVHIfqhCeB0Z2ZPuBD3Gbj8hHFEtXZq8+msAFu/5ZQjiVhgs5WWBjh54LYWSum+d9+wIDAQAB
|
||||||
|
|||||||
@@ -169,3 +169,8 @@ huoMa.franchise.stores.account = 13563273279
|
|||||||
huoMa.franchise.stores.password = Zx@123456.
|
huoMa.franchise.stores.password = Zx@123456.
|
||||||
huoMa.restaurant.stores.account = 18656552865
|
huoMa.restaurant.stores.account = 18656552865
|
||||||
huoMa.restaurant.stores.password = ZX123456
|
huoMa.restaurant.stores.password = ZX123456
|
||||||
|
|
||||||
|
|
||||||
|
cool.api.rsa.private.key=MIIEpQIBAAKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQABAoIBACbBGi8I+CE77M+13wAu4RkD8xL7CQc3ic2ojGqIRPi7r5CuphD6mpzvXqtyfhd7DKr9h8bAxwBlnQ28ObjVgsI96/aM7dxvMs/uVPpqwIJyWuTDG5A05EPVC9REQnC6Mp09mnPL7rZz3Mfy6dIGY2YQWfwmWiPl1B45k+wZ+WPZPI0JVnvRzM881kf4aAhEAt08i9VoihylwVAjWIPmLuhf6ZcqI5q8iUsjfO22wZJsudVTCA/dsJdNxv+1RDKeYnSLJL79cZQcodqEhFqTy6vnn2dMsaHH7dpphU27barxUjeL482SR7kFfMqEXn5sltRn/3ep+3sf4Ph2vMtoZeECgYEA6gXzEtT9ZOeAMp4BRGmfNZ0TQLprPPVSwudz/uUBE4j/vyhfXkh9p7hqwyoxN+Z8b65yINvx8yP6hge6ek/MyAwBCZyfIRxZAPZu1eEGoYKl391ubFt2EIVqrN2DtAvzHMr5B/E2VHBq6AJm/rERFX5oKsg6zHS9tPLhgGnWVd0CgYEA5aFWOrtiqZJlp1MHQ4OeWBJatBSynkORdxCW7ic0CKbkYus0NSz1SsvskpbnfEXNB53x98qJxRhSopg/DC4m7XqxjSf9lY3HH4Y/9907olj33yGAnLWC88GivVndt577u/XhYRCk33vOQ3GoibEdjnpMOkWmOfwYG/FsRWWQvaECgYEA1N2siEisZIgel+wZAv2AD+hchtgKi1wqd5bIb+Yl4HsRBfPXK4+MnG6mzfcm5c4FCiEHNtRZc+waCKgm+vJzNtOUbgXEyP1cCAAgOPOCcI7CCqsDshRPhB+XNL4Y+kCUVnBZrNu/q3bGB1uIC8tL2t0sKx4OPcNCe8EhVQjwKRECgYEA4uothdhKRPtwDIsVsHfN74Yjr7SMVay7gIcaPrjqyGnzYnS+oJWOx50AaFNK6Rko5JAF3jF9NxE0B4yfMPAic6Y88hpEkpcJ4HMPn2Y1WdbFCu/WYgVUJICCys6VNLCcXj85umtyIY38Y9VbEMW/SV49GZBeFQqy4FoP/fvBrkECgYEAnfjTDYwgdmJdsUqyNzAocwcJXG2rVtYc7Txrl0TltcwuJmgoSywdzyOP2R9+NZsfoxWDzG0/yr15ApMvUcnnTwHN/8bGQ9SLatFLKqS4EtdwDKKS1JvNbs7V1myQGpt7jbShZOI0e6Fs4xP8ujxsLeGgiq9mZrS9UdRj5XKDoVM=
|
||||||
|
cool.api.rsa.public.key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0erPAWesjkp9J4htmfCyqKS9npmT9dW3KqWTfb4c7x/QBUtKuokWOO0XikHd4bGUa9kl+twSv/5A3kYz1B9eg6wRuDJoads+G5U7rVQjzdoUtLaf3lNXkuSehl4uHUPQfNa6vcmvzraXPxJjEpYzj9WZh7uJqq2oSgw42H1qdbFCXSaE5BwsOb+2vZXjzh4RO10Sy3Qb1UqGsoZoxVzrtDeEctCjrecFyQr96L2UtYa4NTxSTfu4rgObrwIOMvqqnLsXEzK/rd6kIHYjkZYQCOa48AedWp2YKQ7Ldclj+VMLnXvl42J9exVkbs++8k3P5sI9fdZX4Ey2RBjnSoAo/QIDAQAB
|
||||||
|
wallet.api.rsa.public.key=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOmsrFtFPTnEzfpJ/hDl5RODBxw4i9Ex3NmmG/N7A1+by032zZZgLLpdNh8y5otjFY07Nyr4FGKFRSSuDiTk8vfx3pv6ImS1Rxjjg4qdVHIfqhCeB0Z2ZPuBD3Gbj8hHFEtXZq8+msAFu/5ZQjiVhgs5WWBjh54LYWSum+d9+wIDAQAB
|
||||||
|
|||||||
5
pom.xml
5
pom.xml
@@ -232,6 +232,11 @@
|
|||||||
<artifactId>alibabacloud-dysmsapi20170525</artifactId>
|
<artifactId>alibabacloud-dysmsapi20170525</artifactId>
|
||||||
<version>2.0.24</version>
|
<version>2.0.24</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.70</version>
|
||||||
|
</dependency>
|
||||||
<!-- XML处理 -->
|
<!-- XML处理 -->
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|||||||
Reference in New Issue
Block a user