IWxPayService.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. package beilv.wx.pay.service;
  2. import beilv.carinformation.mapper.CarInformationMapper;
  3. import beilv.common.core.domain.AjaxResult;
  4. import beilv.competition.mapper.CompetitionMapper;
  5. import beilv.order.domain.StoreOrder;
  6. import beilv.order.domain.StoreRefund;
  7. import beilv.order.mapper.StoreOrderMapper;
  8. import beilv.order.mapper.StoreRefundMapper;
  9. import beilv.system.domain.SysMember;
  10. import beilv.system.service.ISysMemberService;
  11. import beilv.vipCardLog.domain.VipCardLog;
  12. import beilv.vipCardLog.service.IVipCardLogService;
  13. import beilv.wx.pay.config.WxPayProperties;
  14. import beilv.wx.pay.domain.vo.AppPayParam;
  15. import beilv.wx.pay.domain.vo.AppRefundParam;
  16. import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
  17. import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Response;
  18. import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
  19. import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
  20. import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
  21. import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
  22. import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
  23. import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result.JsapiResult;
  24. import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
  25. import com.github.binarywang.wxpay.constant.WxPayConstants;
  26. import com.github.binarywang.wxpay.exception.WxPayException;
  27. import com.github.binarywang.wxpay.service.WxPayService;
  28. import lombok.AllArgsConstructor;
  29. import lombok.extern.slf4j.Slf4j;
  30. import org.apache.commons.lang3.ObjectUtils;
  31. import org.apache.commons.lang3.StringUtils;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.data.redis.core.StringRedisTemplate;
  34. import org.springframework.http.ResponseEntity;
  35. import org.springframework.stereotype.Service;
  36. import javax.servlet.http.HttpServletRequest;
  37. import java.math.BigDecimal;
  38. import java.math.RoundingMode;
  39. import java.text.SimpleDateFormat;
  40. import java.util.Date;
  41. import java.util.Set;
  42. import java.util.UUID;
  43. @Slf4j
  44. @Service
  45. @AllArgsConstructor
  46. public class IWxPayService {
  47. @Autowired
  48. private CarInformationMapper carInformationMapper;
  49. @Autowired
  50. private StoreOrderMapper storeOrderMapper;
  51. @Autowired
  52. private CompetitionMapper competitionMapper;
  53. @Autowired
  54. private WxPayProperties wxPayProperties;
  55. @Autowired
  56. private ISysMemberService sysMemberService;
  57. @Autowired
  58. private StoreRefundMapper storeRefundMapper;
  59. @Autowired
  60. private StringRedisTemplate redisTemplate;
  61. @Autowired
  62. private IVipCardLogService vipCardLogService;
  63. private WxPayService wxService;
  64. // Redis中订单延迟队列的key前缀
  65. private static final String ORDER_DELAY_QUEUE_PREFIX = "order:delay:queue:";
  66. // 订单超时时间(5分钟)
  67. private static final long ORDER_TIMEOUT_SECONDS = 5 * 60;
  68. /**
  69. * 统一下单接口
  70. *
  71. * @return 预支付交易会话标识
  72. */
  73. public JsapiResult unifiedOrder(AppPayParam param) throws Exception {
  74. log.info("开始处理统一下单请求,订单号: {}", param.getOrderId());
  75. // 幂等性校验 - 检查订单是否已存在且已支付
  76. StoreOrder existingOrder = storeOrderMapper.selectStoreOrderByOrderId(param.getOrderId());
  77. if (existingOrder != null && existingOrder.getPaid() != null && existingOrder.getPaid() == 1) {
  78. log.warn("订单 {} 已支付,不能重复下单", param.getOrderId());
  79. throw new Exception("订单已支付,不能重复下单");
  80. }
  81. SysMember user = getSysMember(param.getUserId());
  82. param.setSysMember(user);
  83. //微信支付需要的参数
  84. WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
  85. request.setAppid(wxPayProperties.getAppId());
  86. request.setMchid(wxPayProperties.getMchId());
  87. request.setDescription(param.getDescription());
  88. request.setOutTradeNo(param.getOrderId());
  89. request.setNotifyUrl(wxPayProperties.getNotifyUrl());
  90. WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
  91. amount.setTotal(yuanToFen(param.getPayPrice()));
  92. amount.setCurrency("CNY");
  93. request.setAmount(amount);
  94. request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(user.getOpenId()));
  95. log.info("调用微信统一下单接口,订单号: {}", param.getOrderId());
  96. JsapiResult jsapiResult = this.wxService.createOrderV3(TradeTypeEnum.JSAPI, request);
  97. if (StringUtils.isNotEmpty(jsapiResult.getPackageValue())) {
  98. log.info("微信统一下单成功,订单号: {},开始创建本地订单", param.getOrderId());
  99. //成功之后创建订单
  100. generateOrder(param, jsapiResult.getPackageValue());
  101. //将订单添加到延迟队列中
  102. addOrderToDelayQueue(param.getOrderId());
  103. log.info("订单创建完成并加入延迟队列,订单号: {}", param.getOrderId());
  104. } else {
  105. log.warn("微信统一下单失败,订单号: {}", param.getOrderId());
  106. }
  107. return jsapiResult;
  108. }
  109. //获取当前用户信息
  110. private SysMember getSysMember(Long userId) {
  111. log.debug("获取用户信息,用户ID: {}", userId);
  112. return sysMemberService.selectSysMemberById(userId);
  113. }
  114. /**
  115. * 元转分(不四舍五入,直接截取)
  116. *
  117. * @param amount 金额(元)
  118. * @return 分(整数)
  119. */
  120. public static int yuanToFen(BigDecimal amount) {
  121. if (amount == null) return 0;
  122. return amount.multiply(BigDecimal.valueOf(100))
  123. .setScale(0, RoundingMode.DOWN) // 不四舍五入
  124. .intValueExact();
  125. }
  126. /**
  127. * 统一下单接口
  128. *
  129. * @return 预支付交易会话标识
  130. */
  131. private void generateOrder(AppPayParam param, String payId) {
  132. log.info("开始生成订单,订单号: {}", param.getOrderId());
  133. //查看是否已经生成订单,但是未支付
  134. if (!isOrderInDelayQueue(param.getOrderId())) {
  135. // 订单不存在,创建新订单
  136. log.info("订单不存在,创建新订单,订单号: {}", param.getOrderId());
  137. StoreOrder storeOrder = new StoreOrder();
  138. storeOrder.setOrderId(param.getOrderId());
  139. storeOrder.setUid(param.getSysMember().getId());
  140. storeOrder.setRealName(param.getSysMember().getUsername());
  141. storeOrder.setUserPhone(param.getSysMember().getMobile());
  142. storeOrder.setUserAddress(param.getSysMember().getAddress());
  143. storeOrder.setTotalNum(1);
  144. storeOrder.setTotalPrice(param.getTotalPrice());
  145. storeOrder.setPayPrice(param.getPayPrice());
  146. storeOrder.setPayTime(new Date());
  147. storeOrder.setPayId(payId);
  148. storeOrder.setCreateTime(new Date());
  149. storeOrderMapper.insertStoreOrder(storeOrder);
  150. log.info("新订单创建成功,订单号: {}", param.getOrderId());
  151. } else {
  152. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(param.getOrderId());
  153. // 订单已存在,更新支付相关信息
  154. log.info("订单已存在,更新支付信息,订单号: {}", param.getOrderId());
  155. order.setPayTime(new Date());
  156. order.setPayId(payId);
  157. storeOrderMapper.updateStoreOrder(order);
  158. log.info("订单支付信息更新完成,订单号: {}", param.getOrderId());
  159. }
  160. }
  161. /**
  162. * 将订单添加到延迟队列
  163. *
  164. * @param orderId 订单ID
  165. */
  166. private void addOrderToDelayQueue(String orderId) {
  167. log.info("将订单添加到延迟队列,订单号: {}", orderId);
  168. // 计算订单超时时间戳(当前时间+5分钟)
  169. long expireTime = System.currentTimeMillis() + (ORDER_TIMEOUT_SECONDS * 1000);
  170. // 将订单添加到Redis有序集合中,以超时时间戳作为score
  171. redisTemplate.opsForZSet().add(ORDER_DELAY_QUEUE_PREFIX + "orders", orderId, expireTime);
  172. log.info("订单 {} 已添加到延迟队列,超时时间: {}", orderId, new Date(expireTime));
  173. }
  174. /**
  175. * 从延迟队列中移除订单(支付成功时调用)
  176. *
  177. * @param orderId 订单ID
  178. */
  179. private void removeOrderFromDelayQueue(String orderId) {
  180. log.info("从延迟队列中移除订单,订单号: {}", orderId);
  181. // 从Redis有序集合中移除订单
  182. redisTemplate.opsForZSet().remove(ORDER_DELAY_QUEUE_PREFIX + "orders", orderId);
  183. log.info("订单 {} 已从延迟队列中移除", orderId);
  184. }
  185. //生成退款订单号
  186. public String generateOutTradeNo() {
  187. String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
  188. String random = String.valueOf((int) ((Math.random() * 9 + 1) * 100000)); // 6位随机
  189. return "REF" + time + random;
  190. }
  191. /**
  192. * 处理支付结果通知
  193. *
  194. * @return 处理结果
  195. */
  196. public AjaxResult handleNotify(String notifyData, HttpServletRequest request) {
  197. log.info("收到微信支付回调通知");
  198. SignatureHeader header = getRequestHeader(request);
  199. try {
  200. WxPayNotifyV3Result res = this.wxService.parseOrderNotifyV3Result(notifyData, header);
  201. WxPayNotifyV3Result.DecryptNotifyResult decryptRes = res.getResult();
  202. log.info("解析微信支付回调结果,订单号: {}, 交易状态: {}", decryptRes.getOutTradeNo(), decryptRes.getTradeState());
  203. if (WxPayConstants.WxpayTradeStatus.SUCCESS.equals(decryptRes.getTradeState())) {
  204. log.info("支付成功,开始处理订单,订单号: {}", decryptRes.getOutTradeNo());
  205. // 成功处理订单
  206. processOrderPayment(decryptRes.getOutTradeNo());
  207. //调用充值记录服务,更新充值记录状态
  208. VipCardLog vipCardLog = new VipCardLog();
  209. vipCardLog.setId(decryptRes.getOutTradeNo());
  210. vipCardLogService.updateVipCardLogByOrderId(vipCardLog);
  211. // 成功返回200/204,body无需有内容
  212. log.info("订单处理完成,订单号: {}", decryptRes.getOutTradeNo());
  213. return AjaxResult.success();
  214. } else {
  215. log.warn("支付失败,订单号: {},状态: {}", decryptRes.getOutTradeNo(), decryptRes.getTradeState());
  216. // 失败返回4xx或5xx,且需要构造body信息
  217. return AjaxResult.error();
  218. }
  219. } catch (WxPayException e) {
  220. log.error("处理微信支付回调失败", e);
  221. // 失败返回4xx或5xx,且需要构造body信息
  222. return AjaxResult.error("微信支付回调失败");
  223. }
  224. }
  225. /**
  226. * 处理订单支付完成后的业务逻辑
  227. *
  228. * @param orderId 订单号
  229. */
  230. private void processOrderPayment(String orderId) {
  231. log.info("开始处理订单支付完成逻辑,订单号: {}", orderId);
  232. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(orderId);
  233. if (order != null) {
  234. // 检查订单是否已经处理过
  235. if (order.getPaid() == null || order.getPaid() != 1) {
  236. log.info("更新订单状态为已支付,订单号: {}", orderId);
  237. // 更新订单状态
  238. order.setPaid(1); // 设置为已支付
  239. order.setStatus(1); // 设置订单状态为已支付
  240. order.setPayTime(new Date()); // 设置支付时间
  241. storeOrderMapper.updateStoreOrder(order);
  242. // 从延迟队列中移除订单
  243. removeOrderFromDelayQueue(orderId);
  244. log.info("订单状态更新完成,订单号: {}", orderId);
  245. } else {
  246. log.info("订单已处理过,无需重复处理,订单号: {}", orderId);
  247. }
  248. } else {
  249. log.warn("订单不存在,订单号: {}", orderId);
  250. }
  251. }
  252. /**
  253. * 微信支付-申请退款
  254. *
  255. */
  256. public WxPayRefundV3Result refund(AppRefundParam param) throws WxPayException {
  257. log.info("开始处理退款请求,订单号: {}", param.getOrderId());
  258. // 检查订单是否存在
  259. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(param.getOrderId());
  260. if (order == null) {
  261. log.warn("退款失败,订单不存在,订单号: {}", param.getOrderId());
  262. throw new WxPayException("订单不存在");
  263. }
  264. // 检查订单是否已支付
  265. if (order.getPaid() == null || order.getPaid() != 1) {
  266. log.warn("退款失败,订单未支付,订单号: {}", param.getOrderId());
  267. throw new WxPayException("订单未支付,无法退款");
  268. }
  269. // 检查订单是否已退款
  270. if (order.getRefundStatus() != null && order.getRefundStatus() == 2) {
  271. log.warn("退款失败,订单已退款,订单号: {}", param.getOrderId());
  272. throw new WxPayException("订单已退款");
  273. }
  274. // 检查退款金额是否合法
  275. if (param.getRefundAmount().compareTo(order.getPayPrice()) > 0) {
  276. log.warn("退款失败,退款金额大于支付金额,订单号: {}", param.getOrderId());
  277. throw new WxPayException("退款金额不能大于支付金额");
  278. }
  279. WxPayRefundV3Request request = new WxPayRefundV3Request();
  280. //商户退款单号
  281. request.setOutRefundNo(param.getOrderId());
  282. //原支付商户订单号
  283. request.setOutTradeNo(param.getOrderId());
  284. //退款原因说明
  285. request.setReason(param.getReason());
  286. WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
  287. //原订单总金额(单位:分)
  288. amount.setTotal(yuanToFen(param.getTotalPrice()));
  289. //退款金额(单位:分)
  290. amount.setRefund(yuanToFen(param.getRefundAmount()));
  291. //货币类型,默认 "CNY"
  292. amount.setCurrency("CNY");
  293. request.setAmount(amount);
  294. request.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());
  295. param.setSysMember(getSysMember(param.getUserId()));
  296. // 检查是否已存在退款记录
  297. StoreRefund existingRefund = storeRefundMapper.selectStoreRefundByOrderId(param.getOrderId());
  298. if (existingRefund == null) {
  299. log.info("创建退款记录,订单号: {}", param.getOrderId());
  300. refundOrder(param);
  301. }
  302. log.info("调用微信退款接口,订单号: {}", param.getOrderId());
  303. WxPayRefundV3Result result = this.wxService.refundV3(request);
  304. log.info("微信退款接口调用完成,订单号: {}", param.getOrderId());
  305. return result;
  306. }
  307. /**
  308. * 统一退款接口
  309. *
  310. * @return 预支付交易会话标识
  311. */
  312. private void refundOrder(AppRefundParam param) {
  313. log.info("生成退款订单记录,订单号: {}", param.getOrderId());
  314. StoreRefund storeRefund = new StoreRefund();
  315. storeRefund.setUid(param.getSysMember().getId());
  316. storeRefund.setRefundNo(generateOutTradeNo());
  317. storeRefund.setOrderId(param.getOrderId());
  318. storeRefund.setRefundAmount(param.getRefundAmount());
  319. storeRefund.setRefundReason(param.getReason());
  320. storeRefund.setCreateTime(new Date());
  321. storeRefundMapper.insertStoreRefund(storeRefund);
  322. log.info("退款订单记录创建完成,订单号: {}", param.getOrderId());
  323. }
  324. /**
  325. * 退款结果通知
  326. *
  327. * @return 处理结果
  328. */
  329. public AjaxResult parseRefundNotify(String notifyData, HttpServletRequest request) {
  330. log.info("收到微信退款回调通知");
  331. SignatureHeader header = getRequestHeader(request);
  332. try {
  333. WxPayRefundNotifyV3Result res = this.wxService.parseRefundNotifyV3Result(notifyData, header);
  334. WxPayRefundNotifyV3Result.DecryptNotifyResult decryptRes = res.getResult();
  335. log.info("解析微信退款回调结果,订单号: {}, 退款状态: {}", decryptRes.getOutTradeNo(), decryptRes.getRefundStatus());
  336. // TODO 根据自己业务场景需要构造返回对象
  337. if (WxPayConstants.RefundStatus.SUCCESS.equals(decryptRes.getRefundStatus())) {
  338. log.info("退款成功,开始处理订单,订单号: {}", decryptRes.getOutTradeNo());
  339. // 成功处理订单
  340. processOrderRefund(decryptRes.getOutTradeNo());
  341. //成功返回200/204,body无需有内容
  342. log.info("退款处理完成,订单号: {}", decryptRes.getOutTradeNo());
  343. return AjaxResult.success();
  344. } else {
  345. log.warn("退款失败,订单号: {},状态: {}", decryptRes.getOutTradeNo(), decryptRes.getRefundStatus());
  346. //失败返回4xx或5xx,且需要构造body信息
  347. return AjaxResult.error();
  348. }
  349. } catch (WxPayException e) {
  350. log.error("处理微信退款回调失败", e);
  351. //失败返回4xx或5xx,且需要构造body信息
  352. return AjaxResult.error("微信退款回调失败");
  353. }
  354. }
  355. /**
  356. * 退款完成后的业务逻辑
  357. *
  358. * @param orderId 订单号
  359. */
  360. private void processOrderRefund(String orderId) {
  361. log.info("开始处理订单退款完成逻辑,订单号: {}", orderId);
  362. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(orderId);
  363. if (order != null) {
  364. // 检查订单是否已经处理过
  365. if (order.getRefundStatus() != null && order.getPaid() == 1) {
  366. log.info("更新订单状态为已退款,订单号: {}", orderId);
  367. //更新支付订单状态为退款
  368. order.setStatus(2); // 3表示已取消
  369. order.setUpdateTime(new Date());
  370. storeOrderMapper.updateStoreOrder(order);
  371. log.info("订单状态更新完成,订单号: {}", orderId);
  372. } else {
  373. log.info("订单退款状态无需更新,订单号: {}", orderId);
  374. }
  375. } else {
  376. log.warn("订单不存在,订单号: {}", orderId);
  377. }
  378. StoreRefund refund = storeRefundMapper.selectStoreRefundByOrderId(orderId);
  379. if (refund != null) {
  380. // 检查订单是否已经处理过
  381. if (refund.getRefundStatus() != null && refund.getRefundStatus().equals("1")) {
  382. log.info("更新退款记录状态为已退款,退款单号: {}", refund.getRefundNo());
  383. // 更新订单状态
  384. refund.setRefundStatus("2"); // 设置订单状态为已退款
  385. refund.setSuccessTime(new Date());
  386. storeRefundMapper.updateStoreRefund(refund);
  387. log.info("退款记录状态更新完成,退款单号: {}", refund.getRefundNo());
  388. } else {
  389. log.info("退款记录状态无需更新,退款单号: {}", refund.getRefundNo());
  390. }
  391. } else {
  392. log.warn("退款记录不存在,订单号: {}", orderId);
  393. }
  394. }
  395. /**
  396. * 组装请求头重的前面信息
  397. *
  398. * @param request
  399. * @return
  400. */
  401. private SignatureHeader getRequestHeader(HttpServletRequest request) {
  402. log.debug("解析微信回调请求头信息");
  403. // 获取通知签名
  404. String signature = request.getHeader("Wechatpay-Signature");
  405. String nonce = request.getHeader("Wechatpay-Nonce");
  406. String serial = request.getHeader("Wechatpay-Serial");
  407. String timestamp = request.getHeader("Wechatpay-Timestamp");
  408. SignatureHeader signatureHeader = new SignatureHeader();
  409. signatureHeader.setSignature(signature);
  410. signatureHeader.setNonce(nonce);
  411. signatureHeader.setSerial(serial);
  412. signatureHeader.setTimeStamp(timestamp);
  413. return signatureHeader;
  414. }
  415. /**
  416. * 处理超时订单
  417. * 定时任务调用此方法检查并处理超时订单
  418. */
  419. public void processTimeoutOrders() {
  420. log.info("开始处理超时订单");
  421. // 获取当前时间戳
  422. long currentTime = System.currentTimeMillis();
  423. // 从Redis有序集合中获取所有已超时的订单(score小于当前时间的元素)
  424. redisTemplate.opsForZSet().rangeByScore(ORDER_DELAY_QUEUE_PREFIX + "orders", 0, currentTime)
  425. .forEach(orderId -> {
  426. try {
  427. log.info("处理超时订单: {}", orderId);
  428. // 查询订单信息
  429. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(orderId);
  430. if (order != null && (order.getPaid() == null || order.getPaid() != 1)) {
  431. // 订单未支付,执行删除操作或更新状态
  432. // 这里我们更新订单状态为已取消
  433. order.setStatus(3); // 3表示已取消
  434. order.setUpdateTime(new Date());
  435. storeOrderMapper.updateStoreOrder(order);
  436. log.info("订单 {} 已超时,状态已更新为已取消", orderId);
  437. } else if (order != null) {
  438. log.info("订单 {} 已支付,无需处理", orderId);
  439. } else {
  440. log.warn("订单 {} 不存在", orderId);
  441. }
  442. // 从延迟队列中移除订单
  443. redisTemplate.opsForZSet().remove(ORDER_DELAY_QUEUE_PREFIX + "orders", orderId);
  444. log.info("超时订单 {} 处理完成", orderId);
  445. } catch (Exception e) {
  446. log.error("处理超时订单 {} 时发生错误", orderId, e);
  447. }
  448. });
  449. log.info("超时订单处理完成");
  450. }
  451. /**
  452. * 取消订单
  453. *
  454. * @param orderId 订单ID
  455. * @return 处理结果
  456. */
  457. public int cancelOrder(String orderId) {
  458. StoreOrder order = storeOrderMapper.selectStoreOrderByOrderId(orderId);
  459. order.setStatus(3); // 3表示已取消
  460. order.setUpdateTime(new Date());
  461. return storeOrderMapper.updateStoreOrder(order);
  462. }
  463. /**
  464. * 检查订单是否在延迟队列中
  465. *
  466. * @param orderId 订单ID
  467. * @return 如果订单在延迟队列中返回true,否则返回false
  468. */
  469. public boolean isOrderInDelayQueue(String orderId) {
  470. // 使用rank命令检查订单是否在有序集合中
  471. // 如果返回null,说明订单不在集合中
  472. Long rank = redisTemplate.opsForZSet().rank(ORDER_DELAY_QUEUE_PREFIX + "orders", orderId);
  473. return rank != null;
  474. }
  475. }