SandPayService.java 31 KB

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