SandPayService.java 10 KB

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