package com.izouma.nineth.service; import cn.com.sandpay.cashier.sdk.*; import com.alibaba.fastjson.JSONObject; import com.izouma.nineth.config.SandPayProperties; import com.izouma.nineth.domain.GiftOrder; import com.izouma.nineth.domain.MintOrder; import com.izouma.nineth.domain.Order; import com.izouma.nineth.enums.MintOrderStatus; import com.izouma.nineth.enums.OrderStatus; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.repo.GiftOrderRepo; import com.izouma.nineth.repo.MintOrderRepo; import com.izouma.nineth.repo.OrderRepo; import com.izouma.nineth.utils.DateTimeUtils; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.io.IOException; import java.math.BigDecimal; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; @Service @AllArgsConstructor @Slf4j public class SandPayService { private final OrderRepo orderRepo; private final GiftOrderRepo giftOrderRepo; private final SandPayProperties sandPayProperties; private final MintOrderRepo mintOrderRepo; public JSONObject requestServer(JSONObject header, JSONObject body, String reqAddr) { Map reqMap = new HashMap(); JSONObject reqJson = new JSONObject(); reqJson.put("head", header); reqJson.put("body", body); String reqStr = reqJson.toJSONString(); String reqSign; // 签名 try { reqSign = new String(Base64.encodeBase64(CryptoUtil.digitalSign(reqStr.getBytes(StandardCharsets.UTF_8), CertUtil.getPrivateKey(), "SHA1WithRSA"))); } catch (Exception e) { log.error(e.getMessage()); return null; } //整体报文格式 reqMap.put("charset", "UTF-8"); reqMap.put("data", reqStr); reqMap.put("signType", "01"); reqMap.put("sign", reqSign); reqMap.put("extend", ""); String result; try { log.info("请求报文:\n" + JSONObject.toJSONString(reqJson, true)); result = HttpClient.doPost(reqAddr, reqMap, 30000, 30000); result = URLDecoder.decode(result, StandardCharsets.UTF_8); } catch (IOException e) { log.error(e.getMessage()); return null; } Map respMap = SDKUtil.convertResultStringToMap(result); String respData = respMap.get("data"); String respSign = respMap.get("sign"); // 验证签名 boolean valid; try { valid = CryptoUtil.verifyDigitalSign(respData.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(respSign), CertUtil.getPublicKey(), "SHA1WithRSA"); if (!valid) { log.error("verify sign fail."); return null; } log.info("verify sign success"); JSONObject respJson = JSONObject.parseObject(respData); if (respJson != null) { log.info("响应码:[" + respJson.getJSONObject("head").getString("respCode") + "]"); log.info("响应描述:[" + respJson.getJSONObject("head").getString("respMsg") + "]"); log.info("响应报文:\n" + JSONObject.toJSONString(respJson, true)); } else { log.error("服务器请求异常!!!"); } return respJson; } catch (Exception e) { log.error(e.getMessage()); return null; } } public JSONObject requestAlipay(String orderId, BigDecimal amount, String subject, String desc, LocalDateTime timeout, String extend) { if (orderId.length() < 12) { for (int i = orderId.length(); i < 12; i++) { orderId = "0" + orderId; } } JSONObject header = new JSONObject(); header.put("version", "1.0"); //版本号 header.put("method", "sandpay.trade.precreate"); //接口名称:统一下单并支付 header.put("productId", "00000006"); //产品编码 header.put("mid", sandPayProperties.getMid()); //商户号 header.put("accessType", "1"); //接入类型设置为普通商户接入 header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端 header.put("reqTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); //请求时间 DecimalFormat df = new DecimalFormat("000000000000", DecimalFormatSymbols.getInstance(Locale.US)); JSONObject body = new JSONObject(); body.put("payTool", "0401"); //支付工具: 固定填写0401 body.put("orderCode", orderId); //商户订单号 body.put("totalAmount", df.format(amount.multiply(new BigDecimal("100")))); //订单金额 12位长度,精确到分 //body.put("limitPay", "5"); //限定支付方式 送1-限定不能使用贷记卡 送4-限定不能使用花呗 送5-限定不能使用贷记卡+花呗 body.put("subject", subject); //订单标题 body.put("body", desc); //订单描述 body.put("txnTimeOut", DateTimeUtils.format(timeout, "yyyyMMddHHmmss")); //订单超时时间 body.put("notifyUrl", sandPayProperties.getNotifyUrl()); //异步通知地址 body.put("bizExtendParams", ""); //业务扩展参数 body.put("merchExtendParams", ""); //商户扩展参数 body.put("extend", extend); //扩展域 return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/create"); } public JSONObject query(String orderId) { JSONObject header = new JSONObject(); header.put("version", "1.0"); //版本号 header.put("method", "sandpay.trade.query"); //接口名称:订单查询 header.put("productId", "00000006"); //产品编码 header.put("mid", sandPayProperties.getMid()); //商户号 header.put("accessType", "1"); //接入类型设置为普通商户接入 header.put("channelType", "07"); //渠道类型:07-互联网 08-移动端 header.put("reqTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); //请求时间 JSONObject body = new JSONObject(); body.put("orderCode", orderId); body.put("extend", ""); //扩展域 return requestServer(header, body, "https://cashier.sandpay.com.cn/qr/api/order/query"); } @Cacheable(value = "sandPay", key = "#orderId") public String payOrder(Long orderId) { Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在")); if (order.getStatus() != OrderStatus.NOT_PAID) { throw new BusinessException("订单状态错误"); } JSONObject extend = new JSONObject(); extend.put("type", "order"); extend.put("id", orderId); JSONObject res = requestAlipay(orderId.toString(), order.getTotalPrice(), order.getName(), order.getName(), order.getCreatedAt().plusMinutes(3), extend.toJSONString()); if (res == null) throw new BusinessException("下单失败,请稍后再试"); if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) { String msg = res.getJSONObject("head").getString("respMsg"); if (msg.contains("超限")) { throw new BusinessException("超过商户单日额度"); } throw new BusinessException(msg); } return res.getJSONObject("body").getString("qrCode"); } @Cacheable(value = "sandPay", key = "#orderId") public String payGiftOrder(Long orderId) { GiftOrder order = giftOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在")); if (order.getStatus() != OrderStatus.NOT_PAID) { throw new BusinessException("订单状态错误"); } JSONObject extend = new JSONObject(); extend.put("type", "gift"); extend.put("id", orderId); JSONObject res = requestAlipay(orderId.toString(), order.getGasPrice(), "转增" + order.getAssetId(), "转增" + order.getAssetId(), order.getCreatedAt().plusMinutes(3), extend.toJSONString()); if (res == null) throw new BusinessException("下单失败,请稍后再试"); if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) { String msg = res.getJSONObject("head").getString("respMsg"); if (msg.contains("超限")) { throw new BusinessException("超过商户单日额度"); } throw new BusinessException(msg); } return res.getJSONObject("body").getString("qrCode"); } @Cacheable(value = "sandPay", key = "#orderId") public String payMintOrder(Long orderId) { MintOrder order = mintOrderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在")); if (order.getStatus() != MintOrderStatus.NOT_PAID) { throw new BusinessException("订单状态错误"); } JSONObject extend = new JSONObject(); extend.put("type", "mintOrder"); extend.put("id", orderId); JSONObject res = requestAlipay(orderId.toString(), order.getGasPrice(), "铸造活动:" + order.getMintActivityId(), "铸造活动:" + order.getMintActivityId(), order.getCreatedAt().plusMinutes(3), extend.toJSONString()); if (res == null) throw new BusinessException("下单失败,请稍后再试"); if (!"000000".equals(res.getJSONObject("head").getString("respCode"))) { String msg = res.getJSONObject("head").getString("respMsg"); if (msg.contains("超限")) { throw new BusinessException("超过商户单日额度"); } throw new BusinessException(msg); } return res.getJSONObject("body").getString("qrCode"); } }