SandPayService.java 32 KB

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