diff --git a/pom.xml b/pom.xml
index e25b444..27486bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,6 +93,12 @@
org.springframework.boot
spring-boot-starter-jdbc
+
+
+ org.reflections
+ reflections
+ 0.9.12
+
diff --git a/src/main/java/com/win/bank/enums/PaymentStatusEnum.java b/src/main/java/com/win/bank/enums/PaymentStatusEnum.java
new file mode 100644
index 0000000..f85ca71
--- /dev/null
+++ b/src/main/java/com/win/bank/enums/PaymentStatusEnum.java
@@ -0,0 +1,32 @@
+package com.win.bank.enums;
+
+public enum PaymentStatusEnum {
+
+ UNPROCESSED("0", "未处理"), PAYING("1", "支付中"), SUCCESS("2", "支付成功"), FAILED("3", "支付失败");
+
+ private final String code;
+ private final String description;
+
+ PaymentStatusEnum(String code, String description) {
+ this.code = code;
+ this.description = description;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public static PaymentStatusEnum getByCode(String code) {
+ for (PaymentStatusEnum status : PaymentStatusEnum.values()) {
+ if (status.getCode().equals(code)) {
+ return status;
+ }
+ }
+ throw new IllegalArgumentException("Invalid PaymentStatus code: " + code);
+ }
+
+}
diff --git a/src/main/java/com/win/bank/service/BaseBankService.java b/src/main/java/com/win/bank/service/BaseBankService.java
new file mode 100644
index 0000000..3d3e3a7
--- /dev/null
+++ b/src/main/java/com/win/bank/service/BaseBankService.java
@@ -0,0 +1,21 @@
+package com.win.bank.service;
+
+import com.win.bank.domain.BankDO;
+
+public interface BaseBankService {
+ /**
+ * 支付
+ *
+ * @param bankDO
+ * @return
+ */
+ BankDO payment(BankDO bankDO);
+
+ /**
+ * 查询支付结果
+ *
+ * @param bankDO
+ * @return
+ */
+ BankDO queryPaymentResult(BankDO bankDO);
+}
diff --git a/src/main/java/com/win/bank/service/MainService.java b/src/main/java/com/win/bank/service/MainService.java
index dbb7104..956d078 100644
--- a/src/main/java/com/win/bank/service/MainService.java
+++ b/src/main/java/com/win/bank/service/MainService.java
@@ -4,11 +4,13 @@ import java.util.List;
import javax.annotation.Resource;
-import com.win.bank.service.bank.BankService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.win.bank.domain.BankDO;
+import com.win.bank.enums.PaymentStatusEnum;
+import com.win.bank.service.bank.BankService;
+import com.win.bank.utils.BaseBankServiceUtil;
@Component
public class MainService {
@@ -16,14 +18,25 @@ public class MainService {
@Resource
private BankService bankService;
- @Scheduled(cron = "* * * * * ?")
- public void task() {
- System.out.println(System.currentTimeMillis());
-
- List bankDOList = bankService.listByStatus("0");
+ @Scheduled(cron = "0 0/1 * * * ? ")
+ public void payTask() {
+ List bankDOList = bankService.listByStatus(PaymentStatusEnum.UNPROCESSED.getCode());
+ for (BankDO bankDO : bankDOList) {
+ BaseBankService baseBankService = BaseBankServiceUtil.get(bankDO.getPayBankCode().toUpperCase());
+ bankDO = baseBankService.payment(bankDO);
+ bankService.updateById(bankDO);
+ }
+ }
+ @Scheduled(cron = "30 0/1 * * * ? ")
+ public void queryPaymentResult() {
+ List bankDOList = bankService.listByStatus(PaymentStatusEnum.PAYING.getCode());
for (BankDO bankDO : bankDOList) {
- System.out.println(bankDO);
+ BaseBankService baseBankService = BaseBankServiceUtil.get(bankDO.getPayBankCode().toUpperCase());
+ bankDO = baseBankService.queryPaymentResult(bankDO);
+ if (bankDO != null) {
+ bankService.updateById(bankDO);
+ }
}
}
}
diff --git a/src/main/java/com/win/bank/service/bocom/BocomServiceImpl.java b/src/main/java/com/win/bank/service/bocom/BocomServiceImpl.java
new file mode 100644
index 0000000..6c6cf87
--- /dev/null
+++ b/src/main/java/com/win/bank/service/bocom/BocomServiceImpl.java
@@ -0,0 +1,28 @@
+package com.win.bank.service.bocom;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.win.bank.domain.BankDO;
+import com.win.bank.service.BaseBankService;
+
+/**
+ * 交通银行
+ */
+@Service
+public class BocomServiceImpl implements BaseBankService {
+ private static final Logger logger = LoggerFactory.getLogger(BocomServiceImpl.class);
+
+ @Override
+ public BankDO payment(BankDO bankDO) {
+ logger.debug("交通银行 payment");
+ return bankDO;
+ }
+
+ @Override
+ public BankDO queryPaymentResult(BankDO bankDO) {
+ logger.debug("交通银行 queryPaymentResult");
+ return bankDO;
+ }
+}
diff --git a/src/main/java/com/win/bank/service/cmb/ApiDemo.java b/src/main/java/com/win/bank/service/cmb/ApiDemo.java
deleted file mode 100644
index 508525f..0000000
--- a/src/main/java/com/win/bank/service/cmb/ApiDemo.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.win.bank.service.cmb;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Security;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Random;
-
-import org.bouncycastle.crypto.CryptoException;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-/**
- * 招商银行银企直联国密免前置/SaaS对接示例,本示例仅供参考,不保证各种异常场景运行,请勿直接使用,如有错漏请联系对接人员。运行时,请使用所获取的测试资源替换 用户编号、公私钥、对称密钥、服务商编号等信息。
- *
- * @author cmb.firmbank
- * @date 2023/7/20
- */
-public class ApiDemo {
-
- private static final int BOUND_START = 1000000;
- private static final int BOUND_END = 9000000;
- // 测试地址,生产需要替换
- private static String url = "http://192.168.0.142:8080/cdcserver/api/v2";
- // private static String url = "http://cdctest.cmburl.cn:80/cdcserver/api/v2";
- // 生产地址
- // private static String url = "https://cdc.cmbchina.com/cdcserver/api/v2";
- // 银行公钥,生产需要替换
- private static String publicKey = "BNsIe9U0x8IeSe4h/dxUzVEz9pie0hDSfMRINRXc7s1UIXfkExnYECF4QqJ2SnHxLv3z/99gsfDQrQ6dzN5lZj0=";
- // 生产环境银行公钥
- // private static String publicKey =
- // "BEynMEZOjNpwZIiD9jXtZSGr3Ecpwn7r+m+wtafXHb6VIZTnugfuxhcKASq3hX+KX9JlHODDl9/RDKQv4XLOFak=";
- // 客户私钥,生产需要替换
- private static String privateKey = "NBtl7WnuUtA2v5FaebEkU0/Jj1IodLGT6lQqwkzmd2E=";
- // 对称密钥,生产需要替换
- private static String symKey = "VuAzSWQhsoNqzn0K";
-
- // 企业网银用户号,生产需要替换
- private static String uid = "N002986522";
-
- private static Random random = new Random();
-
- private ApiDemo() {}
-
- public static void main(String[] args) throws GeneralSecurityException, IOException, CryptoException {
- // 装载BC库,必须在应用的启动类中调用此函数
- Security.addProvider(new BouncyCastleProvider());
- System.setProperty("sun.net.http.retryPost", "false");
-
- // 业务接口名,这里是查询业务模式接口,生产请替换为对应接口名
- String funcode = "BB1PAYQR";
- // 准备接口数据,生产请替换为具体接口请求报文,包含所需的请求字段
- String currentDatetime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
- String reqid = new SimpleDateFormat("yyyyMMddHHmmssSSSS").format(new Date()) + (BOUND_START + random.nextInt(BOUND_END));
- String data =
- "{\"request\":{\"body\":{\"bb1paybmx1\":[{\"busCod\":\"N02030\",\"busMod\":\"00002\"}],\"bb1payopx1\":[{\"ccyNbr\":\"10\",\"crtAcc\":\"6214831150131511\",\"crtNam\":\"吴极客\",\"dbtAcc\":\"755936045010501\",\"nusAge\":\"用途\",\"bnkFlg\":\"Y\",\"trsAmt\":\"1.05\",\"yurRef\":\"2024041709400601\"}]},\"head\":{\"funcode\":\"BB1PAYOP\",\"userid\":\"N002986522\"}}}";
-
- // String data =
- // "{\"request\":{\"body\":{\"bb1payqrx1\":[{\"busCod\":\"N02030\",\"yurRef\":\"2024041709400602\"}]},\"head\":{\"funcode\":\"BB1PAYQR\",\"userid\":\"N002986522\"}}}";
- System.out.println(data);
- DcHelper dchelper = new DcHelper(url, uid, privateKey, publicKey, symKey);
- // 添加设备信息,请根据文档指引填写真实的信息,参数按顺序分别为:出口IP(无需)、MAC地址、CPU-ID、计算机名、主板ID、主板厂商
- // DeviceInfo deviceInfo = new DeviceInfo(null, "9822EFF12C6B", "AABBCCDDEEFFGGHH", "XXX", "XXX", "XXX");
- // String response = dchelper.sendRequest(data, funcode);
- // process("Api请求1成功,响应报文:\r\n" + response);
- // String response2 = dchelper.sendRequest(data, funcode, deviceInfo);
- // process("Api请求2成功,响应报文:\r\n" + response2);
- }
-
- private static void process(String response) {
-
- }
-}
diff --git a/src/main/java/com/win/bank/service/cmb/CmbServiceImpl.java b/src/main/java/com/win/bank/service/cmb/CmbServiceImpl.java
index c6bab1d..7e9ea2e 100644
--- a/src/main/java/com/win/bank/service/cmb/CmbServiceImpl.java
+++ b/src/main/java/com/win/bank/service/cmb/CmbServiceImpl.java
@@ -1,17 +1,62 @@
package com.win.bank.service.cmb;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.*;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.win.bank.domain.BankDO;
+import com.win.bank.enums.PaymentStatusEnum;
+import com.win.bank.service.BaseBankService;
+import com.win.bank.utils.JsonUtil;
+/**
+ * 招商银行
+ */
@Service
-public class CmbServiceImpl {
+public class CmbServiceImpl implements BaseBankService {
+
+ // 企业网银用户号
+ @Value("${cmb.uid}")
+ private String uid;
+
+ @Value("${cmb.url}")
+ private String url;
+
+ // 业务模式编号
+ @Value("${cmb.busMod}")
+ private String busMod;
- public String payment(BankDO bankDO) {
- String data = "{\"request\":{\"body\":{\"bb1paybmx1\":[{\"busCod\":\"N02030\",\"busMod\":\"00002\"}]},\"head\":{\"funcode\":\"BB1PAYOP\",\"userid\":\"N002986522\"}}}";
+ // 算法,固定为国密算法
+ private static final String alg = "SM";
+ private static final int CONNECT_TIMEOUT = 15000;
+ private static final int READ_TIMEOUT = 60000;
+ private static final int STATUS_OK = 200;
+ private static final String SUCCESS_CODE = "SUC0000";
+ private static final Logger logger = LoggerFactory.getLogger(CmbServiceImpl.class);
+
+ @Override
+ public BankDO payment(BankDO bankDO) {
+ String funCode = "BB1PAYOP";
+ String data = "{\"request\":{\"body\":{\"bb1paybmx1\":[{\"busCod\":\"N02030\",\"busMod\":\"" + busMod + "\"}]},\"head\":{\"funcode\":\"" + funCode + "\",\"userid\":\"" + uid + "\"}}}";
JsonObject requestJson = new Gson().fromJson(data, JsonObject.class);
JsonArray bb1payopx1 = new JsonArray();
JsonObject info = new JsonObject();
@@ -21,11 +66,167 @@ public class CmbServiceImpl {
info.addProperty("ccyNbr", "10");
info.addProperty("trsAmt", bankDO.getAmount().toString());
info.addProperty("nusAge", bankDO.getPurpose());
- info.addProperty("bnkFlg", "Y");
+ String bnkFlg = "Y";
+ if (!StringUtils.isEmpty(bankDO.getRcvBankName()) && !bankDO.getRcvBankName().contains("招商")) {
+ bnkFlg = "N";
+ }
+ info.addProperty("bnkFlg", bnkFlg);
info.addProperty("yurRef", bankDO.getId().toString());
bb1payopx1.add(info);
requestJson.getAsJsonObject("request").getAsJsonObject("body").add("bb1payopx1", bb1payopx1);
- System.out.println(requestJson);
- return null;
+ logger.debug("发送给招商银行的数据:" + JsonUtil.formatJson(requestJson.toString()));
+ String response;
+ try {
+ response = sendRequest(requestJson.toString(), funCode);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ logger.debug("收到招商银行的数据:" + JsonUtil.formatJson(response));
+ JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
+ JsonObject headJson = responseJson.getAsJsonObject("response").getAsJsonObject("head");
+ if (SUCCESS_CODE.equals(headJson.get("resultcode").getAsString())) {
+ JsonObject resultJson = responseJson.getAsJsonObject("response").getAsJsonObject("body").getAsJsonArray("bb1payopz1").get(0).getAsJsonObject();
+ String errCode = resultJson.get("errCod").getAsString();
+ if (SUCCESS_CODE.equals(errCode)) {
+ bankDO.setStatus(PaymentStatusEnum.PAYING.getCode());
+ } else {
+ bankDO.setStatus(PaymentStatusEnum.FAILED.getCode());
+ bankDO.setMessage(resultJson.get("errTxt").getAsString());
+ }
+ } else {
+ bankDO.setStatus(PaymentStatusEnum.FAILED.getCode());
+ bankDO.setMessage(headJson.get("resultmsg").getAsString());
+ }
+ return bankDO;
+ }
+
+ @Override
+ public BankDO queryPaymentResult(BankDO bankDO) {
+ String funCode = "BB1PAYQR";
+ String yurRef = bankDO.getId().toString();
+ String data = "{\"request\":{\"body\":{\"bb1payqrx1\":[{\"busCod\":\"N02030\",\"yurRef\":\"" + yurRef + "\"}]},\"head\":{\"funcode\":\"" + funCode + "\",\"userid\":\"" + uid + "\"}}}";
+ logger.debug("发送给招商银行的数据" + JsonUtil.formatJson(data));
+ String response;
+ try {
+ response = sendRequest(data, funCode);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ logger.debug("收到招商银行的数据:" + JsonUtil.formatJson(response));
+ JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
+ JsonObject headJson = responseJson.getAsJsonObject("response").getAsJsonObject("head");
+ if (SUCCESS_CODE.equals(headJson.get("resultcode").getAsString())) {
+ JsonObject resultJson = responseJson.getAsJsonObject("response").getAsJsonObject("body").getAsJsonArray("bb1payqrz1").get(0).getAsJsonObject();
+ String reqSts = resultJson.get("reqSts").getAsString();
+ if ("FIN".equals(reqSts)) {
+ if ("S".equals(resultJson.get("rtnFlg").getAsString())) {
+ bankDO.setStatus(PaymentStatusEnum.SUCCESS.getCode());
+ bankDO.setSerialNumber(resultJson.get("trxSeq").getAsString());
+ } else {
+ bankDO.setStatus(PaymentStatusEnum.FAILED.getCode());
+ bankDO.setMessage(resultJson.get("rtnNar").getAsString());
+ }
+ } else {
+ return null;
+ }
+ } else {
+ bankDO.setMessage(headJson.get("resultmsg").getAsString());
+ }
+ return bankDO;
+ }
+
+ public String sendRequest(String data, String funcode) throws Exception {
+ HashMap map = new HashMap<>();
+ map.put("UID", uid);
+ map.put("ALG", alg);
+ map.put("DATA", URLEncoder.encode(data, StandardCharsets.UTF_8.displayName()));
+ map.put("FUNCODE", funcode);
+ String response = httpPost(url, map);
+ if (response.startsWith("CDCServer:")) {
+ throw new IOException("访问目标地址 " + url + " 失败:" + response);
+ }
+ return response;
+ }
+
+ private static String httpPost(String httpUrl, Map param) throws IOException, GeneralSecurityException {
+ HttpURLConnection connection = null;
+ String result;
+ try {
+ URL url = new URL(httpUrl);
+ SSLContext sslcontext;
+ sslcontext = SSLContext.getInstance("SSL");
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore)null);
+ X509TrustManager defaultTm = null;
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509TrustManager) {
+ defaultTm = (X509TrustManager)tm;
+ break;
+ }
+ }
+ sslcontext.init(null, new TrustManager[] {defaultTm}, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
+
+ connection = (HttpURLConnection)url.openConnection();
+ connection.setRequestMethod("POST");
+ connection.setConnectTimeout(CONNECT_TIMEOUT);
+ connection.setReadTimeout(READ_TIMEOUT);
+ connection.setInstanceFollowRedirects(true);
+
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+
+ connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ try (OutputStream os = connection.getOutputStream()) {
+ os.write(createLinkString(param).getBytes());
+ if (connection.getResponseCode() != STATUS_OK) {
+ InputStream is = connection.getErrorStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ StringBuilder sbf = new StringBuilder();
+ String temp;
+ while ((temp = br.readLine()) != null) {
+ sbf.append(temp);
+ sbf.append("\r\n");
+ }
+
+ result = sbf.toString();
+ br.close();
+ is.close();
+ } else {
+ InputStream is = connection.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ StringBuilder sbf = new StringBuilder();
+ String temp;
+ while ((temp = br.readLine()) != null) {
+ sbf.append(temp);
+ }
+ result = sbf.toString();
+ br.close();
+ is.close();
+ }
+ }
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ return result;
+ }
+
+ private static String createLinkString(Map params) {
+ ArrayList keys = new ArrayList<>(params.keySet());
+ Collections.sort(keys);
+
+ StringBuilder prestr = new StringBuilder();
+ for (int i = 0; i < keys.size(); i++) {
+ String key = keys.get(i);
+ String value = params.get(key);
+ if (i == keys.size() - 1) {
+ prestr.append(key).append("=").append(value);
+ } else {
+ prestr.append(key).append("=").append(value).append("&");
+ }
+ }
+ return prestr.toString();
}
}
diff --git a/src/main/java/com/win/bank/service/cmb/DcHelper.java b/src/main/java/com/win/bank/service/cmb/DcHelper.java
deleted file mode 100644
index a0698ed..0000000
--- a/src/main/java/com/win/bank/service/cmb/DcHelper.java
+++ /dev/null
@@ -1,369 +0,0 @@
-package com.win.bank.service.cmb;
-
-import java.io.*;
-import java.math.BigInteger;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.util.*;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import javax.net.ssl.*;
-
-import org.bouncycastle.asn1.*;
-import org.bouncycastle.crypto.CryptoException;
-import org.bouncycastle.crypto.params.ECDomainParameters;
-import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
-import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.crypto.params.ParametersWithID;
-import org.bouncycastle.crypto.signers.SM2Signer;
-import org.bouncycastle.jce.ECNamedCurveTable;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.jce.spec.ECParameterSpec;
-import org.bouncycastle.math.ec.ECPoint;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-
-/**
- * 招商银行银企直联国密免前置/SaaS对接示例,本示例仅供参考,不保证各种异常场景运行,请勿直接使用,如有错漏请联系对接人员。运行时,请使用所获取的测试资源替换 用户编号、公私钥、对称密钥、服务商编号等信息。
- *
- * @author cmb.firmbank
- * @date 2023/7/20
- */
-public class DcHelper {
-
- private static final int LENGTH_32 = 32;
- private static final int USERID_LEN = 16;
- private static final int CONNECT_TIMEOUT = 15000;
- private static final int READ_TIMEOUT = 60000;
- private static final int STATUS_OK = 200;
- private static Base64.Encoder encoder = Base64.getEncoder();
- private static Base64.Decoder decoder = Base64.getDecoder();
-
- // 请求URL
- private final String url;
- // 企业网银用户号
- private final String uid;
- // 国密算法向量,根据用户号生成
- private final byte[] userId;
- // 算法,固定为国密算法
- private final String alg;
- // 客户私钥
- private final byte[] privateKey;
- // 银行公钥
- private final byte[] publicKey;
- // 协商的对称密钥
- private final byte[] symKey;
-
- private static final Logger logger = LoggerFactory.getLogger(DcHelper.class);
-
- public DcHelper(String url, String uid, String privateKey, String publicKey, String symKey) {
- this.url = url;
- this.uid = uid;
- this.userId = getUserId(uid);
- this.alg = "SM";
- this.privateKey = decoder.decode(privateKey);
- this.publicKey = decoder.decode(publicKey);
- this.symKey = symKey.getBytes(StandardCharsets.UTF_8);
- }
-
- public String sendRequest(String data, String funcode) throws IOException, CryptoException, GeneralSecurityException {
- // 增加设备信息
- JsonObject requestJson = new Gson().fromJson(data, JsonObject.class);
- // requestJson.getAsJsonObject("request").add("exthdr", deviceInfo.toJson());
- // 对请求报文做排序
- String source = recursiveKeySort(requestJson);
- // 生成签名
- // byte[] signature = cmbSM2SignWithSM3(userId, privateKey, source.getBytes(StandardCharsets.UTF_8));
- // 替换签名字段
- // requestJson.getAsJsonObject("signature").addProperty("sigdat", new String(encoder.encode(signature),
- // StandardCharsets.UTF_8));
-
- // 对数据进行对称加密
- // String request = requestJson.toString();
- // byte[] encryptRequest = cmbSM4Crypt(symKey, userId, request.getBytes(StandardCharsets.UTF_8), 1);
- // String encryptedRequest = new String(encoder.encode(encryptRequest), StandardCharsets.UTF_8);
- logger.debug(data);
- // 发送请求
- HashMap map = new HashMap<>();
- map.put("UID", uid);
- map.put("ALG", alg);
- map.put("DATA", URLEncoder.encode(data, StandardCharsets.UTF_8.displayName()));
- // map.put("DATA", URLEncoder.encode(encryptedRequest, StandardCharsets.UTF_8.displayName()));
- map.put("FUNCODE", funcode);
- String response = httpPost(url, map);
- // logger.debug(response);
- printJson(data);
- if (response.startsWith("CDCServer:")) {
- throw new IOException("访问目标地址 " + url + " 失败:" + response);
- }
-
- // 返回结果解密
- // response = new String((cmbSM4Crypt(symKey, userId, decoder.decode(response), 2)), StandardCharsets.UTF_8);
-
- // 验证签名是否正确
- // JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
- // JsonObject signatureJson = responseJson.getAsJsonObject("signature");
- // String responseSignature = signatureJson.get("sigdat").getAsString();
- // signatureJson.addProperty("sigdat", "__signature_sigdat__");
- // responseJson.add("signature", signatureJson);
- // String responseSorted = recursiveKeySort(responseJson);
- // boolean verify = cmbSM2VerifyWithSM3(userId, publicKey, responseSorted.getBytes(StandardCharsets.UTF_8),
- // decoder.decode(responseSignature));
- // if (!verify) {
- // throw new IOException("响应报文的签名无效");
- // }
- printJson(response);
- return response;
- }
-
- private static String recursiveKeySort(JsonObject json) {
- StringBuilder appender = new StringBuilder();
- appender.append("{");
- Iterator keys = new TreeSet<>(json.keySet()).iterator();
- boolean isFirstEle = true;
- while (keys.hasNext()) {
- if (!isFirstEle) {
- appender.append(",");
- }
- String key = keys.next();
- Object val = json.get(key);
- if (val instanceof JsonObject) {
- appender.append("\"").append(key).append("\":");
- appender.append(recursiveKeySort((JsonObject)val));
- } else if (val instanceof JsonArray) {
- JsonArray jarray = (JsonArray)val;
- appender.append("\"").append(key).append("\":[");
- boolean isFirstArrEle = true;
- for (int i = 0; i < jarray.size(); i++) {
- if (!isFirstArrEle) {
- appender.append(",");
- }
- Object obj = jarray.get(i);
- if (obj instanceof JsonObject) {
- appender.append(recursiveKeySort((JsonObject)obj));
- } else {
- appender.append(obj.toString());
- }
- isFirstArrEle = false;
- }
- appender.append("]");
- } else {
- String value = val.toString();
- appender.append("\"").append(key).append("\":").append(value);
- }
- isFirstEle = false;
- }
- appender.append("}");
- return appender.toString();
- }
-
- private static byte[] getUserId(String uid) {
- return (uid + "0000000000000000").substring(0, USERID_LEN).getBytes();
- }
-
- private static String httpPost(String httpUrl, Map param) throws IOException, GeneralSecurityException {
- HttpURLConnection connection = null;
- String result;
- try {
- URL url = new URL(httpUrl);
- SSLContext sslcontext;
- sslcontext = SSLContext.getInstance("SSL");
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- tmf.init((KeyStore)null);
- X509TrustManager defaultTm = null;
- for (TrustManager tm : tmf.getTrustManagers()) {
- if (tm instanceof X509TrustManager) {
- defaultTm = (X509TrustManager)tm;
- break;
- }
- }
- sslcontext.init(null, new TrustManager[] {defaultTm}, new java.security.SecureRandom());
- HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
-
- connection = (HttpURLConnection)url.openConnection();
- connection.setRequestMethod("POST");
- connection.setConnectTimeout(CONNECT_TIMEOUT);
- connection.setReadTimeout(READ_TIMEOUT);
- connection.setInstanceFollowRedirects(true);
-
- connection.setDoOutput(true);
- connection.setDoInput(true);
-
- connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- try (OutputStream os = connection.getOutputStream()) {
- os.write(createLinkString(param).getBytes());
- if (connection.getResponseCode() != STATUS_OK) {
- InputStream is = connection.getErrorStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
- StringBuilder sbf = new StringBuilder();
- String temp;
- while ((temp = br.readLine()) != null) {
- sbf.append(temp);
- sbf.append("\r\n");
- }
-
- result = sbf.toString();
- br.close();
- is.close();
- } else {
- InputStream is = connection.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
- StringBuilder sbf = new StringBuilder();
- String temp;
- while ((temp = br.readLine()) != null) {
- sbf.append(temp);
- }
- result = sbf.toString();
- br.close();
- is.close();
- }
- }
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- }
- return result;
- }
-
- private static String createLinkString(Map params) {
- ArrayList keys = new ArrayList<>(params.keySet());
- Collections.sort(keys);
-
- StringBuilder prestr = new StringBuilder();
- for (int i = 0; i < keys.size(); i++) {
- String key = keys.get(i);
- String value = params.get(key);
- if (i == keys.size() - 1) {
- prestr.append(key).append("=").append(value);
- } else {
- prestr.append(key).append("=").append(value).append("&");
- }
- }
- return prestr.toString();
- }
-
- // 以下是加解密相关的函数
-
- private static byte[] cmbSM2SignWithSM3(byte[] id, byte[] privkey, byte[] msg) throws IOException, CryptoException {
- if (privkey == null || msg == null) {
- throw new CryptoException("CMBSM2SignWithSM3 input error");
- }
- ECPrivateKeyParameters privateKey = encodePrivateKey(privkey);
- SM2Signer signer = new SM2Signer();
- ParametersWithID parameters = new ParametersWithID(privateKey, id);
- signer.init(true, parameters);
- signer.update(msg, 0, msg.length);
- return decodeDERSignature(signer.generateSignature());
- }
-
- private static ECPrivateKeyParameters encodePrivateKey(byte[] value) {
- BigInteger d = new BigInteger(1, value);
- ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
- ECDomainParameters ecParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
- return new ECPrivateKeyParameters(d, ecParameters);
- }
-
- private static byte[] decodeDERSignature(byte[] signature) throws IOException {
- ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
- ASN1Sequence primitive = (ASN1Sequence)stream.readObject();
- Enumeration enumeration = primitive.getObjects();
- BigInteger intR = enumeration.nextElement().getValue();
- BigInteger intS = enumeration.nextElement().getValue();
- byte[] bytes = new byte[LENGTH_32 * 2];
- byte[] r = format(intR.toByteArray());
- byte[] s = format(intS.toByteArray());
- System.arraycopy(r, 0, bytes, 0, LENGTH_32);
- System.arraycopy(s, 0, bytes, LENGTH_32, LENGTH_32);
- return bytes;
- }
-
- private static byte[] format(byte[] value) {
- if (value.length == LENGTH_32) {
- return value;
- } else {
- byte[] bytes = new byte[LENGTH_32];
- if (value.length > LENGTH_32) {
- System.arraycopy(value, value.length - LENGTH_32, bytes, 0, LENGTH_32);
- } else {
- System.arraycopy(value, 0, bytes, LENGTH_32 - value.length, value.length);
- }
- return bytes;
- }
- }
-
- private static byte[] cmbSM4Crypt(byte[] key, byte[] iv, byte[] input, int mode) throws GeneralSecurityException {
- SecretKeySpec spec = new SecretKeySpec(key, "SM4");
- IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
- Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding", BouncyCastleProvider.PROVIDER_NAME);
- cipher.init(mode, spec, ivParameterSpec);
- return cipher.doFinal(input);
- }
-
- private static boolean cmbSM2VerifyWithSM3(byte[] id, byte[] pubkey, byte[] msg, byte[] signature) throws IOException {
-
- if (pubkey == null || msg == null || signature == null) {
- throw new IllegalArgumentException("CMBSM2VerifyWithSM3 input error");
- }
- ECPublicKeyParameters publicKey = encodePublicKey(pubkey);
- SM2Signer signer = new SM2Signer();
- ParametersWithID parameters = new ParametersWithID(publicKey, id);
- signer.init(false, parameters);
- signer.update(msg, 0, msg.length);
- return signer.verifySignature(encodeDERSignature(signature));
- }
-
- private static ECPublicKeyParameters encodePublicKey(byte[] value) {
- byte[] x = new byte[LENGTH_32];
- byte[] y = new byte[LENGTH_32];
- System.arraycopy(value, 1, x, 0, LENGTH_32);
- System.arraycopy(value, LENGTH_32 + 1, y, 0, LENGTH_32);
- BigInteger intX = new BigInteger(1, x);
- BigInteger intY = new BigInteger(1, y);
- ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
- ECPoint intQ = spec.getCurve().createPoint(intX, intY);
- ECDomainParameters ecParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
- return new ECPublicKeyParameters(intQ, ecParameters);
- }
-
- private static byte[] encodeDERSignature(byte[] signature) throws IOException {
- byte[] r = new byte[LENGTH_32];
- byte[] s = new byte[LENGTH_32];
- System.arraycopy(signature, 0, r, 0, LENGTH_32);
- System.arraycopy(signature, LENGTH_32, s, 0, LENGTH_32);
- ASN1EncodableVector vector = new ASN1EncodableVector();
- vector.add(new ASN1Integer(new BigInteger(1, r)));
- vector.add(new ASN1Integer(new BigInteger(1, s)));
- return (new DERSequence(vector)).getEncoded();
- }
-
- private void printJson(String jsonStr) {
- ObjectMapper mapper = new ObjectMapper();
- mapper.enable(SerializationFeature.INDENT_OUTPUT);
-
- try {
- // 原始的JSON字符串
- // String jsonStr = "{\"name\": \"Alice\", \"age\": 30, \"city\": \"Beijing\"}";
-
- // 格式化打印JSON字符串
- Object json = mapper.readValue(jsonStr, Object.class);
- String formattedJsonStr = mapper.writeValueAsString(json);
- // System.out.println(formattedJsonStr);
- logger.debug(formattedJsonStr);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/com/win/bank/service/cmb/DeviceInfo.java b/src/main/java/com/win/bank/service/cmb/DeviceInfo.java
deleted file mode 100644
index fc25a66..0000000
--- a/src/main/java/com/win/bank/service/cmb/DeviceInfo.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.win.bank.service.cmb;
-
-import com.google.gson.JsonObject;
-
-/**
- * 设备信息
- */
-public class DeviceInfo {
-
- private String ipVal;
- private String macVal;
- private String cpuInfo;
- private String computerName;
- private String mainBoardId;
- private String mainBoardName;
-
- public DeviceInfo(String ipVal, String macVal, String cpuInfo, String computerName, String mainBoardId, String mainBoardName) {
- this.ipVal = ipVal;
- this.macVal = macVal;
- this.cpuInfo = cpuInfo;
- this.computerName = computerName;
- this.mainBoardId = mainBoardId;
- this.mainBoardName = mainBoardName;
- }
-
- public JsonObject toJson() {
- JsonObject deviceInfo = new JsonObject();
- if (ipVal != null) {
- deviceInfo.addProperty("ipType", ipVal.indexOf(':') != -1 ? "6" : "4");
- deviceInfo.addProperty("ipVal", ipVal);
- }
- deviceInfo.addProperty("macVal", macVal);
- deviceInfo.addProperty("cpuInfo", cpuInfo);
- deviceInfo.addProperty("cmpName", computerName);
- deviceInfo.addProperty("mbId", mainBoardId);
- deviceInfo.addProperty("mbMf", mainBoardName);
- return deviceInfo;
- }
-}
diff --git a/src/main/java/com/win/bank/utils/BaseBankServiceUtil.java b/src/main/java/com/win/bank/utils/BaseBankServiceUtil.java
new file mode 100644
index 0000000..dc58427
--- /dev/null
+++ b/src/main/java/com/win/bank/utils/BaseBankServiceUtil.java
@@ -0,0 +1,54 @@
+package com.win.bank.utils;
+
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.PostConstruct;
+
+import org.reflections.Reflections;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import com.win.bank.service.BaseBankService;
+
+@Component
+public class BaseBankServiceUtil implements ApplicationContextAware {
+
+ ApplicationContext context;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.context = applicationContext;
+ }
+
+ private static Map map = new HashMap<>();
+
+ public static BaseBankService get(String code) {
+ return map.get(code);
+ }
+
+ @PostConstruct
+ public void init() {
+ String packageName = "com.win.bank.service";
+ Reflections reflections = new Reflections(packageName);
+ Set> subTypes = reflections.getSubTypesOf(BaseBankService.class);
+
+ for (Class> clazz : subTypes) {
+ if (!Modifier.isAbstract(clazz.getModifiers()) && !clazz.isInterface()) {
+ String key = clazz.getPackageName().substring(clazz.getPackageName().lastIndexOf(".") + 1).toUpperCase();
+ BaseBankService instance = null;
+ try {
+ instance = (BaseBankService)context.getBean(Class.forName(clazz.getName()));
+ map.put(key, instance);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/win/bank/utils/JsonUtil.java b/src/main/java/com/win/bank/utils/JsonUtil.java
new file mode 100644
index 0000000..cb48eb6
--- /dev/null
+++ b/src/main/java/com/win/bank/utils/JsonUtil.java
@@ -0,0 +1,20 @@
+package com.win.bank.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+public class JsonUtil {
+
+ public static String formatJson(String jsonStr) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ Object json = mapper.readValue(jsonStr, Object.class);
+ ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter();
+ String prettyJson = '\n' + writer.writeValueAsString(json);
+ return prettyJson;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index f336f5b..51d47cc 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -31,3 +31,11 @@ logging:
level:
com.win: debug
org.springframework: warn
+
+###################### 以下是银行配置 ######################
+
+# 招商银行
+cmb:
+ uid: N002986522
+ busMod: 00002
+ url: http://192.168.0.142:8080/cdcserver/api/v2
\ No newline at end of file