SandPayService.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. package com.izouma.nineth.service;
  2. import cn.com.sandpay.cashier.sdk.*;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.izouma.nineth.config.GeneralProperties;
  5. import com.izouma.nineth.config.SandPayProperties;
  6. import com.izouma.nineth.domain.GiftOrder;
  7. import com.izouma.nineth.domain.MintOrder;
  8. import com.izouma.nineth.domain.Order;
  9. import com.izouma.nineth.enums.MintOrderStatus;
  10. import com.izouma.nineth.enums.OrderStatus;
  11. import com.izouma.nineth.exception.BusinessException;
  12. import com.izouma.nineth.repo.GiftOrderRepo;
  13. import com.izouma.nineth.repo.MintOrderRepo;
  14. import com.izouma.nineth.repo.OrderRepo;
  15. import com.izouma.nineth.utils.DateTimeUtils;
  16. import com.izouma.nineth.utils.SnowflakeIdWorker;
  17. import lombok.AllArgsConstructor;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.apache.commons.codec.binary.Base64;
  20. import org.springframework.cache.annotation.Cacheable;
  21. import org.springframework.stereotype.Service;
  22. import java.io.IOException;
  23. import java.math.BigDecimal;
  24. import java.net.URLDecoder;
  25. import java.nio.charset.StandardCharsets;
  26. import java.text.DecimalFormat;
  27. import java.text.DecimalFormatSymbols;
  28. import java.time.LocalDateTime;
  29. import java.util.HashMap;
  30. import java.util.Locale;
  31. import java.util.Map;
  32. @Service
  33. @AllArgsConstructor
  34. @Slf4j
  35. public class SandPayService {
  36. private final OrderRepo orderRepo;
  37. private final GiftOrderRepo giftOrderRepo;
  38. private final SandPayProperties sandPayProperties;
  39. private final MintOrderRepo mintOrderRepo;
  40. private final SnowflakeIdWorker snowflakeIdWorker;
  41. private final GeneralProperties generalProperties;
  42. public String getReqTime() {
  43. return DateTimeUtils.format(LocalDateTime.now(), "yyyyMMddHHmmss");
  44. }
  45. public String getTimeout(int seconds) {
  46. return DateTimeUtils.format(LocalDateTime.now().plusSeconds(seconds), "yyyyMMddHHmmss");
  47. }
  48. public String convertAmount(BigDecimal amount) {
  49. DecimalFormat df = new DecimalFormat("000000000000", DecimalFormatSymbols.getInstance(Locale.US));
  50. return df.format(amount.multiply(new BigDecimal("100")));
  51. }
  52. public JSONObject requestServer(JSONObject header, JSONObject body, String reqAddr) {
  53. Map<String, String> reqMap = new HashMap<String, String>();
  54. JSONObject reqJson = new JSONObject();
  55. reqJson.put("head", header);
  56. reqJson.put("body", body);
  57. String reqStr = reqJson.toJSONString();
  58. String reqSign;
  59. // 签名
  60. try {
  61. reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(StandardCharsets.UTF_8),
  62. CertUtil.getPrivateKey(), "SHA1WithRSA")));
  63. } catch (Exception e) {
  64. log.error(e.getMessage());
  65. return null;
  66. }
  67. //整体报文格式
  68. reqMap.put("charset", "UTF-8");
  69. reqMap.put("data", reqStr);
  70. reqMap.put("signType", "01");
  71. reqMap.put("sign", reqSign);
  72. reqMap.put("extend", "");
  73. String result;
  74. try {
  75. log.info("请求报文:\n{}", JSONObject.toJSONString(reqJson, true));
  76. result = HttpClient.doPost(reqAddr, reqMap, 30000, 30000);
  77. result = URLDecoder.decode(result, StandardCharsets.UTF_8);
  78. } catch (IOException e) {
  79. log.error(e.getMessage());
  80. return null;
  81. }
  82. Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
  83. String respData = respMap.get("data");
  84. String respSign = respMap.get("sign");
  85. // 验证签名
  86. boolean valid;
  87. try {
  88. valid = CryptoUtil.verifyDigitalSign(respData.getBytes(StandardCharsets.UTF_8),
  89. Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
  90. if (!valid) {
  91. log.error("verify sign fail.");
  92. return null;
  93. }
  94. log.info("verify sign success");
  95. JSONObject respJson = JSONObject.parseObject(respData);
  96. if (respJson != null) {
  97. log.info("响应码:[{}]", respJson.getJSONObject("head").getString("respCode"));
  98. log.info("响应描述:[{}]", respJson.getJSONObject("head").getString("respMsg"));
  99. log.info("响应报文:\n{}", JSONObject.toJSONString(respJson, true));
  100. } else {
  101. log.error("服务器请求异常!!!");
  102. }
  103. return respJson;
  104. } catch (Exception e) {
  105. log.error(e.getMessage());
  106. return null;
  107. }
  108. }
  109. public JSONObject requestAlipay(String orderId, BigDecimal amount, String subject, String desc,
  110. int timeout, String extend) {
  111. if (orderId.length() < 12) {
  112. for (int i = orderId.length(); i < 12; i++) {
  113. orderId = "0" + orderId;
  114. }
  115. }
  116. JSONObject header = new JSONObject();
  117. header.put("version", "1.0"); //版本号
  118. header.put("method", "sandpay.trade.precreate"); //接口名称:统一下单并支付
  119. header.put("productId", "00000006"); //产品编码
  120. header.put("mid", sandPayProperties.getMid()); //商户号
  121. header.put("accessType", "1"); //接入类型设置为普通商户接入
  122. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  123. header.put("reqTime", getReqTime()); //请求时间
  124. JSONObject body = new JSONObject();
  125. body.put("payTool", "0401"); //支付工具: 固定填写0401
  126. body.put("orderCode", orderId); //商户订单号
  127. body.put("totalAmount", convertAmount(amount)); //订单金额 12位长度,精确到分
  128. //body.put("limitPay", "5"); //限定支付方式 送1-限定不能使用贷记卡 送4-限定不能使用花呗 送5-限定不能使用贷记卡+花呗
  129. body.put("subject", subject); //订单标题
  130. body.put("body", desc); //订单描述
  131. body.put("txnTimeOut", getTimeout(timeout)); //订单超时时间
  132. body.put("notifyUrl", sandPayProperties.getNotifyUrl()); //异步通知地址
  133. body.put("bizExtendParams", ""); //业务扩展参数
  134. body.put("merchExtendParams", ""); //商户扩展参数
  135. body.put("extend", extend); //扩展域
  136. return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/create");
  137. }
  138. public JSONObject requestQuick(String orderId, BigDecimal amount, String subject, String desc,
  139. int timeout, String extend, String frontUrl) {
  140. if (orderId.length() < 12) {
  141. for (int i = orderId.length(); i < 12; i++) {
  142. orderId = "0" + orderId;
  143. }
  144. }
  145. JSONObject header = new JSONObject();
  146. header.put("version", "1.0"); //版本号
  147. header.put("method", "sandpay.trade.pay"); //接口名称:统一下单
  148. header.put("mid", sandPayProperties.getMid()); //商户号
  149. header.put("accessType", "1"); //接入类型设置为平台商户接入 //接入类型设置为普通商户接入
  150. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  151. header.put("reqTime", getReqTime()); //请求时间
  152. header.put("productId", "00000008"); //产品编码
  153. JSONObject body = new JSONObject();
  154. body.put("orderCode", orderId); //商户订单号
  155. body.put("totalAmount", convertAmount(amount)); //订单金额
  156. body.put("subject", subject); //订单标题
  157. body.put("body", desc); //订单描述
  158. body.put("txnTimeOut", getTimeout(timeout)); //订单超时时间
  159. body.put("clientIp", "192.168.22.55"); //客户端IP
  160. body.put("limitPay", ""); //限定支付方式 送1-限定不能使用贷记卡送 4-限定不能使用花呗 送5-限定不能使用贷记卡+花呗
  161. body.put("notifyUrl", sandPayProperties.getNotifyUrl()); //异步通知地址
  162. body.put("frontUrl", frontUrl); //前台通知地址
  163. body.put("storeId", ""); //商户门店编号
  164. body.put("terminalId", ""); //商户终端编号
  165. body.put("operatorId", ""); //操作员编号
  166. body.put("clearCycle", ""); //清算模式
  167. body.put("royaltyInfo", ""); //分账信息
  168. body.put("riskRateInfo", ""); //风控信息域
  169. body.put("bizExtendParams", ""); //业务扩展参数
  170. body.put("merchExtendParams", ""); //商户扩展参数
  171. body.put("extend", extend); //扩展域
  172. body.put("payMode", "sand_h5"); //支付模式
  173. return requestServer(header, body, "https://cashier.sandpay.com.cn/gateway/api/order/pay");
  174. }
  175. public JSONObject query(String orderId) {
  176. JSONObject header = new JSONObject();
  177. header.put("version", "1.0"); //版本号
  178. header.put("method", "sandpay.trade.query"); //接口名称:订单查询
  179. header.put("productId", "00000006"); //产品编码
  180. header.put("mid", sandPayProperties.getMid()); //商户号
  181. header.put("accessType", "1"); //接入类型设置为普通商户接入
  182. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  183. header.put("reqTime", getReqTime()); //请求时间
  184. JSONObject body = new JSONObject();
  185. body.put("orderCode", orderId);
  186. body.put("extend", ""); //扩展域
  187. return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/query");
  188. }
  189. public JSONObject refund(String orderId, BigDecimal amount) {
  190. JSONObject header = new JSONObject();
  191. header.put("version", "1.0"); //版本号
  192. header.put("method", "sandpay.trade.refund"); //接口名称:退货
  193. header.put("productId", "00000006"); //产品编码
  194. header.put("mid", sandPayProperties.getMid()); //商户号
  195. header.put("accessType", "1"); //接入类型设置为普通商户接入
  196. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  197. header.put("reqTime", getReqTime()); //请求时间
  198. JSONObject body = new JSONObject();
  199. body.put("orderCode", snowflakeIdWorker.nextId()); //商户订单号
  200. body.put("oriOrderCode", orderId); //原交易订单号
  201. body.put("refundAmount", convertAmount(amount)); //退货金额
  202. body.put("refundReason", "退货测试"); //退货原因
  203. body.put("notifyUrl", sandPayProperties.getNotifyUrl()); //异步通知地址
  204. body.put("extend", "");
  205. return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/refund");
  206. }
  207. @Cacheable(value = "sandPay", key = "#orderId")
  208. public String payOrder(Long orderId) {
  209. Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  210. if (order.getStatus() != OrderStatus.NOT_PAID) {
  211. throw new BusinessException("订单状态错误");
  212. }
  213. JSONObject extend = new JSONObject();
  214. extend.put("type", "order");
  215. extend.put("id", orderId);
  216. JSONObject res = requestAlipay(orderId.toString(), order.getTotalPrice(), order.getName(), order.getName(),
  217. 180, extend.toJSONString());
  218. if (res == null)
  219. throw new BusinessException("下单失败,请稍后再试");
  220. if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) {
  221. String msg = res.getJSONObject("head").getString("respMsg");
  222. if (msg.contains("超限")) {
  223. throw new BusinessException("超过商户单日额度");
  224. }
  225. if (msg.contains("商户状态")) {
  226. throw new BusinessException("超过商户单日额度");
  227. }
  228. throw new BusinessException(msg);
  229. }
  230. return res.getJSONObject("body").getString("qrCode");
  231. }
  232. @Cacheable(value = "sandPayQuick", key = "#orderId")
  233. public String payOrderQuick(Long orderId) {
  234. Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  235. if (order.getStatus() != OrderStatus.NOT_PAID) {
  236. throw new BusinessException("订单状态错误");
  237. }
  238. JSONObject extend = new JSONObject();
  239. extend.put("type", "order");
  240. extend.put("id", orderId);
  241. JSONObject res = requestQuick(orderId.toString(), order.getTotalPrice(), order.getName(), order.getName(),
  242. 180, extend.toJSONString(), generalProperties.getHost() + "/9th/orderDetail?id=" + orderId);
  243. if (res == null)
  244. throw new BusinessException("下单失败,请稍后再试");
  245. if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) {
  246. String msg = res.getJSONObject("head").getString("respMsg");
  247. if (msg.contains("超限")) {
  248. throw new BusinessException("超过商户单日额度");
  249. }
  250. if (msg.contains("商户状态")) {
  251. throw new BusinessException("超过商户单日额度");
  252. }
  253. throw new BusinessException(msg);
  254. }
  255. return res.getJSONObject("body").getString("credential");
  256. }
  257. @Cacheable(value = "sandPay", key = "#orderId")
  258. public String payGiftOrder(Long orderId) {
  259. GiftOrder order = giftOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  260. if (order.getStatus() != OrderStatus.NOT_PAID) {
  261. throw new BusinessException("订单状态错误");
  262. }
  263. JSONObject extend = new JSONObject();
  264. extend.put("type", "gift");
  265. extend.put("id", orderId);
  266. JSONObject res = requestAlipay(orderId.toString(), order.getGasPrice(), "转增" + order.getAssetId(), "转增" + order.getAssetId(),
  267. 180, extend.toJSONString());
  268. if (res == null)
  269. throw new BusinessException("下单失败,请稍后再试");
  270. if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) {
  271. String msg = res.getJSONObject("head").getString("respMsg");
  272. if (msg.contains("超限")) {
  273. throw new BusinessException("超过商户单日额度");
  274. }
  275. if (msg.contains("商户状态")) {
  276. throw new BusinessException("超过商户单日额度");
  277. }
  278. throw new BusinessException(msg);
  279. }
  280. return res.getJSONObject("body").getString("qrCode");
  281. }
  282. @Cacheable(value = "sandPay", key = "#orderId")
  283. public String payMintOrder(Long orderId) {
  284. MintOrder order = mintOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  285. if (order.getStatus() != MintOrderStatus.NOT_PAID) {
  286. throw new BusinessException("订单状态错误");
  287. }
  288. JSONObject extend = new JSONObject();
  289. extend.put("type", "mintOrder");
  290. extend.put("id", orderId);
  291. JSONObject res = requestAlipay(orderId.toString(), order.getGasPrice(), "铸造活动:" + order.getMintActivityId(),
  292. "铸造活动:" + order.getMintActivityId(), 180, extend.toJSONString());
  293. if (res == null)
  294. throw new BusinessException("下单失败,请稍后再试");
  295. if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) {
  296. String msg = res.getJSONObject("head").getString("respMsg");
  297. if (msg.contains("超限")) {
  298. throw new BusinessException("超过商户单日额度");
  299. }
  300. if (msg.contains("商户状态")) {
  301. throw new BusinessException("超过商户单日额度");
  302. }
  303. throw new BusinessException(msg);
  304. }
  305. return res.getJSONObject("body").getString("qrCode");
  306. }
  307. public JSONObject transfer(String id, String name, String bank, BigDecimal amount) {
  308. JSONObject request = new JSONObject();
  309. DecimalFormat df = new DecimalFormat("000000000000", DecimalFormatSymbols.getInstance(Locale.US));
  310. request.put("version", "01"); //版本号
  311. request.put("productId", "00000004"); //产品ID
  312. request.put("tranTime", getReqTime()); //交易时间
  313. request.put("orderCode", id); //订单号
  314. request.put("timeOut", getTimeout(180)); //订单超时时间
  315. request.put("tranAmt", df.format(amount.multiply(new BigDecimal("100")))); //金额
  316. request.put("currencyCode", "156"); //币种
  317. request.put("accAttr", "0"); //账户属性 0-对私 1-对公
  318. request.put("accType", "4"); //账号类型 3-公司账户 4-银行卡
  319. request.put("accNo", bank); //收款人账户号
  320. request.put("accName", name); //收款人账户名
  321. request.put("provNo", ""); //收款人开户省份编码
  322. request.put("cityNo", ""); //收款人开会城市编码
  323. request.put("bankName", ""); //收款账户开户行名称
  324. request.put("bankType", ""); //收款人账户联行号
  325. request.put("remark", "消费"); //摘要
  326. request.put("payMode", ""); //付款模式
  327. request.put("channelType", ""); //渠道类型
  328. request.put("extendParams", ""); //业务扩展参数
  329. request.put("reqReserved", ""); //请求方保留域
  330. request.put("extend", ""); //扩展域
  331. request.put("phone", ""); //手机号
  332. String reqData = request.toJSONString();
  333. log.info("请求数据:{}", reqData);
  334. try {
  335. String aesKey = RandomStringGenerator.getRandomStringByLength(16);
  336. byte[] aesKeyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
  337. byte[] plainBytes = reqData.getBytes(StandardCharsets.UTF_8);
  338. String encryptData = new String(Base64.encodeBase64(
  339. CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
  340. "AES/ECB/PKCS5Padding", null)), StandardCharsets.UTF_8);
  341. String sign = new String(Base64.encodeBase64(
  342. CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
  343. "SHA1WithRSA")), StandardCharsets.UTF_8);
  344. String encryptKey = new String(Base64.encodeBase64(
  345. CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
  346. "RSA/ECB/PKCS1Padding")), StandardCharsets.UTF_8);
  347. Map<String, String> reqMap = new HashMap<String, String>();
  348. //整体报文格式
  349. reqMap.put("transCode", "RTPM"); // 交易码
  350. reqMap.put("accessType", "0"); // 接入类型
  351. reqMap.put("merId", sandPayProperties.getMid()); // 合作商户ID 杉德系统分配,唯一标识
  352. reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
  353. reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
  354. reqMap.put("sign", sign); // 签名
  355. reqMap.put("extend", ""); // 扩展域
  356. String result;
  357. try {
  358. log.info("请求报文:{}", reqMap);
  359. result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/agentpay",
  360. reqMap, 300000, 300000);
  361. result = URLDecoder.decode(result, StandardCharsets.UTF_8);
  362. } catch (IOException e) {
  363. log.error(e.getMessage());
  364. return null;
  365. }
  366. log.info("响应报文:{}", result);
  367. Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);
  368. String retEncryptKey = responseMap.get("encryptKey");
  369. String retEncryptData = responseMap.get("encryptData");
  370. String retSign = responseMap.get("sign");
  371. log.debug("retEncryptKey:[{}]", retEncryptKey);
  372. log.debug("retEncryptData:[{}]", retEncryptData);
  373. log.debug("retSign:[{}]", retSign);
  374. byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
  375. .getBytes(StandardCharsets.UTF_8));
  376. byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
  377. decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
  378. "RSA/ECB/PKCS1Padding");
  379. byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData.getBytes(StandardCharsets.UTF_8));
  380. byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
  381. merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);
  382. String respData = new String(respDataBytes, StandardCharsets.UTF_8);
  383. log.info("retData:[" + respData + "]");
  384. System.out.println("响应data数据:" + respData);
  385. byte[] signBytes = Base64.decodeBase64(retSign.getBytes(StandardCharsets.UTF_8));
  386. boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
  387. CertUtil.getPublicKey(), "SHA1WithRSA");
  388. if (!isValid) {
  389. log.error("verify sign fail.");
  390. return null;
  391. }
  392. log.info("verify sign success");
  393. System.out.println("verify sign success");
  394. JSONObject respJson = JSONObject.parseObject(respData);
  395. return respJson;
  396. } catch (Exception e) {
  397. log.error(e.getMessage());
  398. return null;
  399. }
  400. }
  401. public JSONObject queryTransfer(String tranTime, String orderId) {
  402. JSONObject request = new JSONObject();
  403. request.put("version", "01"); // 版本号
  404. request.put("productId", "00000004"); // 产品ID
  405. request.put("tranTime", tranTime); // 查询订单的交易时间
  406. request.put("orderCode", orderId); // 要查询的订单号
  407. String reqData = request.toJSONString();
  408. log.info("请求数据:{}", reqData);
  409. try {
  410. String aesKey = RandomStringGenerator.getRandomStringByLength(16);
  411. byte[] aesKeyBytes = aesKey.getBytes(StandardCharsets.UTF_8);
  412. byte[] plainBytes = reqData.getBytes(StandardCharsets.UTF_8);
  413. String encryptData = new String(Base64.encodeBase64(
  414. CryptoUtil.AESEncrypt(plainBytes, aesKeyBytes, "AES",
  415. "AES/ECB/PKCS5Padding", null)), StandardCharsets.UTF_8);
  416. String sign = new String(Base64.encodeBase64(
  417. CryptoUtil.digitalSign(plainBytes, CertUtil.getPrivateKey(),
  418. "SHA1WithRSA")), StandardCharsets.UTF_8);
  419. String encryptKey = new String(Base64.encodeBase64(
  420. CryptoUtil.RSAEncrypt(aesKeyBytes, CertUtil.getPublicKey(), 2048, 11,
  421. "RSA/ECB/PKCS1Padding")), StandardCharsets.UTF_8);
  422. Map<String, String> reqMap = new HashMap<String, String>();
  423. //整体报文格式
  424. reqMap.put("transCode", "RTPM"); // 交易码
  425. reqMap.put("accessType", "0"); // 接入类型
  426. reqMap.put("merId", sandPayProperties.getMid()); // 合作商户ID 杉德系统分配,唯一标识
  427. reqMap.put("encryptKey", encryptKey); // 加密后的AES秘钥
  428. reqMap.put("encryptData", encryptData); // 加密后的请求/应答报文
  429. reqMap.put("sign", sign); // 签名
  430. reqMap.put("extend", ""); // 扩展域
  431. String result;
  432. try {
  433. log.info("请求报文:{}", reqMap);
  434. result = HttpClient.doPost("https://caspay.sandpay.com.cn/agent-main/openapi/queryOrder",
  435. reqMap, 300000, 300000);
  436. result = URLDecoder.decode(result, StandardCharsets.UTF_8);
  437. } catch (IOException e) {
  438. log.error(e.getMessage());
  439. return null;
  440. }
  441. log.info("响应报文:{}", result);
  442. Map<String, String> responseMap = SDKUtil.convertResultStringToMap(result);
  443. String retEncryptKey = responseMap.get("encryptKey");
  444. String retEncryptData = responseMap.get("encryptData");
  445. String retSign = responseMap.get("sign");
  446. log.debug("retEncryptKey:[{}]", retEncryptKey);
  447. log.debug("retEncryptData:[{}]", retEncryptData);
  448. log.debug("retSign:[{}]", retSign);
  449. byte[] decodeBase64KeyBytes = Base64.decodeBase64(retEncryptKey
  450. .getBytes(StandardCharsets.UTF_8));
  451. byte[] merchantAESKeyBytes = CryptoUtil.RSADecrypt(
  452. decodeBase64KeyBytes, CertUtil.getPrivateKey(), 2048, 11,
  453. "RSA/ECB/PKCS1Padding");
  454. byte[] decodeBase64DataBytes = Base64.decodeBase64(retEncryptData.getBytes(StandardCharsets.UTF_8));
  455. byte[] respDataBytes = CryptoUtil.AESDecrypt(decodeBase64DataBytes,
  456. merchantAESKeyBytes, "AES", "AES/ECB/PKCS5Padding", null);
  457. String respData = new String(respDataBytes, StandardCharsets.UTF_8);
  458. log.info("retData:[" + respData + "]");
  459. System.out.println("响应data数据:" + respData);
  460. byte[] signBytes = Base64.decodeBase64(retSign.getBytes(StandardCharsets.UTF_8));
  461. boolean isValid = CryptoUtil.verifyDigitalSign(respDataBytes, signBytes,
  462. CertUtil.getPublicKey(), "SHA1WithRSA");
  463. if (!isValid) {
  464. log.error("verify sign fail.");
  465. return null;
  466. }
  467. log.info("verify sign success");
  468. System.out.println("verify sign success");
  469. JSONObject respJson = JSONObject.parseObject(respData);
  470. return respJson;
  471. } catch (Exception e) {
  472. log.error(e.getMessage());
  473. return null;
  474. }
  475. }
  476. }