SandPayService.java 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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.SandPayProperties;
  5. import com.izouma.nineth.domain.Order;
  6. import com.izouma.nineth.enums.OrderStatus;
  7. import com.izouma.nineth.exception.BusinessException;
  8. import com.izouma.nineth.repo.OrderRepo;
  9. import com.izouma.nineth.utils.DateTimeUtils;
  10. import lombok.AllArgsConstructor;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.commons.codec.binary.Base64;
  13. import org.apache.commons.lang.StringUtils;
  14. import org.springframework.cache.annotation.Cacheable;
  15. import org.springframework.stereotype.Service;
  16. import java.io.IOException;
  17. import java.math.BigDecimal;
  18. import java.net.URLDecoder;
  19. import java.nio.charset.StandardCharsets;
  20. import java.text.DecimalFormat;
  21. import java.text.DecimalFormatSymbols;
  22. import java.text.SimpleDateFormat;
  23. import java.time.LocalDateTime;
  24. import java.util.Date;
  25. import java.util.HashMap;
  26. import java.util.Locale;
  27. import java.util.Map;
  28. @Service
  29. @AllArgsConstructor
  30. @Slf4j
  31. public class SandPayService {
  32. private final OrderRepo orderRepo;
  33. private final SandPayProperties sandPayProperties;
  34. public JSONObject requestServer(JSONObject header, JSONObject body, String reqAddr) {
  35. Map<String, String> reqMap = new HashMap<String, String>();
  36. JSONObject reqJson = new JSONObject();
  37. reqJson.put("head", header);
  38. reqJson.put("body", body);
  39. String reqStr = reqJson.toJSONString();
  40. String reqSign;
  41. // 签名
  42. try {
  43. reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(StandardCharsets.UTF_8), CertUtil.getPrivateKey(), "SHA1WithRSA")));
  44. } catch (Exception e) {
  45. log.error(e.getMessage());
  46. return null;
  47. }
  48. //整体报文格式
  49. reqMap.put("charset", "UTF-8");
  50. reqMap.put("data", reqStr);
  51. reqMap.put("signType", "01");
  52. reqMap.put("sign", reqSign);
  53. reqMap.put("extend", "");
  54. String result;
  55. try {
  56. log.info("请求报文:\n" + JSONObject.toJSONString(reqJson, true));
  57. result = HttpClient.doPost(reqAddr, reqMap, 30000, 30000);
  58. result = URLDecoder.decode(result, StandardCharsets.UTF_8);
  59. } catch (IOException e) {
  60. log.error(e.getMessage());
  61. return null;
  62. }
  63. Map<String, String> respMap = SDKUtil.convertResultStringToMap(result);
  64. String respData = respMap.get("data");
  65. String respSign = respMap.get("sign");
  66. // 验证签名
  67. boolean valid;
  68. try {
  69. valid = CryptoUtil.verifyDigitalSign(respData.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA");
  70. if (!valid) {
  71. log.error("verify sign fail.");
  72. return null;
  73. }
  74. log.info("verify sign success");
  75. JSONObject respJson = JSONObject.parseObject(respData);
  76. if (respJson != null) {
  77. log.info("响应码:[" + respJson.getJSONObject("head").getString("respCode") + "]");
  78. log.info("响应描述:[" + respJson.getJSONObject("head").getString("respMsg") + "]");
  79. log.info("响应报文:\n" + JSONObject.toJSONString(respJson, true));
  80. } else {
  81. log.error("服务器请求异常!!!");
  82. }
  83. return respJson;
  84. } catch (Exception e) {
  85. log.error(e.getMessage());
  86. return null;
  87. }
  88. }
  89. public JSONObject requestAlipay(String orderId, BigDecimal amount, String subject, String desc,
  90. LocalDateTime timeout, String extend) {
  91. JSONObject header = new JSONObject();
  92. header.put("version", "1.0"); //版本号
  93. header.put("method", "sandpay.trade.precreate"); //接口名称:统一下单并支付
  94. header.put("productId", "00000006"); //产品编码
  95. header.put("mid", sandPayProperties.getMid()); //商户号
  96. header.put("accessType", "1"); //接入类型设置为普通商户接入
  97. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  98. header.put("reqTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); //请求时间
  99. DecimalFormat df = new DecimalFormat("000000000000", DecimalFormatSymbols.getInstance(Locale.US));
  100. JSONObject body = new JSONObject();
  101. body.put("payTool", "0401"); //支付工具: 固定填写0401
  102. body.put("orderCode", orderId); //商户订单号
  103. body.put("totalAmount", df.format(amount.multiply(new BigDecimal("100")))); //订单金额 12位长度,精确到分
  104. //body.put("limitPay", "5"); //限定支付方式 送1-限定不能使用贷记卡 送4-限定不能使用花呗 送5-限定不能使用贷记卡+花呗
  105. body.put("subject", subject); //订单标题
  106. body.put("body", desc); //订单描述
  107. body.put("txnTimeOut", DateTimeUtils.format(timeout, "yyyyMMddHHmmss")); //订单超时时间
  108. body.put("notifyUrl", sandPayProperties.getNotifyUrl()); //异步通知地址
  109. body.put("bizExtendParams", ""); //业务扩展参数
  110. body.put("merchExtendParams", ""); //商户扩展参数
  111. body.put("extend", extend); //扩展域
  112. return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/create");
  113. }
  114. public JSONObject query(String orderId) {
  115. JSONObject header = new JSONObject();
  116. header.put("version", "1.0"); //版本号
  117. header.put("method", "sandpay.trade.query"); //接口名称:订单查询
  118. header.put("productId", "00000006"); //产品编码
  119. header.put("mid", sandPayProperties.getMid()); //商户号
  120. header.put("accessType", "1"); //接入类型设置为普通商户接入
  121. header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端
  122. header.put("reqTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); //请求时间
  123. JSONObject body = new JSONObject();
  124. body.put("orderCode", orderId);
  125. body.put("extend", ""); //扩展域
  126. return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/query");
  127. }
  128. @Cacheable(value = "sandPay", key = "#orderId")
  129. public String payOrder(Long orderId) {
  130. Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
  131. if (order.getStatus() != OrderStatus.NOT_PAID) {
  132. throw new BusinessException("订单状态错误");
  133. }
  134. JSONObject extend = new JSONObject();
  135. extend.put("type", "order");
  136. extend.put("id", orderId);
  137. JSONObject res = requestAlipay(orderId.toString(), order.getTotalPrice(), order.getName(), order.getName(),
  138. order.getCreatedAt().plusMinutes(3), extend.toJSONString());
  139. if (res == null)
  140. throw new BusinessException("下单失败,请稍后再试");
  141. return res.getJSONObject("body").getString("qrCode");
  142. }
  143. }